From 1d03ddefc1b5458eede592d5b5780c3c2b10dfca Mon Sep 17 00:00:00 2001
From: lijin <17408817@qq.com>
Date: 星期四, 20 十一月 2025 09:05:16 +0800
Subject: [PATCH] Merge branch 'dev-818-3.4.2.12' of http://120.26.58.240:8888/r/ApiTools into dev-818-3.4.2.12

---
 ApiTools.Core/Services/ChannelPingAnPayWalletService.cs                                    |   13 
 ApiTools.Web.Entry/Startup.cs                                                              |    2 
 ApiTools.Database.Migrations/Migrations/DefaultDbContextModelSnapshot.cs                   |  347 ++++++++++
 ApiTools.Core/Models/ChannelWallets/Queries/GetChannelPingAnPayWalletQuery.cs              |   53 +
 ApiTools.Application/ChannelWallets/Commands/ChannelWalletCommandHandler.cs                |   16 
 ApiTools.Database.Migrations/REDEME.MD                                                     |    2 
 ApiTools.Core/Utils/ScheduleUtils/DbJobPersistence.cs                                      |   88 --
 ApiTools.Application/ChannelWallets/Queries/ChannelWalletQueryHandler.cs                   |   21 
 ApiTools.Core/Jobs/RefreshChannelWalletTransactionStatusJob.cs                             |   58 +
 ApiTools.Core/Models/ChannelWallets/Commands/SaveChannelPingAnPayWalletCommand.cs          |   22 
 ApiTools.Application/ApiTools.Application.xml                                              |   18 
 ApiTools.Web.Entry/PingAnPayCert/config.properties                                         |    8 
 ApiTools.Core/ApiTools.Core.xml                                                            |   67 +
 ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.Designer.cs |  998 +++++++++++++++++++++++++++++++
 ApiTools.Web.Entry/ApiTools.Web.Entry.csproj                                               |    7 
 ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.cs          |  185 +++++
 16 files changed, 1,780 insertions(+), 125 deletions(-)

diff --git a/ApiTools.Application/ApiTools.Application.xml b/ApiTools.Application/ApiTools.Application.xml
index 73862f3..e70123c 100644
--- a/ApiTools.Application/ApiTools.Application.xml
+++ b/ApiTools.Application/ApiTools.Application.xml
@@ -149,6 +149,14 @@
             <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>
             鎻愪氦娓犻亾閽卞寘杞处
@@ -162,11 +170,19 @@
             鏌ヨ娓犻亾閽卞寘浜ゆ槗璇︽儏
             </summary>
         </member>
-        <member name="M:ApiTools.Application.ChannelWalletQueryHandler.#ctor(ApiTools.Core.ChannelWalletTransactionRepository)">
+        <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>
             鏌ヨ娓犻亾閽卞寘浜ゆ槗璇︽儏
diff --git a/ApiTools.Application/ChannelWallets/Commands/ChannelWalletCommandHandler.cs b/ApiTools.Application/ChannelWallets/Commands/ChannelWalletCommandHandler.cs
index 3feb977..0fd2503 100644
--- a/ApiTools.Application/ChannelWallets/Commands/ChannelWalletCommandHandler.cs
+++ b/ApiTools.Application/ChannelWallets/Commands/ChannelWalletCommandHandler.cs
@@ -29,6 +29,12 @@
         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();
@@ -40,23 +46,23 @@
                 wallet = new ChannelWallet();
                 wallet.ChannelId = logier.ChannelId;
                 wallet.Access = EnumWalletAccess.PingAnPay;
-                wallet.SignStatus = EnumWalletSignStatus.Normal;
+                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
             {
-                WalletId = wallet.Id,
+                Id = wallet.Id,
                 Balance = wallet.Balance,
-                ErrorCode = wallet.ErrorCode,
-                FailReason = wallet.FailReason
             };
         }
 
@@ -80,7 +86,7 @@
                 .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, "浣欓涓嶈冻");
 
diff --git a/ApiTools.Application/ChannelWallets/Queries/ChannelWalletQueryHandler.cs b/ApiTools.Application/ChannelWallets/Queries/ChannelWalletQueryHandler.cs
index cbc93a4..59fa35e 100644
--- a/ApiTools.Application/ChannelWallets/Queries/ChannelWalletQueryHandler.cs
+++ b/ApiTools.Application/ChannelWallets/Queries/ChannelWalletQueryHandler.cs
@@ -14,11 +14,28 @@
     /// 鏌ヨ娓犻亾閽卞寘浜ゆ槗璇︽儏
     /// </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>
         /// 鏌ヨ娓犻亾閽卞寘浜ゆ槗璇︽儏
@@ -28,11 +45,11 @@
         /// <returns></returns>
         public async Task<GetChannelWalletTransactionQueryResult> Handle(GetChannelWalletTransactionQuery request, CancellationToken cancellationToken)
         {
-            var logier = JwtUtils.GetCurrentLogier();
             return await channelWalletTransactionRepository.GetQueryable()
-                .Where(it => it.Wallet.ChannelId == logier.ChannelId && it.OutCode == request.OutCode)
+                .Where(it => it.OutCode == request.OutCode)
                 .ProjectToType<GetChannelWalletTransactionQueryResult>()
                 .FirstOrDefaultAsync();
         }
+
     }
 }
diff --git a/ApiTools.Core/ApiTools.Core.xml b/ApiTools.Core/ApiTools.Core.xml
index a13d011..fd5b1e2 100644
--- a/ApiTools.Core/ApiTools.Core.xml
+++ b/ApiTools.Core/ApiTools.Core.xml
@@ -2003,6 +2003,16 @@
             缂栧彿
             </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">
             <summary>
             鏇存崲鎵嬫満鍙�
@@ -2283,16 +2293,6 @@
             澶栭儴閽卞寘Id
             </summary>
         </member>
-        <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommand.Bank">
-            <summary>
-            鎵�灞為摱琛�
-            </summary>
-        </member>
-        <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommand.BankBranch">
-            <summary>
-            鎵�灞炴敮琛�
-            </summary>
-        </member>
         <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommand.Name">
             <summary>
             鎴峰悕
@@ -2303,7 +2303,7 @@
             璐﹀彿
             </summary>
         </member>
-        <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommandResult.WalletId">
+        <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommandResult.Id">
             <summary>
             閽卞寘Id
             </summary>
@@ -2311,16 +2311,6 @@
         <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommandResult.Balance">
             <summary>
             浣欓
-            </summary>
-        </member>
-        <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommandResult.ErrorCode">
-            <summary>
-            閿欒浠g爜
-            </summary>
-        </member>
-        <member name="P:ApiTools.Core.SaveChannelPingAnPayWalletCommandResult.FailReason">
-            <summary>
-            杩斿洖鍏蜂綋鐨勫師鍥犮��
             </summary>
         </member>
         <member name="T:ApiTools.Core.SubmitChannelWalletTransferCommand">
@@ -2423,6 +2413,41 @@
             鏌ヨ鍒扮殑璁㈠崟鐘舵�佷负FAIL澶辫触鎴朢EFUND閫�绁ㄦ椂锛岃繑鍥炲叿浣撶殑鍘熷洜銆�
             </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>
             鏌ヨ娓犻亾閽卞寘浜ゆ槗璇︽儏
diff --git a/ApiTools.Core/Jobs/RefreshChannelWalletTransactionStatusJob.cs b/ApiTools.Core/Jobs/RefreshChannelWalletTransactionStatusJob.cs
new file mode 100644
index 0000000..c92df86
--- /dev/null
+++ b/ApiTools.Core/Jobs/RefreshChannelWalletTransactionStatusJob.cs
@@ -0,0 +1,58 @@
+锘縰sing 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);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/ApiTools.Core/Models/ChannelWallets/Commands/SaveChannelPingAnPayWalletCommand.cs b/ApiTools.Core/Models/ChannelWallets/Commands/SaveChannelPingAnPayWalletCommand.cs
index a2a82c2..bc740c5 100644
--- a/ApiTools.Core/Models/ChannelWallets/Commands/SaveChannelPingAnPayWalletCommand.cs
+++ b/ApiTools.Core/Models/ChannelWallets/Commands/SaveChannelPingAnPayWalletCommand.cs
@@ -19,16 +19,6 @@
         public string OutWalletId { get; set; }
 
         /// <summary>
-        /// 鎵�灞為摱琛�
-        /// </summary>
-        public string Bank { get; set; }
-
-        /// <summary>
-        /// 鎵�灞炴敮琛�
-        /// </summary>
-        public string BankBranch { get; set; }
-
-        /// <summary>
         /// 鎴峰悕
         /// </summary>
         public string Name { get; set; }
@@ -45,21 +35,11 @@
         /// <summary>
         /// 閽卞寘Id
         /// </summary>
-        public Guid WalletId { get; set; }
+        public Guid Id { get; set; }
 
         /// <summary>
         /// 浣欓
         /// </summary>
         public decimal Balance { get; set; }
-
-        /// <summary>
-        /// 閿欒浠g爜
-        /// </summary>
-        public string ErrorCode { get; set; }
-
-        /// <summary>
-        /// 杩斿洖鍏蜂綋鐨勫師鍥犮��
-        /// </summary>
-        public string FailReason { get; set; }
     }
 }
diff --git a/ApiTools.Core/Models/ChannelWallets/Queries/GetChannelPingAnPayWalletQuery.cs b/ApiTools.Core/Models/ChannelWallets/Queries/GetChannelPingAnPayWalletQuery.cs
new file mode 100644
index 0000000..bf77529
--- /dev/null
+++ b/ApiTools.Core/Models/ChannelWallets/Queries/GetChannelPingAnPayWalletQuery.cs
@@ -0,0 +1,53 @@
+锘縰sing 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; }
+
+    }
+}
diff --git a/ApiTools.Core/Services/ChannelPingAnPayWalletService.cs b/ApiTools.Core/Services/ChannelPingAnPayWalletService.cs
index e49da82..628ecc6 100644
--- a/ApiTools.Core/Services/ChannelPingAnPayWalletService.cs
+++ b/ApiTools.Core/Services/ChannelPingAnPayWalletService.cs
@@ -52,6 +52,9 @@
                 }
                 else
                 {
+                    wallet.ErrorCode = null;
+                    wallet.FailReason = null;
+                    wallet.SignStatus = EnumWalletSignStatus.Normal;
                     wallet.Balance = response.AcctBalance.ToDecimal().Value;
                 }
             }
@@ -184,6 +187,16 @@
                         : 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;
diff --git a/ApiTools.Core/Utils/ScheduleUtils/DbJobPersistence.cs b/ApiTools.Core/Utils/ScheduleUtils/DbJobPersistence.cs
index b637fb8..7d8de22 100644
--- a/ApiTools.Core/Utils/ScheduleUtils/DbJobPersistence.cs
+++ b/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);
+            }
         }
     }
 }
diff --git a/ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.Designer.cs b/ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.Designer.cs
new file mode 100644
index 0000000..827c8aa
--- /dev/null
+++ b/ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.Designer.cs
@@ -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
+        }
+    }
+}
diff --git a/ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.cs b/ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.cs
new file mode 100644
index 0000000..baef442
--- /dev/null
+++ b/ApiTools.Database.Migrations/Migrations/20251119014221_UpdateChannelWallet1119.cs
@@ -0,0 +1,185 @@
+锘縰sing 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");
+        }
+    }
+}
diff --git a/ApiTools.Database.Migrations/Migrations/DefaultDbContextModelSnapshot.cs b/ApiTools.Database.Migrations/Migrations/DefaultDbContextModelSnapshot.cs
index 09924a7..de7c9c6 100644
--- a/ApiTools.Database.Migrations/Migrations/DefaultDbContextModelSnapshot.cs
+++ b/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");
diff --git a/ApiTools.Database.Migrations/REDEME.MD b/ApiTools.Database.Migrations/REDEME.MD
index c9a0fa9..1f6848e 100644
--- a/ApiTools.Database.Migrations/REDEME.MD
+++ b/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
diff --git a/ApiTools.Web.Entry/ApiTools.Web.Entry.csproj b/ApiTools.Web.Entry/ApiTools.Web.Entry.csproj
index 617bd5a..b7ace61 100644
--- a/ApiTools.Web.Entry/ApiTools.Web.Entry.csproj
+++ b/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="" />
diff --git a/ApiTools.Web.Entry/PingAnPayCert/config.properties b/ApiTools.Web.Entry/PingAnPayCert/config.properties
new file mode 100644
index 0000000..17a8514
--- /dev/null
+++ b/ApiTools.Web.Entry/PingAnPayCert/config.properties
@@ -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
diff --git a/ApiTools.Web.Entry/Startup.cs b/ApiTools.Web.Entry/Startup.cs
index 9c78c1b..0a4ec9c 100644
--- a/ApiTools.Web.Entry/Startup.cs
+++ b/ApiTools.Web.Entry/Startup.cs
@@ -60,7 +60,7 @@
             {
                 options.BuildSqlType = SqlTypes.SqlServer;
                 options.JobDetail.LogEnabled = true;
-                //options.AddPersistence<DbJobPersistence>();
+                options.AddPersistence<DbJobPersistence>();
             });
 
             services.AddSpecificationDocuments(options =>

--
Gitblit v1.9.1