a20a47fa617dd3a6a5296b2a68e1b9479658f59a..7b47c91bcf89d667a5c99cfafe0d899280f7fbe3
2025-11-19 sunpengfei
feat:平安转账开发
7b47c9 对比 | 目录
2025-11-19 sunpengfei
feat:平安转账开发
3d67ad 对比 | 目录
2025-11-19 sunpengfei
feat:平安转账开发
a62b32 对比 | 目录
3个文件已删除
11个文件已修改
26个文件已添加
7018 ■■■■ 已修改文件
ApiTools.Application/ApiTools.Application.xml 74 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Application/ChannelWallets/Commands/ChannelWalletCommandHandler.cs 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Application/ChannelWallets/Queries/ChannelWalletQueryHandler.cs 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/ApiTools.Core.csproj 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/ApiTools.Core.xml 2030 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Entities/Users/ChannelWallet.cs 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Entities/Users/ChannelWalletTransaction.cs 204 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Entities/Users/ChannelWalletTransactionPingAnPay.cs 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Enums/Resources/EnumResourceController.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Enums/Users/EnumWalletAccess.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Enums/Users/EnumWalletSignStatus.cs 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Enums/Users/EnumWalletTransactionEreceiptStatus.cs 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Enums/Users/EnumWalletTransactionStatus.cs 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Enums/Users/EnumWalletTransactionType.cs 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Jobs/RefreshChannelWalletTransactionStatusJob.cs 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Models/ChannelWallets/Commands/SaveChannelPingAnPayWalletCommand.cs 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Models/ChannelWallets/Commands/SubmitChannelWalletTransferCommand.cs 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Models/ChannelWallets/Queries/GetChannelPingAnPayWalletQuery.cs 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Models/ChannelWallets/Queries/GetChannelWalletTransactionQuery.cs 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Repositories/BaseRepository.cs 351 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Repositories/ChannelWalletRepository.cs 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Repositories/EnterpriseWalletTransactionRepository.cs 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Services/ChannelPingAnPayWalletService.cs 298 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Services/ChannelWalletService.cs 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Services/IChannelWalletService.cs 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/CollectionUtils/CollectionUtils.cs 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/DistributedCacheUtils/DistributedLock.cs 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/DistributedCacheUtils/DistributedLockServiceComponent.cs 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/PingAnPayUtils/Models/HistoryBalanceQueryRequest.cs 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/PingAnPayUtils/Models/InquiryAccountDayHistoryTransactionDetailsRequest.cs 386 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/PingAnPayUtils/Models/SingleDataQueryRequest.cs 487 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/PingAnPayUtils/PingAnPayUtils.cs 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Core/Utils/ScheduleUtils/DbJobPersistence.cs 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.Designer.cs 998 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.cs 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Database.Migrations/Migrations/DefaultDbContextModelSnapshot.cs 347 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Database.Migrations/REDEME.MD 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Web.Entry/ApiTools.Web.Entry.csproj 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Web.Entry/PingAnPayCert/config.properties 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Web.Entry/Startup.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ApiTools.Application/ApiTools.Application.xml
@@ -149,6 +149,64 @@
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Application.ChannelWalletCommandHandler.Handle(ApiTools.Core.SaveChannelPingAnPayWalletCommand,System.Threading.CancellationToken)">
            <summary>
            保存渠道平安银行钱包
            </summary>
            <param name="request"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Application.ChannelWalletCommandHandler.Handle(ApiTools.Core.SubmitChannelWalletTransferCommand,System.Threading.CancellationToken)">
            <summary>
            提交渠道钱包转账
            </summary>
            <param name="request"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="T:ApiTools.Application.ChannelWalletQueryHandler">
            <summary>
            查询渠道钱包交易详情
            </summary>
        </member>
        <member name="M:ApiTools.Application.ChannelWalletQueryHandler.#ctor(ApiTools.Core.ChannelWalletRepository,ApiTools.Core.ChannelWalletTransactionRepository)">
            <summary>
            查询渠道钱包交易详情
            </summary>
        </member>
        <member name="M:ApiTools.Application.ChannelWalletQueryHandler.Handle(ApiTools.Core.GetChannelPingAnPayWalletQuery,System.Threading.CancellationToken)">
            <summary>
            查询渠道平安银行钱包
            </summary>
            <param name="request"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Application.ChannelWalletQueryHandler.Handle(ApiTools.Core.GetChannelWalletTransactionQuery,System.Threading.CancellationToken)">
            <summary>
            查询渠道钱包交易详情
            </summary>
            <param name="request"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Application.SendSmsCommandHandler.Handle(ApiTools.Core.SendSmsCommand,System.Threading.CancellationToken)">
            <summary>
            发送短信
            </summary>
            <param name="request"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Application.SendSmsCommandHandler.Handle(ApiTools.Core.CheckVerifyCodeSmsCommand,System.Threading.CancellationToken)">
            <summary>
            校验验证码
            </summary>
            <param name="request"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="T:ApiTools.CommonServer.Application.SaveSmsSettingCommandHandler">
            <summary>
            保存短信配置
@@ -216,22 +274,6 @@
        <member name="M:ApiTools.CommonServer.Application.GetSmsSettingQueryHandler.Handle(ApiTools.Core.GetSmsSettingQuery,System.Threading.CancellationToken)">
            <summary>
            查询短信配置
            </summary>
            <param name="request"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Application.SendSmsCommandHandler.Handle(ApiTools.Core.SendSmsCommand,System.Threading.CancellationToken)">
            <summary>
            发送短信
            </summary>
            <param name="request"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Application.SendSmsCommandHandler.Handle(ApiTools.Core.CheckVerifyCodeSmsCommand,System.Threading.CancellationToken)">
            <summary>
            校验验证码
            </summary>
            <param name="request"></param>
            <param name="cancellationToken"></param>
ApiTools.Application/ChannelWallets/Commands/ChannelWalletCommandHandler.cs
New file
@@ -0,0 +1,135 @@
using Aop.Api.Domain;
using ApiTools.Core;
using Consul;
using Furion.FriendlyException;
using Mapster;
using Medallion.Threading;
using MediatR;
using Microsoft.EntityFrameworkCore;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Application
{
    public class ChannelWalletCommandHandler(
            IDistributedLockProvider distributedLockProvider,
            ChannelWalletRepository channelWalletRepository,
            ChannelWalletTransactionRepository channelWalletTransactionRepository,
            ChannelWalletService channelWalletService
        ) :
        IRequestHandler<SaveChannelPingAnPayWalletCommand, SaveChannelPingAnPayWalletCommandResult>,
        IRequestHandler<SubmitChannelWalletTransferCommand, SubmitChannelWalletTransferCommandResult>
    {
        private readonly IDistributedLockProvider distributedLockProvider = distributedLockProvider;
        private readonly ChannelWalletRepository channelWalletRepository = channelWalletRepository;
        private readonly ChannelWalletTransactionRepository channelWalletTransactionRepository = channelWalletTransactionRepository;
        private readonly ChannelWalletService channelWalletService = channelWalletService;
        /// <summary>
        /// 保存渠道平安银行钱包
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<SaveChannelPingAnPayWalletCommandResult> Handle(SaveChannelPingAnPayWalletCommand request, CancellationToken cancellationToken)
        {
            var logier = JwtUtils.GetCurrentLogier();
            var wallet = await channelWalletRepository.GetQueryable(false)
                .Where(it => it.ChannelId == logier.ChannelId && it.OutWalletId == request.OutWalletId)
                .FirstOrDefaultAsync();
            if (wallet == null)
            {
                wallet = new ChannelWallet();
                wallet.ChannelId = logier.ChannelId;
                wallet.Access = EnumWalletAccess.PingAnPay;
                wallet.Bank = "平安银行";
                wallet.SignStatus = EnumWalletSignStatus.Apply;
                request.Adapt(wallet);
                await channelWalletRepository.SetCode(wallet);
                await channelWalletRepository.InsertNowAsync(wallet);
            }
            else
            {
                wallet.SignStatus = EnumWalletSignStatus.Apply;
                request.Adapt(wallet);
                await channelWalletRepository.UpdateNowAsync(wallet);
            }
            await channelWalletService.GetEnterpriseWalletBalance(wallet);
            return new SaveChannelPingAnPayWalletCommandResult
            {
                Id = wallet.Id,
                Balance = wallet.Balance,
            };
        }
        /// <summary>
        /// 提交渠道钱包转账
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<SubmitChannelWalletTransferCommandResult> Handle(SubmitChannelWalletTransferCommand request, CancellationToken cancellationToken)
        {
            var logier = JwtUtils.GetCurrentLogier();
            await using var handle = await distributedLockProvider.TryAcquireAsync(
                channelWalletService.GetLockKey(logier.ChannelId.Value, request.OutWalletId),
                TimeSpan.FromMinutes(30));
            if (handle == null) throw Oops.Oh(EnumErrorCodeType.s429);
            var wallet = await channelWalletRepository.GetQueryable(false)
                .Where(it => it.ChannelId == logier.ChannelId && it.OutWalletId == request.OutWalletId)
                .FirstOrDefaultAsync();
            if (wallet == null) throw Oops.Oh(EnumErrorCodeType.s404, "未开通钱包");
            if (wallet.SignStatus != EnumWalletSignStatus.Normal) throw Oops.Oh(EnumErrorCodeType.s404, "钱包未签约");
            await channelWalletService.GetEnterpriseWalletBalance(wallet);
            if (request.Amount > wallet.Balance) throw Oops.Oh(EnumErrorCodeType.s404, "余额不足");
            var checkExist = await channelWalletTransactionRepository.GetQueryable()
                .AnyAsync(it => it.WalletId == wallet.Id && it.OutCode == request.OutCode);
            if (checkExist) throw Oops.Oh(EnumErrorCodeType.s405, "交易单号");
            var transaction = new ChannelWalletTransaction();
            transaction.Type = EnumWalletTransactionType.Transfer;
            transaction.WalletId = wallet.Id;
            transaction.OutCode = request.OutCode;
            transaction.ConcurrencyLock = $"{logier.ChannelId}:{transaction.OutCode}";
            transaction.Amount = request.Amount;
            transaction.Remark = request.Remark;
            transaction.TransactionStatus = EnumWalletTransactionStatus.WaitSubmit;
            transaction.Balance = wallet.Balance;
            transaction.AfterBalance = wallet.Balance - transaction.Amount;
            transaction.OutOperatorId = request.OutOperatorId;
            transaction.OperatorTime = request.OperatorTime;
            transaction.PayerName = wallet.Name;
            transaction.PayerAccount = wallet.Identity;
            transaction.PayerBank = wallet.Bank;
            transaction.PayerBankBranch = wallet.BankBranch;
            transaction.OutReceiveId = request.OutReceiveId;
            transaction.ReceiveBank = request.ReceiveBank;
            transaction.ReceiveBankBranch = request.ReceiveBankBranch;
            transaction.ReceiveName = request.ReceiveName;
            transaction.ReceiveIdentity = request.ReceiveIdentity;
            transaction.ReceiveAccount = request.ReceiveAccount;
            transaction.Currency = request.Currency;
            transaction.Purpose = request.Purpose;
            transaction.Remark = request.Remark;
            await channelWalletTransactionRepository.SetCode(transaction);
            await channelWalletTransactionRepository.InsertNowAsync(transaction);
            await channelWalletService.Transfer(wallet, transaction);
            return new SubmitChannelWalletTransferCommandResult
            {
                Id = transaction.Id,
                Code = transaction.Code,
                TransactionStatus = transaction.TransactionStatus,
                ErrorCode = transaction.ErrorCode,
                FailReason = transaction.FailReason,
            };
        }
    }
}
ApiTools.Application/ChannelWallets/Queries/ChannelWalletQueryHandler.cs
New file
@@ -0,0 +1,55 @@
using ApiTools.Core;
using Mapster;
using MediatR;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Application
{
    /// <summary>
    /// 查询渠道钱包交易详情
    /// </summary>
    public class ChannelWalletQueryHandler(
            ChannelWalletRepository channelWalletRepository,
            ChannelWalletTransactionRepository channelWalletTransactionRepository
        ) :
        IRequestHandler<GetChannelPingAnPayWalletQuery, GetChannelPingAnPayWalletQueryResult>,
        IRequestHandler<GetChannelWalletTransactionQuery, GetChannelWalletTransactionQueryResult>
    {
        private readonly ChannelWalletRepository channelWalletRepository = channelWalletRepository;
        private readonly ChannelWalletTransactionRepository channelWalletTransactionRepository = channelWalletTransactionRepository;
        /// <summary>
        /// 查询渠道平安银行钱包
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<GetChannelPingAnPayWalletQueryResult> Handle(GetChannelPingAnPayWalletQuery request, CancellationToken cancellationToken)
        {
            return await channelWalletRepository.GetQueryable()
                .Where(it => it.OutWalletId == request.OutWalletId)
                .ProjectToType<GetChannelPingAnPayWalletQueryResult>()
                .FirstOrDefaultAsync();
        }
        /// <summary>
        /// 查询渠道钱包交易详情
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<GetChannelWalletTransactionQueryResult> Handle(GetChannelWalletTransactionQuery request, CancellationToken cancellationToken)
        {
            return await channelWalletTransactionRepository.GetQueryable()
                .Where(it => it.OutCode == request.OutCode)
                .ProjectToType<GetChannelWalletTransactionQueryResult>()
                .FirstOrDefaultAsync();
        }
    }
}
ApiTools.Core/ApiTools.Core.csproj
@@ -19,6 +19,8 @@
        <PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
        <PackageReference Include="Baidu.AI" Version="4.15.16" />
        <PackageReference Include="Consul" Version="1.7.14.8" />
        <PackageReference Include="DistributedLock.Core" Version="1.0.8" />
        <PackageReference Include="DistributedLock.Redis" Version="1.1.0" />
        <PackageReference Include="EFCore.BulkExtensions" Version="9.0.1" />
        <PackageReference Include="Furion" Version="4.9.7.106" />
        <PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.106" />
ApiTools.Core/ApiTools.Core.xml
@@ -809,6 +809,411 @@
            是否禁用
            </summary>
        </member>
        <member name="T:ApiTools.Core.ChannelWallet">
            <summary>
            渠道钱包
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.ChannelId">
            <summary>
            渠道Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.Channel">
            <summary>
            渠道
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.OutWalletId">
            <summary>
            外部钱包Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.Access">
            <summary>
            通道
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.Code">
            <summary>
            编号
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.Bank">
            <summary>
            所属银行
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.BankBranch">
            <summary>
            所属支行
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.Name">
            <summary>
            户名
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.Identity">
            <summary>
            账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.Balance">
            <summary>
            余额
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.SignStatus">
            <summary>
            签约状态
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.ErrorCode">
            <summary>
            错误代码
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWallet.FailReason">
            <summary>
            返回具体的原因。
            </summary>
        </member>
        <member name="T:ApiTools.Core.ChannelWalletTransaction">
            <summary>
            渠道钱包交易
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.WalletId">
            <summary>
            钱包Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.Wallet">
            <summary>
            钱包
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.PingAnPay">
            <summary>
            平安信息
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.Type">
            <summary>
            类型
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.Code">
            <summary>
            订单号
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.OutCode">
            <summary>
            外部订单号
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.ConcurrencyLock">
            <summary>
            并发锁
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.Amount">
            <summary>
            金额
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.Balance">
            <summary>
            余额
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.AfterBalance">
            <summary>
            收支后余额
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.OutOperatorId">
            <summary>
            外部操作人Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.OperatorTime">
            <summary>
            操作时间
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.PayerAccount">
            <summary>
            付款人账户
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.PayerName">
            <summary>
            付款人名称
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.PayerBank">
            <summary>
            付款人开户行
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.PayerBankBranch">
            <summary>
            付款人支行
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.OutReceiveId">
            <summary>
            外部收款人Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.ReceiveName">
            <summary>
            收款人姓名
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.ReceiveIdentity">
            <summary>
            收款人身份证号
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.ReceiveAccount">
            <summary>
            收款账户
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.ReceiveBank">
            <summary>
            收款人开户行
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.ReceiveBankBranch">
            <summary>
            收款人支行
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.Currency">
            <summary>
            币种
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.Purpose">
            <summary>
            用途
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.Remark">
            <summary>
            备注
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.ErrorCode">
            <summary>
            查询到的订单状态为FAIL失败或REFUND退票时,返回错误代码
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.FailReason">
            <summary>
            查询到的订单状态为FAIL失败或REFUND退票时,返回具体的原因。
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.TransDate">
            <summary>
            订单支付时间
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.OrderFee">
            <summary>
            预计收费金额(元),转账到银行卡专用
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.EreceiptFileId">
            <summary>
            电子收据Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.EreceiptDownloadUrl">
            <summary>
            电子收据下载链接
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.EreceiptDownloadOssUrl">
            <summary>
            电子收据下载链接
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.EreceiptStatus">
            <summary>
            电子收据状态
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.EreceiptErrorMessage">
            <summary>
            电子收据错误信息
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransaction.TransactionStatus">
            <summary>
            状态
            </summary>
        </member>
        <member name="T:ApiTools.Core.ChannelWalletTransactionPingAnPay">
            <summary>
            渠道钱包交易记录平安支付信息
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.Transaction">
            <summary>
            交易
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.FreezeNo">
            <summary>
            止付编号 有效状态的平安易止付编号,从JGF001止付后返回的
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.StopStt">
            <summary>
            止付状态码
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.StopFailReason">
            <summary>
            止付失败原因
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.RemoveStopStt">
            <summary>
            解除止付状态码
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.RemoveStopFailReason">
            <summary>
            解除止付失败原因
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.ThirdVoucher">
            <summary>
            转账凭证号
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.FrontLogNo">
            <summary>
            银行流水号 银行业务流水号;可以用于对账
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.CstInnerFlowNo">
            <summary>
            客户自定义凭证号 用于客户转账登记和内部识别,通过转账结果查询可以返回。银行不检查唯一性
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.IsBack">
            <summary>
            转账退票标志
            "0:未退票; 默认为0
            1:退票;"
            数据长度:1,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.BackRem">
            <summary>
            支付失败或退票原因描述
            "如果是超级网银则返回如下信息:
            RJ01对方返回:账号不存在
            RJ02对方返回:账号、户名不符
            大小额支付则返回失败描述"
            数据长度:20,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.Yhcljg">
            <summary>
            银行处理结果
            "格式为:“六位代码:中文描述”。冒号为半角。如:000000:转账成功
            处理中的返回(以如下返回开头):
            MA9111:交易正在受理中
            000000:交易受理成功待处理
            000000:交易处理中
            000000:交易受理成功处理中
            成功的返回:
            000000:转账交易成功
            其他的返回都为失败:
            MA9112:转账失败"
            数据长度:40,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.SysFlag">
            <summary>
            转账加急标志
            Y:加急 N:普通S:特急
            数据长度:1,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.Fee">
            <summary>
            转账手续费
            数据长度:13,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.TransBsn">
            <summary>
            转账代码类型
            "4004:单笔转账;
            4014:单笔批量;
            4034:汇总批量"
            数据长度:4,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.SubmitTime">
            <summary>
            交易受理时间
            交易受理时间
            数据长度:14,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.AccountDate">
            <summary>
            记账日期
            主机记账日期
            数据长度:8,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.HostFlowNo">
            <summary>
            主机记账流水号
            主机记账流水
            数据长度:32,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.HostErrorCode">
            <summary>
            错误码
            交易失败的错误代码
            数据长度:20,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.ProxyPayName">
            <summary>
            代理人户名
            用于代理行支付功能
            数据长度:60,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.ProxyPayAcc">
            <summary>
            代理人账号
            用于代理行支付功能
            数据长度:30,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.ChannelWalletTransactionPingAnPay.ProxyPayBankName">
            <summary>
            代理人银行名称
            用于代理行支付功能
            数据长度:30,是否必输:N
            </summary>
        </member>
        <member name="T:ApiTools.Core.User">
            <summary>
            用户
@@ -1115,6 +1520,11 @@
            渠道信息
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumResourceController.UserServerChannelWallet">
            <summary>
            渠道钱包
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumResourceController.UserServerChannelUser">
            <summary>
            渠道用户
@@ -1402,6 +1812,121 @@
            运营
            </summary>
        </member>
        <member name="T:ApiTools.Core.EnumWalletAccess">
            <summary>
            渠道钱包通道
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletAccess.Alipay">
            <summary>
            支付宝
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletAccess.PingAnPay">
            <summary>
            平安银行
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletAccess.WeChatPay">
            <summary>
            微信
            </summary>
        </member>
        <member name="T:ApiTools.Core.EnumWalletSignStatus">
            <summary>
            渠道钱包签约状态
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletSignStatus.Wait">
            <summary>
            未签约
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletSignStatus.Apply">
            <summary>
            申请中
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletSignStatus.Normal">
            <summary>
            已签约
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletSignStatus.Stop">
            <summary>
            终止
            </summary>
        </member>
        <member name="T:ApiTools.Core.EnumWalletTransactionEreceiptStatus">
            <summary>
            钱包交易电子收据状态
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionEreceiptStatus.INIT">
            <summary>
            初始化
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionEreceiptStatus.PROCESS">
            <summary>
            处理中
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionEreceiptStatus.SUCCESS">
            <summary>
            成功
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionEreceiptStatus.FAIL">
            <summary>
            失败
            </summary>
        </member>
        <member name="T:ApiTools.Core.EnumWalletTransactionStatus">
            <summary>
            钱包交易状态
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionStatus.WaitSubmit">
            <summary>
            待提交
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionStatus.WaitPay">
            <summary>
            待支付
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionStatus.Dealing">
            <summary>
            处理中
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionStatus.Success">
            <summary>
            成功
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionStatus.Refund">
            <summary>
            退票
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionStatus.Fail">
            <summary>
            失败
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionType.Recharge">
            <summary>
            充值
            </summary>
        </member>
        <member name="F:ApiTools.Core.EnumWalletTransactionType.Transfer">
            <summary>
            转账
            </summary>
        </member>
        <member name="T:ApiTools.Core.IIsDisabled">
            <summary>
            是否已禁用
@@ -1446,6 +1971,16 @@
        <member name="P:ApiTools.Core.ITreeData`1.Code">
            <summary>
            编号
            </summary>
        </member>
        <member name="T:ApiTools.Core.RefreshChannelWalletTransactionStatusJob">
            <summary>
            刷新渠道钱包交易状态
            </summary>
        </member>
        <member name="M:ApiTools.Core.RefreshChannelWalletTransactionStatusJob.#ctor(ApiTools.Core.ChannelWalletRepository,ApiTools.Core.ChannelWalletTransactionRepository,ApiTools.Core.ChannelWalletService)">
            <summary>
            刷新渠道钱包交易状态
            </summary>
        </member>
        <member name="T:ApiTools.Core.ChangePhoneNumberCommand">
@@ -1714,6 +2249,351 @@
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelUsersQueryResultItem.Status">
            <summary>
            状态
            </summary>
        </member>
        <member name="T:ApiTools.Core.SaveChannelPingAnPayWalletCommand">
            <summary>
            保存渠道平安银行钱包
            </summary>
        </member>
        <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommand.OutWalletId">
            <summary>
            外部钱包Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommand.Name">
            <summary>
            户名
            </summary>
        </member>
        <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommand.Identity">
            <summary>
            账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommandResult.Id">
            <summary>
            钱包Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommandResult.Balance">
            <summary>
            余额
            </summary>
        </member>
        <member name="T:ApiTools.Core.SubmitChannelWalletTransferCommand">
            <summary>
            提交渠道钱包转账
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.OutWalletId">
            <summary>
            外部钱包Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.OutCode">
            <summary>
            外部订单号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.OutOperatorId">
            <summary>
            外部操作人Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.OperatorTime">
            <summary>
            操作时间
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.OutReceiveId">
            <summary>
            外部收款人Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.Amount">
            <summary>
            金额
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.ReceiveName">
            <summary>
            收款人姓名
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.ReceiveIdentity">
            <summary>
            收款人身份证号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.ReceiveAccount">
            <summary>
            收款账户
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.ReceiveBank">
            <summary>
            收款人开户行
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.ReceiveBankBranch">
            <summary>
            收款人支行
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.Currency">
            <summary>
            币种
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.Purpose">
            <summary>
            用途
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommand.Remark">
            <summary>
            备注
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommandResult.Id">
            <summary>
            交易Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommandResult.Code">
            <summary>
            订单号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommandResult.TransactionStatus">
            <summary>
            状态
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommandResult.ErrorCode">
            <summary>
            查询到的订单状态为FAIL失败或REFUND退票时,返回错误代码
            </summary>
        </member>
        <member name="P:ApiTools.Core.SubmitChannelWalletTransferCommandResult.FailReason">
            <summary>
            查询到的订单状态为FAIL失败或REFUND退票时,返回具体的原因。
            </summary>
        </member>
        <member name="T:ApiTools.Core.GetChannelPingAnPayWalletQuery">
            <summary>
            查询渠道平安银行钱包
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelPingAnPayWalletQuery.OutWalletId">
            <summary>
            外部钱包Id
            </summary>
        </member>
        <member name="T:ApiTools.Core.GetChannelPingAnPayWalletQueryResult">
            <summary>
            查询渠道平安银行钱包
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelPingAnPayWalletQueryResult.Id">
            <summary>
            钱包Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelPingAnPayWalletQueryResult.Name">
            <summary>
            户名
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelPingAnPayWalletQueryResult.Identity">
            <summary>
            账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelPingAnPayWalletQueryResult.Balance">
            <summary>
            余额
            </summary>
        </member>
        <member name="T:ApiTools.Core.GetChannelWalletTransactionQuery">
            <summary>
            查询渠道钱包交易详情
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQuery.OutCode">
            <summary>
            外部订单号
            </summary>
        </member>
        <member name="T:ApiTools.Core.GetChannelWalletTransactionQueryResult">
            <summary>
            查询渠道钱包交易详情
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.Id">
            <summary>
            交易Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.Type">
            <summary>
            类型
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.Code">
            <summary>
            订单号
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.OutCode">
            <summary>
            外部订单号
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.ConcurrencyLock">
            <summary>
            并发锁
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.Amount">
            <summary>
            金额
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.Balance">
            <summary>
            余额
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.AfterBalance">
            <summary>
            收支后余额
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.OutOperatorId">
            <summary>
            外部操作人Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.OperatorTime">
            <summary>
            操作时间
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.PayerAccount">
            <summary>
            付款人账户
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.PayerName">
            <summary>
            付款人名称
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.PayerBank">
            <summary>
            付款人开户行
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.PayerBankBranch">
            <summary>
            付款人支行
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.OutReceiveId">
            <summary>
            外部收款人Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.ReceiveName">
            <summary>
            收款人姓名
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.ReceiveIdentity">
            <summary>
            收款人身份证号
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.ReceiveAccount">
            <summary>
            收款账户
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.ReceiveBank">
            <summary>
            收款人开户行
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.ReceiveBankBranch">
            <summary>
            收款人支行
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.Currency">
            <summary>
            币种
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.Purpose">
            <summary>
            用途
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.Remark">
            <summary>
            备注
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.ErrorCode">
            <summary>
            查询到的订单状态为FAIL失败或REFUND退票时,返回错误代码
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.FailReason">
            <summary>
            查询到的订单状态为FAIL失败或REFUND退票时,返回具体的原因。
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.TransDate">
            <summary>
            订单支付时间
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.OrderFee">
            <summary>
            预计收费金额(元),转账到银行卡专用
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.EreceiptFileId">
            <summary>
            电子收据Id
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.EreceiptDownloadUrl">
            <summary>
            电子收据下载链接
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.EreceiptDownloadOssUrl">
            <summary>
            电子收据下载链接
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.EreceiptStatus">
            <summary>
            电子收据状态
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.EreceiptErrorMessage">
            <summary>
            电子收据错误信息
            </summary>
        </member>
        <member name="P:ApiTools.Core.GetChannelWalletTransactionQueryResult.TransactionStatus">
            <summary>
            状态
            </summary>
@@ -2157,6 +3037,231 @@
            <summary>
            签名名称
            </summary>
        </member>
        <member name="M:ApiTools.Core.BaseRepository`2.GetQueryable(System.Boolean)">
            <summary>
            获取查询
            </summary>
            <param name="noTracking"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.BaseRepository`2.GetQueryable(System.Boolean,System.Func{System.Linq.IQueryable{`0},System.Linq.IQueryable{`0}})">
            <summary>
            获取查询
            </summary>
            <param name="noTracking"></param>
            <param name="query"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.BaseRepository`2.Get(System.Guid,System.Func{System.Linq.IQueryable{`0},System.Linq.IQueryable{`0}},System.Threading.CancellationToken)">
            <summary>
            获取实体
            </summary>
            <param name="id"></param>
            <param name="query"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.BaseRepository`2.Get(System.Collections.Generic.List{System.Guid},System.Func{System.Linq.IQueryable{`0},System.Linq.IQueryable{`0}},System.Threading.CancellationToken)">
            <summary>
            获取实体
            </summary>
            <param name="ids"></param>
            <param name="query"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.BaseRepository`2.GetSelect``2(ApiTools.Core.SelectQuery{``0,``1},System.Func{``1,``0},System.Func{``1,System.String},System.Func{System.Linq.IQueryable{`0},System.Linq.IQueryable{`0}},System.Threading.CancellationToken)">
            <summary>
            查询选择器数据
            </summary>
            <typeparam name="TValue"></typeparam>
            <typeparam name="TData"></typeparam>
            <param name="request"></param>
            <param name="getValue"></param>
            <param name="getLabel"></param>
            <param name="query"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.BaseRepository`2.SetIsDisabled(ApiTools.Core.SetIsDisabledCommand,System.Func{System.Linq.IQueryable{`0},System.Linq.IQueryable{`0}},System.Threading.CancellationToken)">
            <summary>
            设置是否禁用
            </summary>
            <param name="request"></param>
            <param name="query"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.BaseRepository`2.DeleteData(ApiTools.Core.DeleteDataCommand,System.Func{System.Linq.IQueryable{`0},System.Linq.IQueryable{`0}},System.Threading.CancellationToken)">
            <summary>
            删除数据
            </summary>
            <param name="request"></param>
            <param name="query"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.BaseRepository`2.UpdateData``1(System.Linq.IQueryable{`0},``0,System.Action{`0},System.Threading.CancellationToken)">
            <summary>
            更新数据
            </summary>
            <typeparam name="TRequest"></typeparam>
            <param name="q"></param>
            <param name="request"></param>
            <param name="update"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.BaseRepository`2.SaveData``1(``0,System.Func{System.Linq.IQueryable{`0},System.Linq.IQueryable{`0}},System.Linq.Expressions.Expression{System.Func{`0,System.Boolean}},System.Action{`0},System.Threading.CancellationToken)">
            <summary>
            保存数据
            </summary>
            <typeparam name="TRequest"></typeparam>
            <param name="request"></param>
            <param name="query"></param>
            <param name="checkExist"></param>
            <param name="update"></param>
            <param name="cancellationToken"></param>
            <returns></returns>
        </member>
        <member name="T:ApiTools.Core.ChannelWalletRepository">
            <summary>
            企业钱包仓库
            </summary>
        </member>
        <member name="M:ApiTools.Core.ChannelWalletRepository.SetCode(ApiTools.Core.ChannelWallet)">
            <summary>
            设置编号
            </summary>
            <param name="entity"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.ChannelWalletTransactionRepository.SetCode(ApiTools.Core.ChannelWalletTransaction)">
            <summary>
            设置编号
            </summary>
            <param name="entity"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.ChannelPingAnPayWalletService.GetEnterpriseWalletBalance(ApiTools.Core.ChannelWallet)">
            <summary>
            查询企业钱包余额
            </summary>
            <param name="wallet"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.ChannelPingAnPayWalletService.Transfer(ApiTools.Core.ChannelWallet,ApiTools.Core.ChannelWalletTransaction)">
            <summary>
            转账
            </summary>
            <param name="wallet"></param>
            <param name="transaction"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.ChannelPingAnPayWalletService.GetTransactionDetail(ApiTools.Core.ChannelWallet,ApiTools.Core.ChannelWalletTransaction)">
            <summary>
            查询交易记录
            </summary>
            <param name="wallet"></param>
            <param name="transaction"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.ChannelPingAnPayWalletService.DownloadEreceiptUrl(ApiTools.Core.ChannelWallet,ApiTools.Core.ChannelWalletTransaction)">
            <summary>
            下载电子收据
            </summary>
            <param name="wallet"></param>
            <param name="transaction"></param>
            <returns></returns>
        </member>
        <member name="T:ApiTools.Core.ChannelWalletService">
            <summary>
            渠道钱包服务
            </summary>
            <param name="channelWalletRepository"></param>
            <param name="channelPingAnPayWalletService"></param>
        </member>
        <member name="M:ApiTools.Core.ChannelWalletService.#ctor(ApiTools.Core.ChannelWalletRepository,ApiTools.Core.ChannelPingAnPayWalletService)">
            <summary>
            渠道钱包服务
            </summary>
            <param name="channelWalletRepository"></param>
            <param name="channelPingAnPayWalletService"></param>
        </member>
        <member name="M:ApiTools.Core.ChannelWalletService.GetEnterpriseWallet(System.String)">
            <summary>
            查询企业钱包余额
            </summary>
            <param name="outWalletId"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.ChannelWalletService.GetEnterpriseWalletBalance(ApiTools.Core.ChannelWallet)">
            <summary>
            查询企业钱包余额
            </summary>
            <param name="wallet"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.ChannelWalletService.Transfer(ApiTools.Core.ChannelWallet,ApiTools.Core.ChannelWalletTransaction)">
            <summary>
            转账
            </summary>
            <param name="wallet"></param>
            <param name="transaction"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.ChannelWalletService.GetTransactionDetail(ApiTools.Core.ChannelWallet,ApiTools.Core.ChannelWalletTransaction)">
            <summary>
            查询交易记录
            </summary>
            <param name="wallet"></param>
            <param name="transaction"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.ChannelWalletService.DownloadEreceiptUrl(ApiTools.Core.ChannelWallet,ApiTools.Core.ChannelWalletTransaction)">
            <summary>
            下载电子收据
            </summary>
            <param name="wallet"></param>
            <param name="transaction"></param>
            <returns></returns>
        </member>
        <member name="T:ApiTools.Core.IChannelWalletService">
            <summary>
            渠道钱包服务
            </summary>
        </member>
        <member name="M:ApiTools.Core.IChannelWalletService.GetEnterpriseWalletBalance(ApiTools.Core.ChannelWallet)">
            <summary>
            查询渠道钱包余额
            </summary>
            <param name="wallet"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.IChannelWalletService.Transfer(ApiTools.Core.ChannelWallet,ApiTools.Core.ChannelWalletTransaction)">
            <summary>
            转账
            </summary>
            <param name="wallet"></param>
            <param name="transaction"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.IChannelWalletService.GetTransactionDetail(ApiTools.Core.ChannelWallet,ApiTools.Core.ChannelWalletTransaction)">
            <summary>
            查询交易记录
            </summary>
            <param name="wallet"></param>
            <param name="transaction"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.IChannelWalletService.DownloadEreceiptUrl(ApiTools.Core.ChannelWallet,ApiTools.Core.ChannelWalletTransaction)">
            <summary>
            下载电子收据
            </summary>
            <param name="wallet"></param>
            <param name="transaction"></param>
            <returns></returns>
        </member>
        <member name="T:ApiTools.Core.AlipayUtils">
            <summary>
@@ -3858,460 +4963,6 @@
            数据长度:30,是否必输:N
            </summary>
        </member>
        <member name="T:ApiTools.Core.HistoryBalanceQueryRequest">
            <summary>
            历史余额查询_银企直联
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryRequest.Account">
            <summary>
            账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryRequest.RptDate">
            <summary>
            历史日期 yyyyMMdd限制查询当前日期的前360天内的
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryRequest.Reserve">
            <summary>
            保留域
            </summary>
        </member>
        <member name="T:ApiTools.Core.HistoryBalanceQueryResponse">
            <summary>
            历史余额查询_银企直联
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryResponse.AcctNo">
            <summary>
            账号
            数据长度:20,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryResponse.CcyCode">
            <summary>
            币种
            数据长度:3,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryResponse.BeginDate">
            <summary>
            开始日期
            "若查询当日明细,开始、结束日期必须为当天;若查询历史明细,开始、结束日期必须是历史日期。
            格式yyyyMMdd"
            数据长度:8,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryResponse.EndDate">
            <summary>
            结束日期
            格式yyyyMMdd
            数据长度:8,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryResponse.PageNo">
            <summary>
            查询页码
            1:第一页,依次递增
            数据长度:6,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryResponse.PageSize">
            <summary>
            每页明细数量
            "当日明细默认每页30条记录,支持最大每页100条,若上送PageSize>100无效,等同100;
            历史明细默认每页30条记录,支持最大每页1000条,若上送PageSize>1000则提示输入错误;
            且每次查询必须固定为此值,否则出现明细遗漏"
            数据长度:6,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryResponse.Reserve">
            <summary>
            预留字段
            数据长度:120,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryResponse.OrderMode">
            <summary>
            记录排序标志
            "001:按交易时间降序;
            002:按交易时间升序;
            说明:
            ① 当为历史交易明细查询时,默认按照001:按交易时间降序;
            ② 当为当日明细查询时,默认按照002:按交易时间升序;
            (注:当日明细在交易量大的情况下,必须采用正序查询,否则会导致交易遗漏和重复)"
            数据长度:3,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryResponse.BankTranFlowNo">
            <summary>
            银行交易流水号
            输入则查询过滤指定条件的记录
            数据长度:30,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.HistoryBalanceQueryResponse.OppAcctNo">
            <summary>
            交易对手账号
            输入则查询过滤指定条件的记录
            数据长度:30,是否必输:N
            </summary>
        </member>
        <member name="T:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest">
            <summary>
            查询账户当日历史交易明细_银企直联
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest.AcctNo">
            <summary>
            账号
            数据长度:20,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest.CcyCode">
            <summary>
            币种
            数据长度:3,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest.BeginDate">
            <summary>
            开始日期
            "若查询当日明细,开始、结束日期必须为当天;若查询历史明细,开始、结束日期必须是历史日期。
            格式yyyyMMdd"
            数据长度:8,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest.EndDate">
            <summary>
            结束日期
            格式yyyyMMdd
            数据长度:8,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest.PageNo">
            <summary>
            查询页码
            1:第一页,依次递增
            数据长度:6,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest.PageSize">
            <summary>
            每页明细数量
            "当日明细默认每页30条记录,支持最大每页100条,若上送PageSize>100无效,等同100;
            历史明细默认每页30条记录,支持最大每页1000条,若上送PageSize>1000则提示输入错误;
            且每次查询必须固定为此值,否则出现明细遗漏"
            数据长度:6,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest.Reserve">
            <summary>
            预留字段
            数据长度:120,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest.OrderMode">
            <summary>
            记录排序标志
            "001:按交易时间降序;
            002:按交易时间升序;
            说明:
            ① 当为历史交易明细查询时,默认按照001:按交易时间降序;
            ② 当为当日明细查询时,默认按照002:按交易时间升序;
            (注:当日明细在交易量大的情况下,必须采用正序查询,否则会导致交易遗漏和重复)"
            数据长度:3,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest.BankTranFlowNo">
            <summary>
            银行交易流水号
            输入则查询过滤指定条件的记录
            数据长度:30,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest.OppAcctNo">
            <summary>
            交易对手账号
            输入则查询过滤指定条件的记录
            数据长度:30,是否必输:N
            </summary>
        </member>
        <member name="T:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponse">
            <summary>
            查询账户当日历史交易明细_银企直联
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponse.AcctNo">
            <summary>
            账号
            数据长度:20,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponse.CcyCode">
            <summary>
            货币类型
            数据长度:3,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponse.EndFlag">
            <summary>
            数据结束标志
            "“Y”---表示查询结果已全部输出完毕;
            “N”---表示查询结果只输出一部分,后续部分有待请求输出;"
            数据长度:1,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponse.Reserve">
            <summary>
            预留字段
            数据长度:120,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponse.PageNo">
            <summary>
            查询页码
            同上送
            数据长度:6,是否必输:Y
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponse.PageRecCount">
            <summary>
            记录笔数
            本次返回的笔数
            数据长度:2,是否必输:N
            </summary>
        </member>
        <member name="T:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem">
            <summary>
            查询账户当日历史交易明细_银企直联
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.AcctDate">
            <summary>
            主机记账日期
            记账日期
            数据长度:8,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.TxTime">
            <summary>
            交易时间
            数据长度:6,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.HostTrace">
            <summary>
            主机流水号
            银行记账流水号
            数据长度:32,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.BussSeqNo">
            <summary>
            业务流水号
            银行业务流水号
            数据长度:32,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.DetailSerialNo">
            <summary>
            明细序号
            明细序号,原来和核心水号一起区分交易唯一性
            数据长度:19,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.OutNode">
            <summary>
            付款方网点号
            数据长度:9,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.OutBankNo">
            <summary>
            付款方联行号
            数据长度:16,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.OutBankName">
            <summary>
            付款行名称
            数据长度:120,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.OutAcctNo">
            <summary>
            付款方账号
            数据长度:32,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.OutAcctName">
            <summary>
            付款方户名
            数据长度:120,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.CcyCode">
            <summary>
            结算币种
            数据长度:3,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.TranAmount">
            <summary>
            交易金额
            数据长度:15,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.InNode">
            <summary>
            收款方网点号
            数据长度:9,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.InBankNo">
            <summary>
            收款方联行号
            数据长度:16,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.InBankName">
            <summary>
            收款方行名
            数据长度:120,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.InAcctNo">
            <summary>
            收款方账号
            数据长度:32,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.InAcctName">
            <summary>
            收款方户名
            数据长度:120,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.DcFlag">
            <summary>
            借贷标志
            D 借;C 贷
            数据长度:1,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.AbstractStr">
            <summary>
            摘要,未翻译的摘要,如TRS
            数据长度:120,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.VoucherNo">
            <summary>
            凭证号
            空
            数据长度:20,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.TranFee">
            <summary>
            手续费
            数据长度:15,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.PostFee">
            <summary>
            邮电费
            数据长度:15,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.AcctBalance">
            <summary>
            账面余额
            数据长度:15,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.Purpose">
            <summary>
            用途,附言
            客户转账上送的资金用途。
            数据长度:300,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.AbstractStr_Desc">
            <summary>
            中文摘要,AbstractStr的中文翻译
            数据长度:100,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.ProxyPayName">
            <summary>
            代理人户名
            用于代理行支付功能
            数据长度:100,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.ProxyPayAcc">
            <summary>
            代理人账号
            用于代理行支付功能
            数据长度:100,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.ProxyPayBankName">
            <summary>
            代理人银行名称
            用于代理行支付功能
            数据长度:100,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.HostDate">
            <summary>
            主机日期
            交易自然日期
            数据长度:8,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.TranSeqNo">
            <summary>
            交易流水号
            数据长度:32,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.Remark1">
            <summary>
            备注1
            数据长度:300,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.Remark2">
            <summary>
            备注2
            数据长度:300,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.BeReverseFlag">
            <summary>
            被冲正标志
            "0--无关;
            1--被冲正;
            2--冲正"
            数据长度:2,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.SeqTime">
            <summary>
            时序时间
            数据长度:30,是否必输:N
            </summary>
        </member>
        <member name="P:ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsResponseItem.FeeCode">
            <summary>
            费用代码
            数据长度:20,是否必输:N
            </summary>
        </member>
        <member name="T:ApiTools.Core.InquiryAccountStopPaymentDetailsRequest">
            <summary>
            账户止付详情查询_银企直联 对公账户层的冻结/止付详情查询,每页最大100条。
@@ -4798,456 +5449,6 @@
            交易状态标志 20:交易成功 30:失败;其他为银行受理成功处理中,请使用“交易进度查询4005”接口获取最终状态
            </summary>
        </member>
        <member name="T:ApiTools.Core.SingleDataQueryRequest">
            <summary>
            回单数据查询_银企直联
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.AcctNo">
            <summary>
            账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.ReceiptType">
            <summary>
            回单类型 参照回单类型 注:查全部可送“ALL”
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.SubType">
            <summary>
            子类型 参照回单类型 注:查全部可送“ALL”
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.StartDate">
            <summary>
            起始日期 格式yyyyMMdd(记账日期)
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.EndDate">
            <summary>
            结束日期 格式yyyyMMdd(记账日期)
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.StartRecord">
            <summary>
            起始记录数 起始值为1,不能送0
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.RecordNum">
            <summary>
            本批记录数
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.StartAmt">
            <summary>
            开始金额 (交易金额)double(20,4)
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.EntAmt">
            <summary>
            结束金额  (交易金额)double(20,5)
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.OrderMode">
            <summary>
            排序方式  001:交易时间从近到远
            002:交易时间从远到近
            003:金额升序(从小到大)
            004:金额降序(从大到小)
            005:回单号升序
            006:回单号降序
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.PayeeAcctNo">
            <summary>
            收款人账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.PayeeName">
            <summary>
            收款人名称
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.DrCrFlag">
            <summary>
            借贷标志 D:借方交易 C:贷方交易
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.Ccy">
            <summary>
            币种
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.SerialNo">
            <summary>
            顺序号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.PrintBranchId">
            <summary>
            打印网点 代码里面没有
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.ReceiptNo">
            <summary>
            回单号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryRequest.PrintFlag">
            <summary>
            打印标志 0:首次打印 1:补打
            </summary>
        </member>
        <member name="T:ApiTools.Core.SingleDataQueryResponse">
            <summary>
            回单数据查询_银企直联
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponse.RecordTotalCount">
            <summary>
            记录总数
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponse.StartRecord">
            <summary>
            起始记录数
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponse.ResultNum">
            <summary>
            本次返回记录数
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponse.EndFlag">
            <summary>
            结束标志 Y:无剩余记录 N:有剩余记录
            </summary>
        </member>
        <member name="T:ApiTools.Core.SingleDataQueryResponseItem">
            <summary>
            回单数据查询_银企直联
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.ReceiptNo">
            <summary>
            回单号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.CheckCode">
            <summary>
            验证码
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.ReceiptType">
            <summary>
            回单类型
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.SubType">
            <summary>
            回单子类
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.BookingDate">
            <summary>
            记账日期
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PayerName">
            <summary>
            付款人名称
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PayeeName">
            <summary>
            收款人名称
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PayerAccNo">
            <summary>
            付款人账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PayeeAccNo">
            <summary>
            收款人账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PayerAcctOpenBranchID">
            <summary>
            付款人开户行
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PayeeAcctOpenBranchID">
            <summary>
            收款人开户行
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PayerAcctOpenBranchName">
            <summary>
            付款人开户行名称
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PayeeAcctOpenBranchName">
            <summary>
            收款人开户行名称
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.MainAcctNo">
            <summary>
            主账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.SubAcctNo">
            <summary>
            子账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.OldAcctNo">
            <summary>
            原账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.Ccy">
            <summary>
            币种
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.TranAmt">
            <summary>
            交易金额
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.SubBranchID">
            <summary>
            网点号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.DrCrFlag">
            <summary>
            借贷标志
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.Crpp">
            <summary>
            资金用途
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.Corpus">
            <summary>
            本金
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.DepositIntRate">
            <summary>
            存款利率
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.DepositReceiptNo">
            <summary>
            存单号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.StartPeriod">
            <summary>
            起始期
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.EndPeriod">
            <summary>
            结束期
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.InterestTax">
            <summary>
            利息税
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.IntInterest">
            <summary>
            利息
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.OverdraftInterest">
            <summary>
            透支利息
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.TaxRate">
            <summary>
            税率
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.LoanAcctNo">
            <summary>
            贷款账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.DuebillNo">
            <summary>
            借据号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PaidAmt">
            <summary>
            还款金额
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.RepayCorpus">
            <summary>
            还款本金
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.ReplyInterest">
            <summary>
            还款利息
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.ComInterest">
            <summary>
            复利
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.CorpusBalance">
            <summary>
            本金余额
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.DueRepayCorpus">
            <summary>
            应还本金
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.RepayCount">
            <summary>
            还款期数
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.Commission">
            <summary>
            手续费金额
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.MaterialFee">
            <summary>
            工本费
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.TaxedInterest">
            <summary>
            税后利息
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.HostSeqNo">
            <summary>
            主机流水号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.LoanIntRate">
            <summary>
            贷款利率
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.ReceivableInterest">
            <summary>
            应收利息
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.TellerNo">
            <summary>
            柜员号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.AuthTellerNo">
            <summary>
            授权柜员号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PrintClientName">
            <summary>
            打印客户端名称
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PrintTime">
            <summary>
            打印时间
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PrintTimes">
            <summary>
            打印次数
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.RegionNo">
            <summary>
            地区号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.TermNo">
            <summary>
            终端号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.PrintNote">
            <summary>
            打印节点
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.BussType">
            <summary>
            业务类型
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.IntSettleAcctNo">
            <summary>
            结息账号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.AcctOpenBranchID">
            <summary>
            账户开户行行号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.TranDate">
            <summary>
            交易日期
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.TranTime">
            <summary>
            交易时间
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.BranchId">
            <summary>
            机构号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.SerialNo">
            <summary>
            顺序号
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.RecordType">
            <summary>
            记录类型
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.FrontEndCode">
            <summary>
            前置机代码
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.RemarkCode">
            <summary>
            摘要码
            </summary>
        </member>
        <member name="P:ApiTools.Core.SingleDataQueryResponseItem.Summary">
            <summary>
            摘要
            </summary>
        </member>
        <member name="T:ApiTools.Core.SingleOrBatchReceiptPDFMergeDownloadNewRequest">
            <summary>
            单笔或多笔回单PDF合并下载(新)_银企直联
@@ -5398,20 +5599,6 @@
            <param name="request"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.PingAnPayUtils.HistoryBalanceQuery(ApiTools.Core.HistoryBalanceQueryRequest)">
            <summary>
            历史余额查询_银企直联
            </summary>
            <param name="request"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.PingAnPayUtils.InquiryAccountDayHistoryTransactionDetails(ApiTools.Core.InquiryAccountDayHistoryTransactionDetailsRequest)">
            <summary>
            查询账户当日历史交易明细_银企直联
            </summary>
            <param name="request"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.PingAnPayUtils.StopPaymentAndSettlementAccounts(ApiTools.Core.StopPaymentAndSettlementAccountsRequest)">
            <summary>
            账户止付和解止付_银企直联 对公账户层的止付、解除止付
@@ -5436,13 +5623,6 @@
        <member name="M:ApiTools.Core.PingAnPayUtils.CorSingleTransferQuery(ApiTools.Core.CorSingleTransferQueryRequest)">
            <summary>
            单笔转账指令查询_银企直联
            </summary>
            <param name="request"></param>
            <returns></returns>
        </member>
        <member name="M:ApiTools.Core.PingAnPayUtils.SingleDataQuery(ApiTools.Core.SingleDataQueryRequest)">
            <summary>
            当日历史回单数据查询接口_银企直联
            </summary>
            <param name="request"></param>
            <returns></returns>
ApiTools.Core/Entities/Users/ChannelWallet.cs
New file
@@ -0,0 +1,81 @@
using Furion.DatabaseAccessor;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 渠道钱包
    /// </summary>
    public class ChannelWallet : CommonEntity<MasterDbContextLocator>
    {
        /// <summary>
        /// 渠道Id
        /// </summary>
        public Guid? ChannelId { get; set; }
        /// <summary>
        /// 渠道
        /// </summary>
        public Channel Channel { get; set; }
        /// <summary>
        /// 外部钱包Id
        /// </summary>
        public string OutWalletId { get; set; }
        /// <summary>
        /// 通道
        /// </summary>
        public EnumWalletAccess Access { get; set; }
        /// <summary>
        /// 编号
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 所属银行
        /// </summary>
        public string Bank { get; set; }
        /// <summary>
        /// 所属支行
        /// </summary>
        public string BankBranch { get; set; }
        /// <summary>
        /// 户名
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 账号
        /// </summary>
        public string Identity { get; set; }
        /// <summary>
        /// 余额
        /// </summary>
        public decimal Balance { get; set; }
        /// <summary>
        /// 签约状态
        /// </summary>
        public EnumWalletSignStatus SignStatus { get; set; }
        /// <summary>
        /// 错误代码
        /// </summary>
        public string ErrorCode { get; set; }
        /// <summary>
        /// 返回具体的原因。
        /// </summary>
        public string FailReason { get; set; }
    }
}
ApiTools.Core/Entities/Users/ChannelWalletTransaction.cs
New file
@@ -0,0 +1,204 @@
using Furion.DatabaseAccessor;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 渠道钱包交易
    /// </summary>
    public class ChannelWalletTransaction : CommonEntity<MasterDbContextLocator>, IEntityTypeBuilder<ChannelWalletTransaction>
    {
        /// <summary>
        /// 钱包Id
        /// </summary>
        public Guid WalletId { get; set; }
        /// <summary>
        /// 钱包
        /// </summary>
        public ChannelWallet Wallet { get; set; }
        /// <summary>
        /// 平安信息
        /// </summary>
        public ChannelWalletTransactionPingAnPay PingAnPay { get; set; }
        /// <summary>
        /// 类型
        /// </summary>
        public EnumWalletTransactionType Type { get; set; }
        /// <summary>
        /// 订单号
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 外部订单号
        /// </summary>
        public string OutCode { get; set; }
        /// <summary>
        /// 并发锁
        /// </summary>
        public string ConcurrencyLock { get; set; }
        /// <summary>
        /// 金额
        /// </summary>
        public decimal Amount { get; set; }
        /// <summary>
        /// 余额
        /// </summary>
        public decimal Balance { get; set; }
        /// <summary>
        /// 收支后余额
        /// </summary>
        public decimal AfterBalance { get; set; }
        /// <summary>
        /// 外部操作人Id
        /// </summary>
        public string OutOperatorId { get; set; }
        /// <summary>
        /// 操作时间
        /// </summary>
        public DateTime? OperatorTime { get; set; }
        /// <summary>
        /// 付款人账户
        /// </summary>
        public string PayerAccount { get; set; }
        /// <summary>
        /// 付款人名称
        /// </summary>
        public string PayerName { get; set; }
        /// <summary>
        /// 付款人开户行
        /// </summary>
        public string PayerBank { get; set; }
        /// <summary>
        /// 付款人支行
        /// </summary>
        public string PayerBankBranch { get; set; }
        /// <summary>
        /// 外部收款人Id
        /// </summary>
        public string OutReceiveId { get; set; }
        /// <summary>
        /// 收款人姓名
        /// </summary>
        public string ReceiveName { get; set; }
        /// <summary>
        /// 收款人身份证号
        /// </summary>
        public string ReceiveIdentity { get; set; }
        /// <summary>
        /// 收款账户
        /// </summary>
        public string ReceiveAccount { get; set; }
        /// <summary>
        /// 收款人开户行
        /// </summary>
        public string ReceiveBank { get; set; }
        /// <summary>
        /// 收款人支行
        /// </summary>
        public string ReceiveBankBranch { get; set; }
        /// <summary>
        /// 币种
        /// </summary>
        public string Currency { get; set; }
        /// <summary>
        /// 用途
        /// </summary>
        public string Purpose { get; set; }
        /// <summary>
        /// 备注
        /// </summary>
        public string Remark { get; set; }
        /// <summary>
        /// 查询到的订单状态为FAIL失败或REFUND退票时,返回错误代码
        /// </summary>
        public string ErrorCode { get; set; }
        /// <summary>
        /// 查询到的订单状态为FAIL失败或REFUND退票时,返回具体的原因。
        /// </summary>
        public string FailReason { get; set; }
        /// <summary>
        /// 订单支付时间
        /// </summary>
        public DateTime? TransDate { get; set; }
        /// <summary>
        /// 预计收费金额(元),转账到银行卡专用
        /// </summary>
        public decimal? OrderFee { get; set; }
        /// <summary>
        /// 电子收据Id
        /// </summary>
        public string EreceiptFileId { get; set; }
        /// <summary>
        /// 电子收据下载链接
        /// </summary>
        public string EreceiptDownloadUrl { get; set; }
        /// <summary>
        /// 电子收据下载链接
        /// </summary>
        public string EreceiptDownloadOssUrl { get; set; }
        /// <summary>
        /// 电子收据状态
        /// </summary>
        public EnumWalletTransactionEreceiptStatus? EreceiptStatus { get; set; }
        /// <summary>
        /// 电子收据错误信息
        /// </summary>
        public string EreceiptErrorMessage { get; set; }
        /// <summary>
        /// 状态
        /// </summary>
        public EnumWalletTransactionStatus TransactionStatus { get; set; }
        public void Configure(EntityTypeBuilder<ChannelWalletTransaction> entityBuilder, DbContext dbContext, Type dbContextLocator)
        {
            entityBuilder
                .HasOne(it => it.PingAnPay)
                .WithOne(it => it.Transaction)
                .HasForeignKey<ChannelWalletTransactionPingAnPay>(it => it.Id);
            entityBuilder
                .HasIndex(it => it.ConcurrencyLock)
                .IsUnique();
        }
    }
}
ApiTools.Core/Entities/Users/ChannelWalletTransactionPingAnPay.cs
New file
@@ -0,0 +1,165 @@
using Furion.DatabaseAccessor;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 渠道钱包交易记录平安支付信息
    /// </summary>
    public class ChannelWalletTransactionPingAnPay : CommonEntity<MasterDbContextLocator>
    {
        /// <summary>
        /// 交易
        /// </summary>
        public ChannelWalletTransaction Transaction { get; set; }
        /// <summary>
        /// 止付编号 有效状态的平安易止付编号,从JGF001止付后返回的
        /// </summary>
        public string FreezeNo { get; set; }
        /// <summary>
        /// 止付状态码
        /// </summary>
        public string StopStt { get; set; }
        /// <summary>
        /// 止付失败原因
        /// </summary>
        public string StopFailReason { get; set; }
        /// <summary>
        /// 解除止付状态码
        /// </summary>
        public string RemoveStopStt { get; set; }
        /// <summary>
        /// 解除止付失败原因
        /// </summary>
        public string RemoveStopFailReason { get; set; }
        /// <summary>
        /// 转账凭证号
        /// </summary>
        public string ThirdVoucher { get; set; }
        /// <summary>
        /// 银行流水号 银行业务流水号;可以用于对账
        /// </summary>
        public string FrontLogNo { get; set; }
        /// <summary>
        /// 客户自定义凭证号 用于客户转账登记和内部识别,通过转账结果查询可以返回。银行不检查唯一性
        /// </summary>
        public string CstInnerFlowNo { get; set; }
        /// <summary>
        /// 转账退票标志
        /// "0:未退票; 默认为0
        /// 1:退票;"
        /// 数据长度:1,是否必输:N
        /// </summary>
        public string IsBack { get; set; }
        /// <summary>
        /// 支付失败或退票原因描述
        /// "如果是超级网银则返回如下信息:
        /// RJ01对方返回:账号不存在
        /// RJ02对方返回:账号、户名不符
        /// 大小额支付则返回失败描述"
        /// 数据长度:20,是否必输:N
        /// </summary>
        public string BackRem { get; set; }
        /// <summary>
        /// 银行处理结果
        /// "格式为:“六位代码:中文描述”。冒号为半角。如:000000:转账成功
        /// 处理中的返回(以如下返回开头):
        /// MA9111:交易正在受理中
        /// 000000:交易受理成功待处理
        /// 000000:交易处理中
        /// 000000:交易受理成功处理中
        /// 成功的返回:
        /// 000000:转账交易成功
        /// 其他的返回都为失败:
        /// MA9112:转账失败"
        /// 数据长度:40,是否必输:Y
        /// </summary>
        public string Yhcljg { get; set; }
        /// <summary>
        /// 转账加急标志
        /// Y:加急 N:普通S:特急
        /// 数据长度:1,是否必输:Y
        /// </summary>
        public string SysFlag { get; set; }
        /// <summary>
        /// 转账手续费
        /// 数据长度:13,是否必输:Y
        /// </summary>
        public string Fee { get; set; }
        /// <summary>
        /// 转账代码类型
        /// "4004:单笔转账;
        /// 4014:单笔批量;
        /// 4034:汇总批量"
        /// 数据长度:4,是否必输:Y
        /// </summary>
        public string TransBsn { get; set; }
        /// <summary>
        /// 交易受理时间
        /// 交易受理时间
        /// 数据长度:14,是否必输:N
        /// </summary>
        public string SubmitTime { get; set; }
        /// <summary>
        /// 记账日期
        /// 主机记账日期
        /// 数据长度:8,是否必输:N
        /// </summary>
        public string AccountDate { get; set; }
        /// <summary>
        /// 主机记账流水号
        /// 主机记账流水
        /// 数据长度:32,是否必输:N
        /// </summary>
        public string HostFlowNo { get; set; }
        /// <summary>
        /// 错误码
        /// 交易失败的错误代码
        /// 数据长度:20,是否必输:N
        /// </summary>
        public string HostErrorCode { get; set; }
        /// <summary>
        /// 代理人户名
        /// 用于代理行支付功能
        /// 数据长度:60,是否必输:N
        /// </summary>
        public string ProxyPayName { get; set; }
        /// <summary>
        /// 代理人账号
        /// 用于代理行支付功能
        /// 数据长度:30,是否必输:N
        /// </summary>
        public string ProxyPayAcc { get; set; }
        /// <summary>
        /// 代理人银行名称
        /// 用于代理行支付功能
        /// 数据长度:30,是否必输:N
        /// </summary>
        public string ProxyPayBankName { get; set; }
    }
}
ApiTools.Core/Enums/Resources/EnumResourceController.cs
@@ -53,6 +53,11 @@
        [ResourceController(EnumResourceService.UserServer, "Channel")]
        UserServerChannel,
        /// <summary>
        /// 渠道钱包
        /// </summary>
        [ResourceController(EnumResourceService.UserServer, "ChannelWallet")]
        UserServerChannelWallet,
        /// <summary>
        /// 渠道用户
        /// </summary>
        [ResourceController(EnumResourceService.UserServer, "ChannelUser")]
ApiTools.Core/Enums/Users/EnumWalletAccess.cs
New file
@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 渠道钱包通道
    /// </summary>
    public enum EnumWalletAccess
    {
        /// <summary>
        /// 支付宝
        /// </summary>
        Alipay = 10,
        /// <summary>
        /// 平安银行
        /// </summary>
        PingAnPay = 20,
        /// <summary>
        /// 微信
        /// </summary>
        WeChatPay = 30,
    }
}
ApiTools.Core/Enums/Users/EnumWalletSignStatus.cs
New file
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 渠道钱包签约状态
    /// </summary>
    public enum EnumWalletSignStatus
    {
        /// <summary>
        /// 未签约
        /// </summary>
        Wait = 1,
        /// <summary>
        /// 申请中
        /// </summary>
        Apply = 10,
        /// <summary>
        /// 已签约
        /// </summary>
        Normal = 100,
        /// <summary>
        /// 终止
        /// </summary>
        Stop = 999
    }
}
ApiTools.Core/Enums/Users/EnumWalletTransactionEreceiptStatus.cs
New file
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 钱包交易电子收据状态
    /// </summary>
    public enum EnumWalletTransactionEreceiptStatus
    {
        /// <summary>
        /// 初始化
        /// </summary>
        INIT = 10,
        /// <summary>
        /// 处理中
        /// </summary>
        PROCESS = 20,
        /// <summary>
        /// 成功
        /// </summary>
        SUCCESS = 30,
        /// <summary>
        /// 失败
        /// </summary>
        FAIL = 40,
    }
}
ApiTools.Core/Enums/Users/EnumWalletTransactionStatus.cs
New file
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 钱包交易状态
    /// </summary>
    public enum EnumWalletTransactionStatus
    {
        /// <summary>
        /// 待提交
        /// </summary>
        WaitSubmit = 1,
        /// <summary>
        /// 待支付
        /// </summary>
        WaitPay = 10,
        /// <summary>
        /// 处理中
        /// </summary>
        Dealing = 20,
        /// <summary>
        /// 成功
        /// </summary>
        Success = 30,
        /// <summary>
        /// 退票
        /// </summary>
        Refund = 40,
        /// <summary>
        /// 失败
        /// </summary>
        Fail = 50,
    }
}
ApiTools.Core/Enums/Users/EnumWalletTransactionType.cs
New file
@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    public enum EnumWalletTransactionType
    {
        /// <summary>
        /// 充值
        /// </summary>
        Recharge = 10,
        /// <summary>
        /// 转账
        /// </summary>
        Transfer = 20
    }
}
ApiTools.Core/Jobs/RefreshChannelWalletTransactionStatusJob.cs
New file
@@ -0,0 +1,58 @@
using Furion;
using Furion.DatabaseAccessor;
using Furion.EventBus;
using Furion.Schedule;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 刷新渠道钱包交易状态
    /// </summary>
    [JobDetail("RefreshChannelWalletTransactionStatusJob", Description = "刷新渠道钱包交易状态", Concurrent = false)]
    [PeriodMinutes(5)]
    public class RefreshChannelWalletTransactionStatusJob(
            ChannelWalletRepository channelWalletRepository,
            ChannelWalletTransactionRepository channelWalletTransactionRepository,
            ChannelWalletService channelWalletService
        ) : IJob
    {
        private readonly ChannelWalletRepository channelWalletRepository = channelWalletRepository;
        private readonly ChannelWalletTransactionRepository channelWalletTransactionRepository = channelWalletTransactionRepository;
        private readonly ChannelWalletService channelWalletService = channelWalletService;
        public async Task ExecuteAsync(JobExecutingContext context, CancellationToken stoppingToken)
        {
            var env = App.GetConfig<string>("Environment");
            if (env != "Local")
            {
                var transactions = await channelWalletTransactionRepository.GetQueryable(false)
                .Where(it =>
                    it.TransactionStatus == EnumWalletTransactionStatus.WaitPay
                    || it.TransactionStatus == EnumWalletTransactionStatus.Dealing)
                .ToListAsync();
                var walletIds = transactions.DistinctSelect(it => it.WalletId);
                var wallets = await channelWalletRepository.GetQueryable(false)
                    .Where(it => walletIds.Contains(it.Id))
                    .ToListAsync();
                foreach (var transaction in transactions)
                {
                    var wallet = wallets.FirstOrDefault(it => it.Id == transaction.WalletId);
                    if (wallet != null)
                    {
                        // 查询交易详情
                        await channelWalletService.GetTransactionDetail(wallet, transaction);
                        // 下载回单
                        await channelWalletService.DownloadEreceiptUrl(wallet, transaction);
                    }
                }
            }
        }
    }
}
ApiTools.Core/Models/ChannelWallets/Commands/SaveChannelPingAnPayWalletCommand.cs
New file
@@ -0,0 +1,45 @@
using MediatR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 保存渠道平安银行钱包
    /// </summary>
    [Resource([EnumResourceController.UserServerChannelWallet])]
    public class SaveChannelPingAnPayWalletCommand : IRequest<SaveChannelPingAnPayWalletCommandResult>
    {
        /// <summary>
        /// 外部钱包Id
        /// </summary>
        public string OutWalletId { get; set; }
        /// <summary>
        /// 户名
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 账号
        /// </summary>
        public string Identity { get; set; }
    }
    public class SaveChannelPingAnPayWalletCommandResult
    {
        /// <summary>
        /// 钱包Id
        /// </summary>
        public Guid Id { get; set; }
        /// <summary>
        /// 余额
        /// </summary>
        public decimal Balance { get; set; }
    }
}
ApiTools.Core/Models/ChannelWallets/Commands/SubmitChannelWalletTransferCommand.cs
New file
@@ -0,0 +1,118 @@
using MediatR;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 提交渠道钱包转账
    /// </summary>
    [Resource([EnumResourceController.UserServerChannelWallet])]
    public class SubmitChannelWalletTransferCommand : IRequest<SubmitChannelWalletTransferCommandResult>
    {
        /// <summary>
        /// 外部钱包Id
        /// </summary>
        public string OutWalletId { get; set; }
        /// <summary>
        /// 外部订单号
        /// </summary>
        public string OutCode { get; set; }
        /// <summary>
        /// 外部操作人Id
        /// </summary>
        public string OutOperatorId { get; set; }
        /// <summary>
        /// 操作时间
        /// </summary>
        public DateTime? OperatorTime { get; set; }
        /// <summary>
        /// 外部收款人Id
        /// </summary>
        public string OutReceiveId { get; set; }
        /// <summary>
        /// 金额
        /// </summary>
        public decimal Amount { get; set; }
        /// <summary>
        /// 收款人姓名
        /// </summary>
        public string ReceiveName { get; set; }
        /// <summary>
        /// 收款人身份证号
        /// </summary>
        public string ReceiveIdentity { get; set; }
        /// <summary>
        /// 收款账户
        /// </summary>
        public string ReceiveAccount { get; set; }
        /// <summary>
        /// 收款人开户行
        /// </summary>
        public string ReceiveBank { get; set; }
        /// <summary>
        /// 收款人支行
        /// </summary>
        public string ReceiveBankBranch { get; set; }
        /// <summary>
        /// 币种
        /// </summary>
        public string Currency { get; set; }
        /// <summary>
        /// 用途
        /// </summary>
        public string Purpose { get; set; }
        /// <summary>
        /// 备注
        /// </summary>
        public string Remark { get; set; }
    }
    public class SubmitChannelWalletTransferCommandResult
    {
        /// <summary>
        /// 交易Id
        /// </summary>
        public Guid Id { get; set; }
        /// <summary>
        /// 订单号
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 状态
        /// </summary>
        public EnumWalletTransactionStatus TransactionStatus { get; set; }
        /// <summary>
        /// 查询到的订单状态为FAIL失败或REFUND退票时,返回错误代码
        /// </summary>
        public string ErrorCode { get; set; }
        /// <summary>
        /// 查询到的订单状态为FAIL失败或REFUND退票时,返回具体的原因。
        /// </summary>
        public string FailReason { get; set; }
    }
}
ApiTools.Core/Models/ChannelWallets/Queries/GetChannelPingAnPayWalletQuery.cs
New file
@@ -0,0 +1,53 @@
using MediatR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 查询渠道平安银行钱包
    /// </summary>
    [Resource([EnumResourceController.UserServerChannelWallet])]
    public class GetChannelPingAnPayWalletQuery : IRequest<GetChannelPingAnPayWalletQueryResult>
    {
        /// <summary>
        /// 外部钱包Id
        /// </summary>
        public string OutWalletId { get; set; }
    }
    /// <summary>
    /// 查询渠道平安银行钱包
    /// </summary>
    public class GetChannelPingAnPayWalletQueryResult
    {
        /// <summary>
        /// 钱包Id
        /// </summary>
        public Guid Id { get; set; }
        /// <summary>
        /// 户名
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 账号
        /// </summary>
        public string Identity { get; set; }
        /// <summary>
        /// 余额
        /// </summary>
        public decimal Balance { get; set; }
        /// <summary>
        /// 签约状态
        /// </summary>
        public EnumWalletSignStatus SignStatus { get; set; }
    }
}
ApiTools.Core/Models/ChannelWallets/Queries/GetChannelWalletTransactionQuery.cs
New file
@@ -0,0 +1,192 @@
using MediatR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 查询渠道钱包交易详情
    /// </summary>
    [Resource([EnumResourceController.UserServerChannelWallet])]
    public class GetChannelWalletTransactionQuery : IRequest<GetChannelWalletTransactionQueryResult>
    {
        /// <summary>
        /// 外部订单号
        /// </summary>
        public string OutCode { get; set; }
    }
    /// <summary>
    /// 查询渠道钱包交易详情
    /// </summary>
    public class GetChannelWalletTransactionQueryResult
    {
        /// <summary>
        /// 交易Id
        /// </summary>
        public Guid Id { get; set; }
        /// <summary>
        /// 类型
        /// </summary>
        public EnumWalletTransactionType Type { get; set; }
        /// <summary>
        /// 订单号
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// 外部订单号
        /// </summary>
        public string OutCode { get; set; }
        /// <summary>
        /// 并发锁
        /// </summary>
        public string ConcurrencyLock { get; set; }
        /// <summary>
        /// 金额
        /// </summary>
        public decimal Amount { get; set; }
        /// <summary>
        /// 余额
        /// </summary>
        public decimal Balance { get; set; }
        /// <summary>
        /// 收支后余额
        /// </summary>
        public decimal AfterBalance { get; set; }
        /// <summary>
        /// 外部操作人Id
        /// </summary>
        public string OutOperatorId { get; set; }
        /// <summary>
        /// 操作时间
        /// </summary>
        public DateTime? OperatorTime { get; set; }
        /// <summary>
        /// 付款人账户
        /// </summary>
        public string PayerAccount { get; set; }
        /// <summary>
        /// 付款人名称
        /// </summary>
        public string PayerName { get; set; }
        /// <summary>
        /// 付款人开户行
        /// </summary>
        public string PayerBank { get; set; }
        /// <summary>
        /// 付款人支行
        /// </summary>
        public string PayerBankBranch { get; set; }
        /// <summary>
        /// 外部收款人Id
        /// </summary>
        public string OutReceiveId { get; set; }
        /// <summary>
        /// 收款人姓名
        /// </summary>
        public string ReceiveName { get; set; }
        /// <summary>
        /// 收款人身份证号
        /// </summary>
        public string ReceiveIdentity { get; set; }
        /// <summary>
        /// 收款账户
        /// </summary>
        public string ReceiveAccount { get; set; }
        /// <summary>
        /// 收款人开户行
        /// </summary>
        public string ReceiveBank { get; set; }
        /// <summary>
        /// 收款人支行
        /// </summary>
        public string ReceiveBankBranch { get; set; }
        /// <summary>
        /// 币种
        /// </summary>
        public string Currency { get; set; }
        /// <summary>
        /// 用途
        /// </summary>
        public string Purpose { get; set; }
        /// <summary>
        /// 备注
        /// </summary>
        public string Remark { get; set; }
        /// <summary>
        /// 查询到的订单状态为FAIL失败或REFUND退票时,返回错误代码
        /// </summary>
        public string ErrorCode { get; set; }
        /// <summary>
        /// 查询到的订单状态为FAIL失败或REFUND退票时,返回具体的原因。
        /// </summary>
        public string FailReason { get; set; }
        /// <summary>
        /// 订单支付时间
        /// </summary>
        public DateTime? TransDate { get; set; }
        /// <summary>
        /// 预计收费金额(元),转账到银行卡专用
        /// </summary>
        public decimal? OrderFee { get; set; }
        /// <summary>
        /// 电子收据Id
        /// </summary>
        public string EreceiptFileId { get; set; }
        /// <summary>
        /// 电子收据下载链接
        /// </summary>
        public string EreceiptDownloadUrl { get; set; }
        /// <summary>
        /// 电子收据下载链接
        /// </summary>
        public string EreceiptDownloadOssUrl { get; set; }
        /// <summary>
        /// 电子收据状态
        /// </summary>
        public EnumWalletTransactionEreceiptStatus? EreceiptStatus { get; set; }
        /// <summary>
        /// 电子收据错误信息
        /// </summary>
        public string EreceiptErrorMessage { get; set; }
        /// <summary>
        /// 状态
        /// </summary>
        public EnumWalletTransactionStatus TransactionStatus { get; set; }
    }
}
ApiTools.Core/Repositories/BaseRepository.cs
New file
@@ -0,0 +1,351 @@
using EFCore.BulkExtensions;
using Furion.DatabaseAccessor;
using Furion.DistributedIDGenerator;
using Furion.FriendlyException;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    public abstract class BaseRepository<TEntity, TDbContextLocator>
        where TEntity : CommonEntity, new()
        where TDbContextLocator : class, IDbContextLocator
    {
        public readonly IRepository<TEntity, TDbContextLocator> rep;
        public readonly CurrentLogier logier;
        public BaseRepository(
            IRepository<TEntity, TDbContextLocator> rep)
        {
            this.rep = rep;
            logier = JwtUtils.GetCurrentLogier();
        }
        public virtual IQueryable<TEntity> GetQueryableIgnoreFilter(bool noTracking = true)
        {
            return rep.GetQueryable(noTracking);
        }
        /// <summary>
        /// 获取查询
        /// </summary>
        /// <param name="noTracking"></param>
        /// <returns></returns>
        public virtual IQueryable<TEntity> GetQueryable(bool noTracking = true)
        {
            return rep.GetQueryable(noTracking);
        }
        /// <summary>
        /// 获取查询
        /// </summary>
        /// <param name="noTracking"></param>
        /// <param name="query"></param>
        /// <returns></returns>
        public virtual IQueryable<TEntity> GetQueryable(
            bool noTracking,
            Func<IQueryable<TEntity>, IQueryable<TEntity>> query)
        {
            var q = GetQueryable(false);
            if (query != null)
            {
                q = query(q);
            }
            return q;
        }
        /// <summary>
        /// 获取实体
        /// </summary>
        /// <param name="id"></param>
        /// <param name="query"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public virtual Task<TEntity> Get(
            Guid id,
            Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null,
            CancellationToken cancellationToken = default)
        {
            return GetQueryable(false, query)
                .Where(it => it.Id == id)
                .FirstOrDefaultAsync(cancellationToken);
        }
        /// <summary>
        /// 获取实体
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="query"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public virtual Task<List<TEntity>> Get(
            List<Guid> ids,
            Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null,
            CancellationToken cancellationToken = default)
        {
            return GetQueryable(false, query)
                .Where(it => ids.Contains(it.Id))
                .ToListAsync(cancellationToken);
        }
        /// <summary>
        /// 查询选择器数据
        /// </summary>
        /// <typeparam name="TValue"></typeparam>
        /// <typeparam name="TData"></typeparam>
        /// <param name="request"></param>
        /// <param name="getValue"></param>
        /// <param name="getLabel"></param>
        /// <param name="query"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<List<SelectOption<TValue, TData>>> GetSelect<TValue, TData>(
            SelectQuery<TValue, TData> request,
            Func<TData, TValue> getValue,
            Func<TData, string> getLabel,
            Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null,
            CancellationToken cancellationToken = default)
        {
            var q = GetQueryable();
            if (query != null) q = query(q);
            else q = q.OrderBy(it => it.Sort).ThenBy(it => it.CreatedTime);
            var models = await q
                .ProjectToType<TData>()
                .ToListAsync(cancellationToken);
            var options = new List<SelectOption<TValue, TData>>();
            foreach (var model in models)
            {
                var option = new SelectOption<TValue, TData>();
                option.Data = model;
                option.Value = getValue(model);
                option.Label = getLabel(model);
                options.Add(option);
            }
            return options;
        }
        public async Task<TResult> GetDetail<TResult>(
            Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null,
            CancellationToken cancellationToken = default)
        {
            var model = await GetQueryable(false, query)
                .ProjectToType<TResult>()
                .FirstOrDefaultAsync(cancellationToken);
            if (model == null)
            {
                var summary = await typeof(TEntity).GetSummary();
                throw Oops.Oh(EnumErrorCodeType.s404, $"{summary ?? "信息"}");
            }
            return model;
        }
        /// <summary>
        /// 设置是否禁用
        /// </summary>
        /// <param name="request"></param>
        /// <param name="query"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<int> SetIsDisabled(
             SetIsDisabledCommand request,
            Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null,
            CancellationToken cancellationToken = default)
        {
            var q = GetQueryable(false);
            if (query != null) q = query(q);
            var entities = await q
                .Where(it => request.Ids.Contains(it.Id))
                .ToListAsync();
            var isDisabledProperty = typeof(TEntity).GetProperty("IsDisabled", typeof(bool));
            foreach (var entity in entities)
            {
                isDisabledProperty.SetValue(entity, request.IsDisabled);
            }
            await UpdateAsync(entities);
            return entities.Count;
        }
        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="request"></param>
        /// <param name="query"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<int> DeleteData(
            DeleteDataCommand request, Func<IQueryable<TEntity>,
            IQueryable<TEntity>> query = null,
            CancellationToken cancellationToken = default)
        {
            var q = GetQueryable(false);
            if (query != null) q = query(q);
            var entities = await q
                .Where(it => request.Ids.Contains(it.Id))
                .ToListAsync(cancellationToken);
            return entities.Any()
                ? await rep.DeleteNowAsync(entities, cancellationToken)
                : 0;
        }
        /// <summary>
        /// 更新数据
        /// </summary>
        /// <typeparam name="TRequest"></typeparam>
        /// <param name="q"></param>
        /// <param name="request"></param>
        /// <param name="update"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<Guid> UpdateData<TRequest>(
            IQueryable<TEntity> q,
            TRequest request,
            Action<TEntity> update = null,
            CancellationToken cancellationToken = default)
        {
            var entity = await q.FirstOrDefaultAsync();
            if (entity == null)
            {
                var summary = await typeof(TEntity).GetSummary();
                throw Oops.Oh(EnumErrorCodeType.s404, $"{summary ?? "信息"}");
            }
            if (update != null) update(entity);
            else request.Adapt(entity);
            await rep.UpdateAsync(entity);
            return entity.Id;
        }
        /// <summary>
        /// 保存数据
        /// </summary>
        /// <typeparam name="TRequest"></typeparam>
        /// <param name="request"></param>
        /// <param name="query"></param>
        /// <param name="checkExist"></param>
        /// <param name="update"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<TEntity> SaveData<TRequest>(
             TRequest request,
            Func<IQueryable<TEntity>, IQueryable<TEntity>> query = null,
            Expression<Func<TEntity, bool>> checkExist = null,
            Action<TEntity> update = null,
            CancellationToken cancellationToken = default)
            where TRequest : SaveDataCommand, new()
        {
            var xmlDoc = await XmlDocUtils.GetXmlDocAsync();
            var summary = await typeof(TEntity).GetSummary(xmlDoc);
            if (checkExist != null && await GetQueryableIgnoreFilter().AnyAsync(checkExist))
                throw Oops.Oh(EnumErrorCodeType.s405, $"{summary ?? "信息"}");
            if (request.Id.HasValue)
            {
                var q = GetQueryable(false);
                if (query != null) q = query(q);
                var entity = await q.FirstOrDefaultAsync(it => it.Id == request.Id, cancellationToken);
                if (entity == null) throw Oops.Oh(EnumErrorCodeType.s404, $"{summary ?? "信息"}");
                if (update != null) update(entity);
                else request.Adapt(entity);
                await rep.UpdateAsync(entity);
                return entity;
            }
            else
            {
                var entity = new TEntity();
                if (update != null) update(entity);
                else request.Adapt(entity);
                await rep.InsertAsync(entity);
                return entity;
            }
        }
        public virtual Task<List<T1>> SqlQueriesAsync<T1>(string sql, object model, CancellationToken cancellationToken = default)
        {
            return rep.SqlQueriesAsync<T1>(sql, model, cancellationToken);
        }
        public virtual IDbContextTransaction BeginTransaction()
        {
            return rep.Database.BeginTransaction();
        }
        public virtual Task InsertAsync(TEntity entity, CancellationToken cancellationToken = default)
        {
            return rep.InsertAsync(entity, cancellationToken: cancellationToken);
        }
        public virtual Task InsertNowAsync(TEntity entity, CancellationToken cancellationToken = default)
        {
            return rep.InsertNowAsync(entity, cancellationToken: cancellationToken);
        }
        public virtual Task InsertAsync(List<TEntity> entities, CancellationToken cancellationToken = default)
        {
            return rep.InsertAsync(entities, cancellationToken);
        }
        public virtual Task<int> InsertNowAsync(List<TEntity> entities, CancellationToken cancellationToken = default)
        {
            return rep.InsertNowAsync(entities, cancellationToken);
        }
        public virtual async Task BulkInsertAsync(List<TEntity> entities, CancellationToken cancellationToken = default)
        {
            await rep.Context.BulkInsertAsync(entities, cancellationToken: cancellationToken);
        }
        public virtual Task UpdateAsync(TEntity entity)
        {
            return rep.UpdateAsync(entity);
        }
        public virtual Task UpdateNowAsync(TEntity entity)
        {
            return rep.UpdateNowAsync(entity);
        }
        public virtual Task UpdateAsync(List<TEntity> entities)
        {
            return rep.UpdateAsync(entities);
        }
        public virtual Task<int> UpdateNowAsync(List<TEntity> entities)
        {
            return rep.UpdateNowAsync(entities);
        }
        public virtual Task DeleteAsync(TEntity entity)
        {
            return rep.DeleteAsync(entity);
        }
        public virtual Task DeleteNowAsync(TEntity entity, CancellationToken cancellationToken = default)
        {
            return rep.DeleteNowAsync(entity, cancellationToken);
        }
        public virtual Task DeleteAsync(List<TEntity> entities)
        {
            return rep.DeleteAsync(entities);
        }
        public virtual Task<int> DeleteNowAsync(List<TEntity> entities, CancellationToken cancellationToken = default)
        {
            return rep.DeleteNowAsync(entities, cancellationToken);
        }
        public virtual Task SaveNowAsync()
        {
            return rep.SaveNowAsync();
        }
    }
}
ApiTools.Core/Repositories/ChannelWalletRepository.cs
New file
@@ -0,0 +1,66 @@
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Furion.FriendlyException;
using Microsoft.EntityFrameworkCore;
using pingan.openbank.api.sdk.enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 企业钱包仓库
    /// </summary>
    public class ChannelWalletRepository : BaseRepository<ChannelWallet, MasterDbContextLocator>, IScoped
    {
        public ChannelWalletRepository(IRepository<ChannelWallet, MasterDbContextLocator> rep) : base(rep)
        {
        }
        public override IQueryable<ChannelWallet> GetQueryable(bool noTracking = true)
        {
            var q = rep.GetQueryable(noTracking);
            if (logier != null)
            {
                switch (logier.Type)
                {
                    case EnumUserType.Channel:
                        q = q.Where(it => it.ChannelId == logier.ChannelId);
                        break;
                    case EnumUserType.Operation:
                        break;
                    default:
                        break;
                }
            }
            return q;
        }
        public Task<bool> CheckExist(string code, Guid? id)
        {
            return GetQueryableIgnoreFilter()
                    .AnyAsync(it => it.Code == code && it.Id != id);
        }
        /// <summary>
        /// 设置编号
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task SetCode(ChannelWallet entity)
        {
            entity.Code = $"{DateTime.Now:yyyyMMddHHmmss}{new Random(IDGen.NextID().GetHashCode()).Next(1000, 9999)}";
            var exist = await CheckExist(entity.Code, entity.Id);
            if (exist)
            {
                await SetCode(entity);
            }
        }
    }
}
ApiTools.Core/Repositories/EnterpriseWalletTransactionRepository.cs
New file
@@ -0,0 +1,41 @@
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    public class ChannelWalletTransactionRepository : BaseRepository<ChannelWalletTransaction, MasterDbContextLocator>, IScoped
    {
        public ChannelWalletTransactionRepository(IRepository<ChannelWalletTransaction, MasterDbContextLocator> rep) : base(rep)
        {
        }
        public Task<bool> CheckExist(string code, Guid? id)
        {
            return GetQueryableIgnoreFilter()
                    .AnyAsync(it => it.Code == code && it.Id != id);
        }
        /// <summary>
        /// 设置编号
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task SetCode(ChannelWalletTransaction entity)
        {
            entity.Code = $"{DateTime.Now:yyyyMMddHHmmss}{new Random(IDGen.NextID().GetHashCode()).Next(1000, 9999)}";
            var exist = await CheckExist(entity.Code, entity.Id);
            if (exist)
            {
                await SetCode(entity);
            }
        }
    }
}
ApiTools.Core/Services/ChannelPingAnPayWalletService.cs
New file
@@ -0,0 +1,298 @@
using Aop.Api.Domain;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DistributedIDGenerator;
using Furion.FriendlyException;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Identity.Client;
using NetTopologySuite.Index.HPRtree;
using Org.BouncyCastle.Ocsp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    public class ChannelPingAnPayWalletService(
            ChannelWalletRepository channelWalletRepository,
            ChannelWalletTransactionRepository channelWalletTransactionRepository,
            PingAnPayUtils utils
        ) :
        IChannelWalletService, ITransient
    {
        private readonly ChannelWalletRepository channelWalletRepository = channelWalletRepository;
        private readonly ChannelWalletTransactionRepository channelWalletTransactionRepository = channelWalletTransactionRepository;
        private readonly PingAnPayUtils utils = utils;
        /// <summary>
        /// 查询企业钱包余额
        /// </summary>
        /// <param name="wallet"></param>
        /// <returns></returns>
        public async Task<ChannelWallet> GetEnterpriseWalletBalance(ChannelWallet wallet)
        {
            if (wallet != null
                && wallet.Identity.IsNotNull())
            {
                var response = await utils.CorAcctBalanceQuery(new CorAcctBalanceQueryRequest
                {
                    Account = wallet.Identity,
                    CcyCode = "RMB",
                });
                if (response.Code.IsNotNull())
                {
                    wallet.Balance = 0;
                    wallet.ErrorCode = response.Code;
                    wallet.FailReason = response.Message;
                }
                else
                {
                    wallet.ErrorCode = null;
                    wallet.FailReason = null;
                    wallet.SignStatus = EnumWalletSignStatus.Normal;
                    wallet.Balance = response.AcctBalance.ToDecimal().Value;
                }
            }
            return wallet;
        }
        /// <summary>
        /// 转账
        /// </summary>
        /// <param name="wallet"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public async Task Transfer(ChannelWallet wallet, ChannelWalletTransaction transaction)
        {
            transaction.PingAnPay = new ChannelWalletTransactionPingAnPay();
            var responseStop = await utils.StopPaymentAndSettlementAccounts(new StopPaymentAndSettlementAccountsRequest
            {
                CnsmrSeqNo = transaction.Code,
                AccountNo = transaction.PayerAccount,
                OpType = "A",
                CcyCode = "RMB",
                SeqNo = $"{DateTime.Now:yyyyMMddHHmmssfff}{new Random(IDGen.NextID().GetHashCode()).Next(100, 999)}",
                TradeDate = DateTime.Now.ToString("yyyyMMdd").ToInt()!.Value,
                TradeTime = DateTime.Now.ToString("HHmmss").ToInt()!.Value,
            });
            if (responseStop.Code.IsNotNull())
            {
                transaction.ErrorCode = responseStop.Code;
                transaction.FailReason = responseStop.Errors?.FirstOrDefault()?.ErrorMessage ?? responseStop.Message;
                transaction.PingAnPay.StopStt = "30";
                transaction.PingAnPay.StopFailReason = transaction.FailReason;
                await channelWalletTransactionRepository.UpdateNowAsync(transaction);
            }
            else
            {
                if (responseStop.StopPayFlw.IsNotNull() && responseStop.Stt == "20")
                {
                    transaction.PingAnPay.FreezeNo = responseStop.StopPayFlw;
                }
                else
                {
                    var responseStopDetail = await utils.InquiryAccountStopPaymentDetails(new InquiryAccountStopPaymentDetailsRequest
                    {
                        CnsmrSeqNo = transaction.Code,
                        AccountNo = transaction.PayerAccount,
                        PageNo = "1",
                    });
                    if (responseStopDetail.Code.IsNotNull())
                    {
                        transaction.ErrorCode = responseStopDetail.Code;
                        transaction.FailReason = responseStopDetail.Errors?.FirstOrDefault()?.ErrorMessage ?? responseStopDetail.Message;
                        await channelWalletTransactionRepository.UpdateNowAsync(transaction);
                    }
                    else if (responseStopDetail.List.IsNotNull())
                    {
                        transaction.PingAnPay.FreezeNo = responseStopDetail.List.FirstOrDefault(it => it.FreezeStatu == "0")?.StopPayFlw;
                    }
                    else
                    {
                        transaction.FailReason = "止付失败并未查询到止付编号";
                        await channelWalletTransactionRepository.UpdateNowAsync(transaction);
                    }
                }
            }
            if (transaction.PingAnPay.FreezeNo.IsNotNull())
            {
                transaction.PingAnPay.ThirdVoucher = transaction.Code;
                await channelWalletTransactionRepository.UpdateNowAsync(transaction);
                var responsePayment = await utils.SingleApplicationSuspensionPayment(new SingleApplicationSuspensionPaymentRequest
                {
                    CcyCode = "RMB",
                    CnsmrSeqNo = transaction.Code,
                    FreezeNo = transaction.PingAnPay.FreezeNo,
                    ThirdVoucher = transaction.Code,
                    OutAcctName = wallet.Name,
                    OutAcctNo = wallet.Identity,
                    InAcctBankName = transaction.ReceiveBank,
                    InAcctName = transaction.ReceiveName,
                    InAcctNo = transaction.ReceiveAccount,
                    TranAmount = transaction.Amount.ToString(),
                    UseEx = transaction.Purpose,
                    UnionFlag = wallet.Bank == transaction.ReceiveBank ? "1" : "0",
                    AddrFlag = "1"
                });
                if (responsePayment.Code.IsNotNull())
                {
                    transaction.ErrorCode = responsePayment.Code;
                    transaction.FailReason = responsePayment.Errors?.FirstOrDefault()?.ErrorMessage ?? responsePayment.Message;
                    transaction.TransactionStatus = EnumWalletTransactionStatus.Fail;
                    await channelWalletTransactionRepository.UpdateNowAsync(transaction);
                }
                else
                {
                    await GetTransactionDetail(wallet, transaction);
                    if (transaction.TransactionStatus == EnumWalletTransactionStatus.Success)
                    {
                        await DownloadEreceiptUrl(wallet, transaction);
                    }
                }
            }
        }
        /// <summary>
        /// 查询交易记录
        /// </summary>
        /// <param name="wallet"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public async Task GetTransactionDetail(ChannelWallet wallet, ChannelWalletTransaction transaction)
        {
            var response = await utils.CorSingleTransferQuery(new CorSingleTransferQueryRequest
            {
                OrigThirdVoucher = transaction.Code,
            });
            if (response.Code.IsNotNull())
            {
                transaction.ErrorCode = response.Code;
                transaction.FailReason = response.Errors?.FirstOrDefault()?.ErrorMessage ?? response.Message;
                await channelWalletTransactionRepository.UpdateNowAsync(transaction);
            }
            else
            {
                response.Adapt(transaction.PingAnPay);
                transaction.TransDate = response.AccountDate.ToDateTime();
                transaction.OrderFee = response.Fee.ToDecimal();
                transaction.TransactionStatus = response.Stt == "20"
                        ? EnumWalletTransactionStatus.Success
                        : response.Stt == "30"
                        ? EnumWalletTransactionStatus.Fail
                        : EnumWalletTransactionStatus.Dealing;
                if (transaction.TransactionStatus == EnumWalletTransactionStatus.Fail)
                {
                    transaction.ErrorCode = response.Stt;
                    transaction.FailReason = response.BackRem;
                }
                else
                {
                    transaction.ErrorCode = null;
                    transaction.FailReason = null;
                }
                if (transaction.TransactionStatus == EnumWalletTransactionStatus.Success && transaction.TransDate == null)
                {
                    transaction.TransDate = DateTime.Now;
                }
                await channelWalletTransactionRepository.UpdateNowAsync(transaction);
                if (transaction.TransactionStatus != EnumWalletTransactionStatus.Dealing)
                {
                    var responseStop = await utils.StopPaymentAndSettlementAccounts(new StopPaymentAndSettlementAccountsRequest
                    {
                        CnsmrSeqNo = transaction.Code,
                        AccountNo = transaction.PayerAccount,
                        StopPayFlw = transaction.PingAnPay.FreezeNo,
                        OpType = "D",
                        CcyCode = "RMB",
                        SeqNo = $"{DateTime.Now:yyyyMMddHHmmssfff}{new Random(IDGen.NextID().GetHashCode()).Next(100, 999)}",
                        TradeDate = DateTime.Now.ToString("yyyyMMdd").ToInt()!.Value,
                        TradeTime = DateTime.Now.ToString("HHmmss").ToInt()!.Value,
                    });
                    if (responseStop.Code.IsNotNull())
                    {
                        transaction.PingAnPay.RemoveStopStt = "30";
                        transaction.PingAnPay.RemoveStopFailReason = responseStop.Errors?.FirstOrDefault()?.ErrorMessage ?? responseStop.Message;
                    }
                    else
                    {
                        transaction.PingAnPay.RemoveStopStt = responseStop.Stt;
                        transaction.PingAnPay.RemoveStopFailReason = responseStop.SttDesc;
                    }
                    await channelWalletTransactionRepository.UpdateNowAsync(transaction);
                }
            }
        }
        /// <summary>
        /// 下载电子收据
        /// </summary>
        /// <param name="wallet"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public async Task DownloadEreceiptUrl(ChannelWallet wallet, ChannelWalletTransaction transaction)
        {
            var response = await utils.SameDayHistoryReceiptDataQuery(new SameDayHistoryReceiptDataQueryRequest
            {
                OutAccNo = transaction.PayerAccount,
                AccountBeginDate = transaction.PingAnPay.AccountDate,
                AccountEndDate = transaction.PingAnPay.AccountDate,
                InAccNo = transaction.ReceiveAccount,
                HostFlow = transaction.PingAnPay.HostFlowNo
            });
            if (response.Code.IsNotNull())
            {
                transaction.EreceiptStatus = EnumWalletTransactionEreceiptStatus.FAIL;
                transaction.EreceiptErrorMessage = response.Errors?.FirstOrDefault()?.ErrorMessage ?? response.Message;
                await channelWalletTransactionRepository.UpdateNowAsync(transaction);
            }
            else if (response.List.IsNull())
            {
                transaction.EreceiptStatus = EnumWalletTransactionEreceiptStatus.FAIL;
                transaction.EreceiptErrorMessage = "未找到回单记录";
                await channelWalletTransactionRepository.UpdateNowAsync(transaction);
            }
            else
            {
                var responseDownload = await utils.SingleOrBatchReceiptPDFMergeDownloadNew(new SingleOrBatchReceiptPDFMergeDownloadNewRequest
                {
                    OutAccNo = transaction.PayerAccount,
                    List = response.List
                        .Select(it => new SingleOrBatchReceiptPDFMergeDownloadNewRequestItem
                        {
                            RecepitType = it.ReceiptType,
                            SeqNo = it.SeqNo,
                            AccountDate = it.AccountDate
                        })
                        .ToList()
                });
                if (responseDownload.Code.IsNotNull())
                {
                    transaction.EreceiptStatus = EnumWalletTransactionEreceiptStatus.FAIL;
                    transaction.EreceiptErrorMessage = responseDownload.Errors?.FirstOrDefault()?.ErrorMessage ?? responseDownload.Message;
                    await channelWalletTransactionRepository.UpdateNowAsync(transaction);
                }
                else
                {
                    transaction.EreceiptFileId = responseDownload.DocID;
                    transaction.EreceiptDownloadUrl = utils.DownloadFile(responseDownload.DocID, responseDownload.FileName);
                    transaction.EreceiptDownloadOssUrl = AliyunOSSUtils.Upload(
                        "PingAnPay",
                        new MemoryStream(File.ReadAllBytes(transaction.EreceiptDownloadUrl)),
                        $"电子回单-{transaction.Code}.zip")
                        .Url;
                    transaction.EreceiptStatus = EnumWalletTransactionEreceiptStatus.SUCCESS;
                    await channelWalletTransactionRepository.UpdateNowAsync(transaction);
                }
            }
        }
    }
}
ApiTools.Core/Services/ChannelWalletService.cs
New file
@@ -0,0 +1,109 @@
using Aop.Api.Domain;
using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Microsoft.EntityFrameworkCore;
using pingan.openbank.api.sdk.enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 渠道钱包服务
    /// </summary>
    /// <param name="channelWalletRepository"></param>
    /// <param name="channelPingAnPayWalletService"></param>
    public class ChannelWalletService(
            ChannelWalletRepository channelWalletRepository,
            ChannelPingAnPayWalletService channelPingAnPayWalletService
        ) :
        ITransient
    {
        private readonly ChannelWalletRepository channelWalletRepository = channelWalletRepository;
        private readonly ChannelPingAnPayWalletService channelPingAnPayWalletService = channelPingAnPayWalletService;
        public IChannelWalletService GetService(EnumWalletAccess access)
        {
            switch (access)
            {
                //case EnumWalletAccess.Alipay:
                //    return enterpriseAliPayWalletService;
                case EnumWalletAccess.PingAnPay:
                    return channelPingAnPayWalletService;
                //case EnumWalletAccess.WeChatPay:
                //    return enterpriseWeChatPayWalletService;
                default:
                    throw Oops.Oh(EnumErrorCodeType.s400, "支付通道不支持");
            }
        }
        /// <summary>
        /// 查询企业钱包余额
        /// </summary>
        /// <param name="outWalletId"></param>
        /// <returns></returns>
        public async Task<ChannelWallet> GetEnterpriseWallet(string outWalletId)
        {
            var logier = JwtUtils.GetCurrentLogier();
            var wallet = await channelWalletRepository.GetQueryable(false)
                .Where(it => it.ChannelId == logier.ChannelId && it.OutWalletId == outWalletId)
                .FirstOrDefaultAsync();
            return await GetService(wallet.Access).GetEnterpriseWalletBalance(wallet);
        }
        /// <summary>
        /// 查询企业钱包余额
        /// </summary>
        /// <param name="wallet"></param>
        /// <returns></returns>
        public async Task<ChannelWallet> GetEnterpriseWalletBalance(ChannelWallet wallet)
        {
            return await GetService(wallet.Access).GetEnterpriseWalletBalance(wallet);
        }
        /// <summary>
        /// 转账
        /// </summary>
        /// <param name="wallet"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public async Task Transfer(ChannelWallet wallet, ChannelWalletTransaction transaction)
        {
            await GetService(wallet.Access).Transfer(wallet, transaction);
        }
        /// <summary>
        /// 查询交易记录
        /// </summary>
        /// <param name="wallet"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public async Task GetTransactionDetail(ChannelWallet wallet, ChannelWalletTransaction transaction)
        {
            await GetService(wallet.Access).GetTransactionDetail(wallet, transaction);
        }
        /// <summary>
        /// 下载电子收据
        /// </summary>
        /// <param name="wallet"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public async Task DownloadEreceiptUrl(ChannelWallet wallet, ChannelWalletTransaction transaction)
        {
            if (transaction.TransactionStatus == EnumWalletTransactionStatus.Success)
            {
                await GetService(wallet.Access).DownloadEreceiptUrl(wallet, transaction);
            }
        }
        public string GetLockKey(Guid channelId, string outWalletId)
        {
            return $"EnterpriseWallet:{channelId}:{outWalletId}";
        }
    }
}
ApiTools.Core/Services/IChannelWalletService.cs
New file
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    /// <summary>
    /// 渠道钱包服务
    /// </summary>
    public interface IChannelWalletService
    {
        /// <summary>
        /// 查询渠道钱包余额
        /// </summary>
        /// <param name="wallet"></param>
        /// <returns></returns>
        Task<ChannelWallet> GetEnterpriseWalletBalance(ChannelWallet wallet);
        /// <summary>
        /// 转账
        /// </summary>
        /// <param name="wallet"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        Task Transfer(ChannelWallet wallet, ChannelWalletTransaction transaction);
        /// <summary>
        /// 查询交易记录
        /// </summary>
        /// <param name="wallet"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        Task GetTransactionDetail(ChannelWallet wallet, ChannelWalletTransaction transaction);
        /// <summary>
        /// 下载电子收据
        /// </summary>
        /// <param name="wallet"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        Task DownloadEreceiptUrl(ChannelWallet wallet, ChannelWalletTransaction transaction);
    }
}
ApiTools.Core/Utils/CollectionUtils/CollectionUtils.cs
@@ -1,4 +1,6 @@
using System;
using Furion.DatabaseAccessor;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
@@ -69,5 +71,28 @@
        {
            return !list.IsNull();
        }
        public static IQueryable<TEntity> GetQueryable<TEntity, TDbContextLocator>(this IRepository<TEntity, TDbContextLocator> rep, bool noTracking = true)
            where TEntity : class, IPrivateEntity, new()
            where TDbContextLocator : class, IDbContextLocator
        {
            var q = rep.AsQueryable();
            if (noTracking)
            {
                q = q.AsNoTracking();
            }
            return q;
        }
        public static IQueryable<TEntity> GetQueryable<TEntity>(this IRepository<TEntity> rep, bool noTracking = true)
            where TEntity : class, IPrivateEntity, new()
        {
            var q = rep.AsQueryable();
            if (noTracking)
            {
                q = q.AsNoTracking();
            }
            return q;
        }
    }
}
ApiTools.Core/Utils/DistributedCacheUtils/DistributedLock.cs
New file
@@ -0,0 +1,20 @@
using Medallion.Threading;
using Medallion.Threading.Redis;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    public static class DistributedLock
    {
        public static ValueTask<IDistributedSynchronizationHandle> TryAcquireAsync(
            this IDistributedLockProvider provider,
            string lockKey, TimeSpan timeout, CancellationToken cancellationToken = default)
        {
            lockKey = $"DistributedLock:{lockKey}";
            var @lock = provider.CreateLock(lockKey);
            return @lock.TryAcquireAsync(timeout, cancellationToken);
        }
    }
}
ApiTools.Core/Utils/DistributedCacheUtils/DistributedLockServiceComponent.cs
New file
@@ -0,0 +1,24 @@
using Furion;
using Medallion.Threading;
using Medallion.Threading.Redis;
using Microsoft.Extensions.DependencyInjection;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApiTools.Core
{
    public sealed class DistributedLockServiceComponent : IServiceComponent
    {
        public void Load(IServiceCollection services, ComponentContext componentContext)
        {
            var configuration = App.GetConfig<string>("DistributedCache:Configuration");
            var connection = ConnectionMultiplexer.Connect(configuration);
            var database = connection.GetDatabase();
            services.AddSingleton<IDistributedLockProvider>(it => new RedisDistributedSynchronizationProvider(database));
        }
    }
}
ApiTools.Core/Utils/PingAnPayUtils/Models/HistoryBalanceQueryRequest.cs
File was deleted
ApiTools.Core/Utils/PingAnPayUtils/Models/InquiryAccountDayHistoryTransactionDetailsRequest.cs
File was deleted
ApiTools.Core/Utils/PingAnPayUtils/Models/SingleDataQueryRequest.cs
File was deleted
ApiTools.Core/Utils/PingAnPayUtils/PingAnPayUtils.cs
@@ -51,26 +51,6 @@
        }
        /// <summary>
        /// 历史余额查询_银企直联
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<HistoryBalanceQueryResponse> HistoryBalanceQuery(HistoryBalanceQueryRequest request)
        {
            return await Send<HistoryBalanceQueryRequest, HistoryBalanceQueryResponse>(request, "/V1.0/bedl/HistoryBalanceQuery");
        }
        /// <summary>
        /// 查询账户当日历史交易明细_银企直联
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<InquiryAccountDayHistoryTransactionDetailsResponse> InquiryAccountDayHistoryTransactionDetails(InquiryAccountDayHistoryTransactionDetailsRequest request)
        {
            return await Send<InquiryAccountDayHistoryTransactionDetailsRequest, InquiryAccountDayHistoryTransactionDetailsResponse>(request, "/V1.0/bedl/InquiryAccountDayHistoryTransactionDetails");
        }
        /// <summary>
        /// 账户止付和解止付_银企直联 对公账户层的止付、解除止付
        /// </summary>
        /// <param name="request"></param>
@@ -108,16 +88,6 @@
        public async Task<CorSingleTransferQueryResponse> CorSingleTransferQuery(CorSingleTransferQueryRequest request)
        {
            return await Send<CorSingleTransferQueryRequest, CorSingleTransferQueryResponse>(request, "/V1.0/bedl/CorSingleTransferQuery");
        }
        /// <summary>
        /// 当日历史回单数据查询接口_银企直联
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<SingleDataQueryResponse> SingleDataQuery(SingleDataQueryRequest request)
        {
            return await Send<SingleDataQueryRequest, SingleDataQueryResponse>(request, "/V1.0/bedl/SingleDataQuery");
        }
        /// <summary>
ApiTools.Core/Utils/ScheduleUtils/DbJobPersistence.cs
@@ -16,21 +16,13 @@
    /// <summary>
    /// 作业持久化(数据库)
    /// </summary>
    public class DbJobPersistence : IJobPersistence, IDisposable
    public class DbJobPersistence : IJobPersistence
    {
        private readonly IServiceScope _serviceScope;
        private readonly IRepository<ScheduleJobDetail> repScheduleJobDetail;
        private readonly IRepository<ScheduleJobTrigger> repScheduleJobTrigger;
        private readonly IRepository<ScheduleJobTriggerTimeline, LogDbContextLocator> repScheduleJobTriggerTimeline;
        private readonly IServiceScopeFactory serviceScopeFactory;
        public DbJobPersistence(IServiceScopeFactory scopeFactory)
        public DbJobPersistence(IServiceScopeFactory serviceScopeFactory)
        {
            _serviceScope = scopeFactory.CreateScope();
            var services = _serviceScope.ServiceProvider;
            repScheduleJobDetail = services.GetService<IRepository<ScheduleJobDetail>>();
            repScheduleJobTrigger = services.GetService<IRepository<ScheduleJobTrigger>>();
            repScheduleJobTriggerTimeline = services.GetService<IRepository<ScheduleJobTriggerTimeline, LogDbContextLocator>>();
            this.serviceScopeFactory = serviceScopeFactory;
        }
        /// <summary>
@@ -44,78 +36,28 @@
        public Task<SchedulerBuilder> OnLoadingAsync(SchedulerBuilder builder, CancellationToken stoppingToken)
        {
            // 标记从其他地方更新,比如数据库
            return Task.FromResult(builder);
        }
        public async Task OnChangedAsync(PersistenceContext context)
        public Task OnChangedAsync(PersistenceContext context)
        {
            switch (context.Behavior)
            {
                case PersistenceBehavior.Appended:
                    var insertEntity = new ScheduleJobDetail();
                    context.JobDetail.Adapt(insertEntity);
                    await repScheduleJobDetail.InsertNowAsync(insertEntity);
                    break;
                case PersistenceBehavior.Updated:
                    var updateEntity = await repScheduleJobDetail.AsQueryable().FirstOrDefaultAsync(it => it.JobId == context.JobId);
                    if (updateEntity != null)
                    {
                        context.JobDetail.Adapt(updateEntity);
                        await repScheduleJobDetail.UpdateNowAsync(updateEntity);
                    }
                    break;
                case PersistenceBehavior.Removed:
                    var deleteEntity = await repScheduleJobDetail.AsQueryable().FirstOrDefaultAsync(it => it.JobId == context.JobId);
                    if (deleteEntity != null)
                    {
                        await repScheduleJobDetail.DeleteNowAsync(deleteEntity);
                    }
                    break;
                default:
                    break;
            }
            return Task.CompletedTask;
        }
        public async Task OnTriggerChangedAsync(PersistenceTriggerContext context)
        public Task OnTriggerChangedAsync(PersistenceTriggerContext context)
        {
            switch (context.Behavior)
            {
                case PersistenceBehavior.Appended:
                    var insertEntity = new ScheduleJobTrigger();
                    context.Trigger.Adapt(insertEntity);
                    await repScheduleJobTrigger.InsertNowAsync(insertEntity);
                    break;
                case PersistenceBehavior.Updated:
                    var updateEntity = await repScheduleJobTrigger.AsQueryable().FirstOrDefaultAsync(it => it.JobId == context.JobId && it.TriggerId == context.TriggerId);
                    if (updateEntity != null)
                    {
                        context.Trigger.Adapt(updateEntity);
                        await repScheduleJobTrigger.UpdateNowAsync(updateEntity);
                    }
                    break;
                case PersistenceBehavior.Removed:
                    var deleteEntity = await repScheduleJobTrigger.AsQueryable().FirstOrDefaultAsync(it => it.JobId == context.JobId && it.TriggerId == context.TriggerId);
                    if (deleteEntity != null)
                    {
                        await repScheduleJobTrigger.DeleteNowAsync(deleteEntity);
                    }
                    break;
                default:
                    break;
            }
            return Task.CompletedTask;
        }
        public async Task OnExecutionRecordAsync(PersistenceExecutionRecordContext context)
        {
            var entity = new ScheduleJobTriggerTimeline();
            context.Timeline.Adapt(entity);
            await repScheduleJobTriggerTimeline.InsertNowAsync(entity);
        }
        public void Dispose()
        {
            _serviceScope?.Dispose();
            using (var scope = serviceScopeFactory.CreateScope())
            {
                var rep = scope.ServiceProvider.GetRequiredService<IRepository<ScheduleJobTriggerTimeline, LogDbContextLocator>>();
                var entity = new ScheduleJobTriggerTimeline();
                context.Timeline.Adapt(entity);
                await rep.InsertNowAsync(entity);
            }
        }
    }
}
ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.Designer.cs
New file
@@ -0,0 +1,998 @@
// <auto-generated />
using System;
using ApiTools.EntityFramework.Core;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace ApiTools.Database.Migrations.Migrations
{
    [DbContext(typeof(DefaultDbContext))]
    [Migration("20251119014221_UpdateChannelWallet1119")]
    partial class UpdateChannelWallet1119
    {
        /// <inheritdoc />
        protected override void BuildTargetModel(ModelBuilder modelBuilder)
        {
#pragma warning disable 612, 618
            modelBuilder
                .HasAnnotation("ProductVersion", "9.0.2")
                .HasAnnotation("Relational:MaxIdentifierLength", 128);
            SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
            modelBuilder.Entity("ApiTools.Core.Channel", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Code")
                        .HasColumnType("nvarchar(max)");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<bool>("IsDisabled")
                        .HasColumnType("bit");
                    b.Property<string>("Name")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.HasKey("Id");
                    b.ToTable("Channel");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWallet", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<int>("Access")
                        .HasColumnType("int");
                    b.Property<decimal>("Balance")
                        .HasColumnType("decimal(18,2)");
                    b.Property<string>("Bank")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("BankBranch")
                        .HasColumnType("nvarchar(max)");
                    b.Property<Guid?>("ChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Code")
                        .HasColumnType("nvarchar(max)");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("ErrorCode")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("FailReason")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Identity")
                        .HasColumnType("nvarchar(max)");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<string>("Name")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("OutWalletId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("SignStatus")
                        .HasColumnType("int");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.HasKey("Id");
                    b.HasIndex("ChannelId");
                    b.ToTable("ChannelWallet");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWalletTransaction", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<decimal>("AfterBalance")
                        .HasColumnType("decimal(18,2)");
                    b.Property<decimal>("Amount")
                        .HasColumnType("decimal(18,2)");
                    b.Property<decimal>("Balance")
                        .HasColumnType("decimal(18,2)");
                    b.Property<string>("Code")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ConcurrencyLock")
                        .HasColumnType("nvarchar(450)");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Currency")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("EreceiptDownloadOssUrl")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("EreceiptDownloadUrl")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("EreceiptErrorMessage")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("EreceiptFileId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int?>("EreceiptStatus")
                        .HasColumnType("int");
                    b.Property<string>("ErrorCode")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("FailReason")
                        .HasColumnType("nvarchar(max)");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<DateTime?>("OperatorTime")
                        .HasColumnType("datetime2");
                    b.Property<decimal?>("OrderFee")
                        .HasColumnType("decimal(18,2)");
                    b.Property<string>("OutCode")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("OutOperatorId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("OutReceiveId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("PayerAccount")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("PayerBank")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("PayerBankBranch")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("PayerName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Purpose")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ReceiveAccount")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ReceiveBank")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ReceiveBankBranch")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ReceiveIdentity")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ReceiveName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Remark")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTime?>("TransDate")
                        .HasColumnType("datetime2");
                    b.Property<int>("TransactionStatus")
                        .HasColumnType("int");
                    b.Property<int>("Type")
                        .HasColumnType("int");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<Guid>("WalletId")
                        .HasColumnType("uniqueidentifier");
                    b.HasKey("Id");
                    b.HasIndex("ConcurrencyLock")
                        .IsUnique()
                        .HasFilter("[ConcurrencyLock] IS NOT NULL");
                    b.HasIndex("WalletId");
                    b.ToTable("ChannelWalletTransaction");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWalletTransactionPingAnPay", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("AccountDate")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("BackRem")
                        .HasColumnType("nvarchar(max)");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("CstInnerFlowNo")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Fee")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("FreezeNo")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("FrontLogNo")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("HostErrorCode")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("HostFlowNo")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("IsBack")
                        .HasColumnType("nvarchar(max)");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<string>("ProxyPayAcc")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ProxyPayBankName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ProxyPayName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("RemoveStopFailReason")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("RemoveStopStt")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<string>("StopFailReason")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("StopStt")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("SubmitTime")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("SysFlag")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ThirdVoucher")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("TransBsn")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Yhcljg")
                        .HasColumnType("nvarchar(max)");
                    b.HasKey("Id");
                    b.ToTable("ChannelWalletTransactionPingAnPay");
                });
            modelBuilder.Entity("ApiTools.Core.Resource", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("ActionName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ActionSummary")
                        .HasColumnType("nvarchar(max)");
                    b.Property<bool>("AllowAnonymous")
                        .HasColumnType("bit");
                    b.Property<string>("ApplicationName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Code")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ControllerName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ControllerSummary")
                        .HasColumnType("nvarchar(max)");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<bool>("CustomResponse")
                        .HasColumnType("bit");
                    b.Property<string>("DynamicAssemblyName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<bool>("FileUpload")
                        .HasColumnType("bit");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<bool>("IsExpired")
                        .HasColumnType("bit");
                    b.Property<bool>("IsFromForm")
                        .HasColumnType("bit");
                    b.Property<int>("Method")
                        .HasColumnType("int");
                    b.Property<string>("Name")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("RequestTypeFullName")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("RequestTypeName")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ResponseTypeFullName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ResponseTypeName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Route")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("RouteArea")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ServiceName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.HasKey("Id");
                    b.ToTable("Resource");
                });
            modelBuilder.Entity("ApiTools.Core.ScheduleJobDetail", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("AssemblyName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<bool>("Concurrent")
                        .HasColumnType("bit");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Description")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("GroupName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<bool>("IncludeAnnotations")
                        .HasColumnType("bit");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<string>("JobId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("JobType")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Properties")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.HasKey("Id");
                    b.ToTable("ScheduleJobDetail");
                });
            modelBuilder.Entity("ApiTools.Core.ScheduleJobTrigger", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Args")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("AssemblyName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Description")
                        .HasColumnType("nvarchar(max)");
                    b.Property<long>("ElapsedTime")
                        .HasColumnType("bigint");
                    b.Property<DateTime?>("EndTime")
                        .HasColumnType("datetime2");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<string>("JobId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTime?>("LastRunTime")
                        .HasColumnType("datetime2");
                    b.Property<long>("MaxNumberOfErrors")
                        .HasColumnType("bigint");
                    b.Property<long>("MaxNumberOfRuns")
                        .HasColumnType("bigint");
                    b.Property<DateTime?>("NextRunTime")
                        .HasColumnType("datetime2");
                    b.Property<long>("NumRetries")
                        .HasColumnType("bigint");
                    b.Property<long>("NumberOfErrors")
                        .HasColumnType("bigint");
                    b.Property<long>("NumberOfRuns")
                        .HasColumnType("bigint");
                    b.Property<bool>("ResetOnlyOnce")
                        .HasColumnType("bit");
                    b.Property<string>("Result")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("RetryTimeout")
                        .HasColumnType("int");
                    b.Property<bool>("RunOnStart")
                        .HasColumnType("bit");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<bool>("StartNow")
                        .HasColumnType("bit");
                    b.Property<DateTime?>("StartTime")
                        .HasColumnType("datetime2");
                    b.Property<long>("Status")
                        .HasColumnType("bigint");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("TriggerId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("TriggerType")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.HasKey("Id");
                    b.ToTable("ScheduleJobTrigger");
                });
            modelBuilder.Entity("ApiTools.Core.SmsLog", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<int>("Access")
                        .HasColumnType("int");
                    b.Property<Guid?>("ChannelCreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<Guid?>("ChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Code")
                        .HasColumnType("nvarchar(max)");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTime?>("Expiry")
                        .HasColumnType("datetime2");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<bool>("IsUsed")
                        .HasColumnType("bit");
                    b.Property<string>("Message")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("PhoneNumber")
                        .IsRequired()
                        .HasMaxLength(11)
                        .HasColumnType("nvarchar(11)");
                    b.Property<string>("RequestId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<int>("Status")
                        .HasColumnType("int");
                    b.Property<string>("TemplateCode")
                        .IsRequired()
                        .HasMaxLength(128)
                        .HasColumnType("nvarchar(128)");
                    b.Property<string>("TemplateParam")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.HasKey("Id");
                    b.HasIndex("ChannelId");
                    b.ToTable("SmsLog");
                });
            modelBuilder.Entity("ApiTools.Core.SmsSetting", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<Guid?>("ChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<int>("DailyMaxCount")
                        .HasColumnType("int");
                    b.Property<int>("HourlyMaxCount")
                        .HasColumnType("int");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<bool>("IsDisabled")
                        .HasColumnType("bit");
                    b.Property<int>("MinutelyMaxCount")
                        .HasColumnType("int");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<bool>("WithoutParams")
                        .HasColumnType("bit");
                    b.HasKey("Id");
                    b.HasIndex("ChannelId");
                    b.ToTable("SmsSetting");
                });
            modelBuilder.Entity("ApiTools.Core.SmsSettingAccess", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<int>("Access")
                        .HasColumnType("int");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<bool>("IsDisabled")
                        .HasColumnType("bit");
                    b.Property<Guid>("SettingId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("SignName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.HasKey("Id");
                    b.HasIndex("SettingId");
                    b.ToTable("SmsSettingAccess");
                });
            modelBuilder.Entity("ApiTools.Core.User", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Avatar")
                        .HasColumnType("nvarchar(max)");
                    b.Property<Guid?>("ChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<bool>("IsCheckPhoneNumber")
                        .HasColumnType("bit");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<int>("Level")
                        .HasColumnType("int");
                    b.Property<string>("Name")
                        .HasMaxLength(32)
                        .HasColumnType("nvarchar(32)");
                    b.Property<string>("Password")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("PhoneNumber")
                        .HasMaxLength(11)
                        .HasColumnType("nvarchar(11)");
                    b.Property<string>("Remark")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<int>("Status")
                        .HasColumnType("int");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("Type")
                        .HasColumnType("int");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("UserName")
                        .IsRequired()
                        .HasMaxLength(32)
                        .HasColumnType("nvarchar(32)");
                    b.HasKey("Id");
                    b.HasIndex("ChannelId");
                    b.ToTable("User");
                    b.HasData(
                        new
                        {
                            Id = new Guid("11111111-1111-1111-1111-111111111111"),
                            CreatedTime = new DateTimeOffset(new DateTime(2000, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 8, 0, 0, 0)),
                            IsCheckPhoneNumber = false,
                            IsDeleted = false,
                            Level = 999,
                            Name = "管理员",
                            Password = "iEYggKrMhQ3ASUGLobra1w==:fn/DsMJUbD9FGpvBvR3moMpMPptdxzZlourPVhU479I=",
                            Sort = 0,
                            Status = 10,
                            Type = 100,
                            UserName = "system"
                        });
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWallet", b =>
                {
                    b.HasOne("ApiTools.Core.Channel", "Channel")
                        .WithMany()
                        .HasForeignKey("ChannelId");
                    b.Navigation("Channel");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWalletTransaction", b =>
                {
                    b.HasOne("ApiTools.Core.ChannelWallet", "Wallet")
                        .WithMany()
                        .HasForeignKey("WalletId")
                        .OnDelete(DeleteBehavior.Cascade)
                        .IsRequired();
                    b.Navigation("Wallet");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWalletTransactionPingAnPay", b =>
                {
                    b.HasOne("ApiTools.Core.ChannelWalletTransaction", "Transaction")
                        .WithOne("PingAnPay")
                        .HasForeignKey("ApiTools.Core.ChannelWalletTransactionPingAnPay", "Id")
                        .OnDelete(DeleteBehavior.Cascade)
                        .IsRequired();
                    b.Navigation("Transaction");
                });
            modelBuilder.Entity("ApiTools.Core.SmsLog", b =>
                {
                    b.HasOne("ApiTools.Core.Channel", "Channel")
                        .WithMany()
                        .HasForeignKey("ChannelId");
                    b.Navigation("Channel");
                });
            modelBuilder.Entity("ApiTools.Core.SmsSetting", b =>
                {
                    b.HasOne("ApiTools.Core.Channel", "Channel")
                        .WithMany()
                        .HasForeignKey("ChannelId");
                    b.Navigation("Channel");
                });
            modelBuilder.Entity("ApiTools.Core.SmsSettingAccess", b =>
                {
                    b.HasOne("ApiTools.Core.SmsSetting", "Setting")
                        .WithMany("Accesses")
                        .HasForeignKey("SettingId")
                        .OnDelete(DeleteBehavior.Cascade)
                        .IsRequired();
                    b.Navigation("Setting");
                });
            modelBuilder.Entity("ApiTools.Core.User", b =>
                {
                    b.HasOne("ApiTools.Core.Channel", "Channel")
                        .WithMany()
                        .HasForeignKey("ChannelId");
                    b.Navigation("Channel");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWalletTransaction", b =>
                {
                    b.Navigation("PingAnPay");
                });
            modelBuilder.Entity("ApiTools.Core.SmsSetting", b =>
                {
                    b.Navigation("Accesses");
                });
#pragma warning restore 612, 618
        }
    }
}
ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.cs
New file
@@ -0,0 +1,185 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ApiTools.Database.Migrations.Migrations
{
    /// <inheritdoc />
    public partial class UpdateChannelWallet1119 : Migration
    {
        /// <inheritdoc />
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "ChannelWallet",
                columns: table => new
                {
                    Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
                    ChannelId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                    OutWalletId = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Access = table.Column<int>(type: "int", nullable: false),
                    Code = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Bank = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    BankBranch = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Name = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Identity = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Balance = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
                    SignStatus = table.Column<int>(type: "int", nullable: false),
                    ErrorCode = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    FailReason = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Sort = table.Column<int>(type: "int", nullable: false),
                    TraceId = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    CreatedTime = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: false),
                    CreatedUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                    CreatedChannelId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                    UpdatedTime = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true),
                    UpdatedUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                    IsDeleted = table.Column<bool>(type: "bit", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_ChannelWallet", x => x.Id);
                    table.ForeignKey(
                        name: "FK_ChannelWallet_Channel_ChannelId",
                        column: x => x.ChannelId,
                        principalTable: "Channel",
                        principalColumn: "Id");
                });
            migrationBuilder.CreateTable(
                name: "ChannelWalletTransaction",
                columns: table => new
                {
                    Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
                    WalletId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
                    Type = table.Column<int>(type: "int", nullable: false),
                    Code = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    OutCode = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ConcurrencyLock = table.Column<string>(type: "nvarchar(450)", nullable: true),
                    Amount = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
                    Balance = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
                    AfterBalance = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
                    OutOperatorId = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    OperatorTime = table.Column<DateTime>(type: "datetime2", nullable: true),
                    PayerAccount = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    PayerName = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    PayerBank = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    PayerBankBranch = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    OutReceiveId = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReceiveName = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReceiveIdentity = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReceiveAccount = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReceiveBank = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ReceiveBankBranch = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Currency = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Purpose = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Remark = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ErrorCode = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    FailReason = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    TransDate = table.Column<DateTime>(type: "datetime2", nullable: true),
                    OrderFee = table.Column<decimal>(type: "decimal(18,2)", nullable: true),
                    EreceiptFileId = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    EreceiptDownloadUrl = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    EreceiptDownloadOssUrl = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    EreceiptStatus = table.Column<int>(type: "int", nullable: true),
                    EreceiptErrorMessage = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    TransactionStatus = table.Column<int>(type: "int", nullable: false),
                    Sort = table.Column<int>(type: "int", nullable: false),
                    TraceId = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    CreatedTime = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: false),
                    CreatedUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                    CreatedChannelId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                    UpdatedTime = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true),
                    UpdatedUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                    IsDeleted = table.Column<bool>(type: "bit", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_ChannelWalletTransaction", x => x.Id);
                    table.ForeignKey(
                        name: "FK_ChannelWalletTransaction_ChannelWallet_WalletId",
                        column: x => x.WalletId,
                        principalTable: "ChannelWallet",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                });
            migrationBuilder.CreateTable(
                name: "ChannelWalletTransactionPingAnPay",
                columns: table => new
                {
                    Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
                    FreezeNo = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    StopStt = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    StopFailReason = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    RemoveStopStt = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    RemoveStopFailReason = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ThirdVoucher = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    FrontLogNo = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    CstInnerFlowNo = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    IsBack = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    BackRem = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Yhcljg = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    SysFlag = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Fee = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    TransBsn = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    SubmitTime = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    AccountDate = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    HostFlowNo = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    HostErrorCode = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ProxyPayName = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ProxyPayAcc = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    ProxyPayBankName = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    Sort = table.Column<int>(type: "int", nullable: false),
                    TraceId = table.Column<string>(type: "nvarchar(max)", nullable: true),
                    CreatedTime = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: false),
                    CreatedUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                    CreatedChannelId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                    UpdatedTime = table.Column<DateTimeOffset>(type: "datetimeoffset", nullable: true),
                    UpdatedUserId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
                    IsDeleted = table.Column<bool>(type: "bit", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_ChannelWalletTransactionPingAnPay", x => x.Id);
                    table.ForeignKey(
                        name: "FK_ChannelWalletTransactionPingAnPay_ChannelWalletTransaction_Id",
                        column: x => x.Id,
                        principalTable: "ChannelWalletTransaction",
                        principalColumn: "Id",
                        onDelete: ReferentialAction.Cascade);
                });
            migrationBuilder.CreateIndex(
                name: "IX_ChannelWallet_ChannelId",
                table: "ChannelWallet",
                column: "ChannelId");
            migrationBuilder.CreateIndex(
                name: "IX_ChannelWalletTransaction_ConcurrencyLock",
                table: "ChannelWalletTransaction",
                column: "ConcurrencyLock",
                unique: true,
                filter: "[ConcurrencyLock] IS NOT NULL");
            migrationBuilder.CreateIndex(
                name: "IX_ChannelWalletTransaction_WalletId",
                table: "ChannelWalletTransaction",
                column: "WalletId");
        }
        /// <inheritdoc />
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "ChannelWalletTransactionPingAnPay");
            migrationBuilder.DropTable(
                name: "ChannelWalletTransaction");
            migrationBuilder.DropTable(
                name: "ChannelWallet");
        }
    }
}
ApiTools.Database.Migrations/Migrations/DefaultDbContextModelSnapshot.cs
@@ -66,6 +66,317 @@
                    b.ToTable("Channel");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWallet", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<int>("Access")
                        .HasColumnType("int");
                    b.Property<decimal>("Balance")
                        .HasColumnType("decimal(18,2)");
                    b.Property<string>("Bank")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("BankBranch")
                        .HasColumnType("nvarchar(max)");
                    b.Property<Guid?>("ChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Code")
                        .HasColumnType("nvarchar(max)");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("ErrorCode")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("FailReason")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Identity")
                        .HasColumnType("nvarchar(max)");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<string>("Name")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("OutWalletId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("SignStatus")
                        .HasColumnType("int");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.HasKey("Id");
                    b.HasIndex("ChannelId");
                    b.ToTable("ChannelWallet");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWalletTransaction", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<decimal>("AfterBalance")
                        .HasColumnType("decimal(18,2)");
                    b.Property<decimal>("Amount")
                        .HasColumnType("decimal(18,2)");
                    b.Property<decimal>("Balance")
                        .HasColumnType("decimal(18,2)");
                    b.Property<string>("Code")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ConcurrencyLock")
                        .HasColumnType("nvarchar(450)");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Currency")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("EreceiptDownloadOssUrl")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("EreceiptDownloadUrl")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("EreceiptErrorMessage")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("EreceiptFileId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int?>("EreceiptStatus")
                        .HasColumnType("int");
                    b.Property<string>("ErrorCode")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("FailReason")
                        .HasColumnType("nvarchar(max)");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<DateTime?>("OperatorTime")
                        .HasColumnType("datetime2");
                    b.Property<decimal?>("OrderFee")
                        .HasColumnType("decimal(18,2)");
                    b.Property<string>("OutCode")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("OutOperatorId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("OutReceiveId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("PayerAccount")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("PayerBank")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("PayerBankBranch")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("PayerName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Purpose")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ReceiveAccount")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ReceiveBank")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ReceiveBankBranch")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ReceiveIdentity")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ReceiveName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Remark")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTime?>("TransDate")
                        .HasColumnType("datetime2");
                    b.Property<int>("TransactionStatus")
                        .HasColumnType("int");
                    b.Property<int>("Type")
                        .HasColumnType("int");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<Guid>("WalletId")
                        .HasColumnType("uniqueidentifier");
                    b.HasKey("Id");
                    b.HasIndex("ConcurrencyLock")
                        .IsUnique()
                        .HasFilter("[ConcurrencyLock] IS NOT NULL");
                    b.HasIndex("WalletId");
                    b.ToTable("ChannelWalletTransaction");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWalletTransactionPingAnPay", b =>
                {
                    b.Property<Guid>("Id")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("AccountDate")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("BackRem")
                        .HasColumnType("nvarchar(max)");
                    b.Property<Guid?>("CreatedChannelId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<DateTimeOffset>("CreatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("CreatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("CstInnerFlowNo")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Fee")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("FreezeNo")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("FrontLogNo")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("HostErrorCode")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("HostFlowNo")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("IsBack")
                        .HasColumnType("nvarchar(max)");
                    b.Property<bool>("IsDeleted")
                        .HasColumnType("bit");
                    b.Property<string>("ProxyPayAcc")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ProxyPayBankName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ProxyPayName")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("RemoveStopFailReason")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("RemoveStopStt")
                        .HasColumnType("nvarchar(max)");
                    b.Property<int>("Sort")
                        .HasColumnType("int");
                    b.Property<string>("StopFailReason")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("StopStt")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("SubmitTime")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("SysFlag")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("ThirdVoucher")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("TraceId")
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("TransBsn")
                        .HasColumnType("nvarchar(max)");
                    b.Property<DateTimeOffset?>("UpdatedTime")
                        .HasColumnType("datetimeoffset");
                    b.Property<Guid?>("UpdatedUserId")
                        .HasColumnType("uniqueidentifier");
                    b.Property<string>("Yhcljg")
                        .HasColumnType("nvarchar(max)");
                    b.HasKey("Id");
                    b.ToTable("ChannelWalletTransactionPingAnPay");
                });
            modelBuilder.Entity("ApiTools.Core.Resource", b =>
                {
                    b.Property<Guid>("Id")
@@ -600,6 +911,37 @@
                        });
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWallet", b =>
                {
                    b.HasOne("ApiTools.Core.Channel", "Channel")
                        .WithMany()
                        .HasForeignKey("ChannelId");
                    b.Navigation("Channel");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWalletTransaction", b =>
                {
                    b.HasOne("ApiTools.Core.ChannelWallet", "Wallet")
                        .WithMany()
                        .HasForeignKey("WalletId")
                        .OnDelete(DeleteBehavior.Cascade)
                        .IsRequired();
                    b.Navigation("Wallet");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWalletTransactionPingAnPay", b =>
                {
                    b.HasOne("ApiTools.Core.ChannelWalletTransaction", "Transaction")
                        .WithOne("PingAnPay")
                        .HasForeignKey("ApiTools.Core.ChannelWalletTransactionPingAnPay", "Id")
                        .OnDelete(DeleteBehavior.Cascade)
                        .IsRequired();
                    b.Navigation("Transaction");
                });
            modelBuilder.Entity("ApiTools.Core.SmsLog", b =>
                {
                    b.HasOne("ApiTools.Core.Channel", "Channel")
@@ -638,6 +980,11 @@
                    b.Navigation("Channel");
                });
            modelBuilder.Entity("ApiTools.Core.ChannelWalletTransaction", b =>
                {
                    b.Navigation("PingAnPay");
                });
            modelBuilder.Entity("ApiTools.Core.SmsSetting", b =>
                {
                    b.Navigation("Accesses");
ApiTools.Database.Migrations/REDEME.MD
@@ -1,7 +1,7 @@
-------------------------------主数据库---------------------------------------
新增迁移文件
dotnet ef migrations add UpdateSmsSetting1009 -s "../ApiTools.Web.Entry" -c DefaultDbContext
dotnet ef migrations add UpdateChannelWallet1119 -s "../ApiTools.Web.Entry" -c DefaultDbContext
删除迁移文件
dotnet ef migrations remove -s "../ApiTools.Web.Entry" -c DefaultDbContext
ApiTools.Web.Entry/ApiTools.Web.Entry.csproj
@@ -21,6 +21,13 @@
      <ProjectReference Include="..\ApiTools.Application\ApiTools.Application.csproj" />
      <ProjectReference Include="..\ApiTools.Database.Migrations\ApiTools.Database.Migrations.csproj" />
    </ItemGroup>
    <ItemGroup>
      <None Update="PingAnPayCert\config.properties">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </None>
    </ItemGroup>
    <ProjectExtensions>
        <VisualStudio>
            <UserProperties properties_4launchsettings_1json__JsonSchema="" />
ApiTools.Web.Entry/PingAnPayCert/config.properties
New file
@@ -0,0 +1,8 @@
appId=22c4781c85
publicKey=0480E866C61C385C2916901CFC10AA53DFD89DBFFA87A4A49C26F82C66F30B7A7038D61FDBE08236F6ACFA6216A6FBCC511841586ABE24107438E049BE98C4660C
appPrivateKey=7051c204b10e5380859d8e38c3061fbe2d309c4cac1b89f0c331690d291fb18b
baseUrl=https://my-st1.orangebank.com.cn:567/fat7/openapi/gateway/
fileUploadUrl=https://my-st1.orangebank.com.cn:567/fat7/openapi/file//boapFile/upload
fileDownLoadUrl=https://my-st1.orangebank.com.cn:567/fat7/openapi/file//boapFile/download
signMethod=SM2
appSecret=73W620
ApiTools.Web.Entry/Startup.cs
@@ -39,6 +39,7 @@
            services.AddComponent<EventBusServiceComponent>();
            services.AddComponent<DistributedCacheServiceComponent>();
            services.AddComponent<DistributedLockServiceComponent>();
            services.AddHttpRemote(); 
            services.AddSingleton<AlipayUtils>();
@@ -59,7 +60,7 @@
            {
                options.BuildSqlType = SqlTypes.SqlServer;
                options.JobDetail.LogEnabled = true;
                //options.AddPersistence<DbJobPersistence>();
                options.AddPersistence<DbJobPersistence>();
            });
            services.AddSpecificationDocuments(options =>