diff --git a/CoreCms.Net.IRepository/User/ICoreCmsUserTocashWeChatNotifyRepository.cs b/CoreCms.Net.IRepository/User/ICoreCmsUserTocashWeChatNotifyRepository.cs index dcded3dd..53624f09 100644 --- a/CoreCms.Net.IRepository/User/ICoreCmsUserTocashWeChatNotifyRepository.cs +++ b/CoreCms.Net.IRepository/User/ICoreCmsUserTocashWeChatNotifyRepository.cs @@ -26,6 +26,14 @@ namespace CoreCms.Net.IRepository { #region 重写增删改查操作=========================================================== + /// + /// 重写异步插入方法(返回序列) + /// + /// 实体数据 + /// + Task ExecuteReturnIdentityAsync(CoreCmsUserTocashWeChatNotify entity); + + /// /// 重写异步插入方法 /// diff --git a/CoreCms.Net.IServices/User/ICoreCmsUserTocashWeChatNotifyServices.cs b/CoreCms.Net.IServices/User/ICoreCmsUserTocashWeChatNotifyServices.cs index b91b49b1..5c193dfa 100644 --- a/CoreCms.Net.IServices/User/ICoreCmsUserTocashWeChatNotifyServices.cs +++ b/CoreCms.Net.IServices/User/ICoreCmsUserTocashWeChatNotifyServices.cs @@ -26,6 +26,13 @@ namespace CoreCms.Net.IServices { #region 重写增删改查操作=========================================================== + /// + /// 重写异步插入方法(返回序列) + /// + /// 实体数据 + /// + Task ExecuteReturnIdentityAsync(CoreCmsUserTocashWeChatNotify entity); + /// /// 重写异步插入方法 /// diff --git a/CoreCms.Net.Model/CoreCms.Net.Model.xml b/CoreCms.Net.Model/CoreCms.Net.Model.xml index 1455a5ef..bdcbf0bd 100644 --- a/CoreCms.Net.Model/CoreCms.Net.Model.xml +++ b/CoreCms.Net.Model/CoreCms.Net.Model.xml @@ -8397,6 +8397,11 @@ 用户昵称 + + + 商家转账反馈数据 + + 用户提现使用商家转账微信回调通知 @@ -8447,6 +8452,31 @@ 创建时间 + + + 验签的平台证书序列号或支付公钥ID + + + + + 验签的签名值 + + + + + 验签的时间戳 + + + + + 验签的随机字符串 + + + + + 解密数据 + + 用户提现使用商家转账回调记录 diff --git a/CoreCms.Net.Model/Entities/User/CoreCmsUserTocashWeChatNotify.cs b/CoreCms.Net.Model/Entities/User/CoreCmsUserTocashWeChatNotify.cs index efcd9c12..433a9411 100644 --- a/CoreCms.Net.Model/Entities/User/CoreCmsUserTocashWeChatNotify.cs +++ b/CoreCms.Net.Model/Entities/User/CoreCmsUserTocashWeChatNotify.cs @@ -1,10 +1,10 @@ /*********************************************************************** * Project: CoreCms - * ProjectName: 核心内容管理系统 - * Web: https://www.corecms.net - * Author: 大灰灰 - * Email: jianweie@163.com - * CreateTime: 2025/7/28 23:08:04 + * ProjectName: 核心内容管理系统 + * Web: https://www.corecms.net + * Author: 大灰灰 + * Email: jianweie@163.com + * CreateTime: 2025/8/1 23:54:59 * Description: 暂无 ***********************************************************************/ @@ -25,67 +25,164 @@ namespace CoreCms.Net.Model.Entities public CoreCmsUserTocashWeChatNotify() { } - + /// /// 序列 /// [Display(Name = "序列")] + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + [Required(ErrorMessage = "请输入{0}")] - public System.Int32 id { get; set; } - + + + + public System.Int32 id { get; set; } + + /// /// 通知ID /// [Display(Name = "通知ID")] + [Required(ErrorMessage = "请输入{0}")] - [StringLength(maximumLength: 50, ErrorMessage = "{0}不能超过{1}字")] - public System.String callBackId { get; set; } - + [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")] + + + public System.String callBackId { get; set; } + + /// /// 通知创建时间 /// [Display(Name = "通知创建时间")] + [Required(ErrorMessage = "请输入{0}")] - [StringLength(maximumLength: 50, ErrorMessage = "{0}不能超过{1}字")] - public System.String create_time { get; set; } - + [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")] + + + public System.String create_time { get; set; } + + /// /// 通知数据类型 /// [Display(Name = "通知数据类型")] + [Required(ErrorMessage = "请输入{0}")] - [StringLength(maximumLength: 50, ErrorMessage = "{0}不能超过{1}字")] - public System.String resource_type { get; set; } - + [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")] + + + public System.String resource_type { get; set; } + + /// /// 通知类型 /// [Display(Name = "通知类型")] + [Required(ErrorMessage = "请输入{0}")] - [StringLength(maximumLength: 50, ErrorMessage = "{0}不能超过{1}字")] - public System.String event_type { get; set; } - + [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")] + + + public System.String event_type { get; set; } + + /// /// 回调摘要 /// [Display(Name = "回调摘要")] + [Required(ErrorMessage = "请输入{0}")] - [StringLength(maximumLength: 100, ErrorMessage = "{0}不能超过{1}字")] - public System.String summary { get; set; } - + [StringLength(maximumLength:100,ErrorMessage = "{0}不能超过{1}字")] + + + public System.String summary { get; set; } + + /// /// 通知数据 /// [Display(Name = "通知数据")] + [Required(ErrorMessage = "请输入{0}")] - public System.String resource { get; set; } - + + + + public System.String resource { get; set; } + + /// /// 创建时间 /// [Display(Name = "创建时间")] + [Required(ErrorMessage = "请输入{0}")] - public System.DateTime createTime { get; set; } + + + + public System.DateTime createTime { get; set; } + + + /// + /// 验签的平台证书序列号或支付公钥ID + /// + [Display(Name = "验签的平台证书序列号或支付公钥ID")] + + + [StringLength(maximumLength:100,ErrorMessage = "{0}不能超过{1}字")] + + + public System.String wechatpaySerial { get; set; } + + + /// + /// 验签的签名值 + /// + [Display(Name = "验签的签名值")] + + + [StringLength(maximumLength:1000,ErrorMessage = "{0}不能超过{1}字")] + + + public System.String wechatpaySignature { get; set; } + + + /// + /// 验签的时间戳 + /// + [Display(Name = "验签的时间戳")] + + + [StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")] + + + public System.String wechatpayTimestamp { get; set; } + + + /// + /// 验签的随机字符串 + /// + [Display(Name = "验签的随机字符串")] + + + [StringLength(maximumLength:100,ErrorMessage = "{0}不能超过{1}字")] + + + public System.String wechatpayNonce { get; set; } + + + /// + /// 解密数据 + /// + [Display(Name = "解密数据")] + + + [StringLength(maximumLength:1000,ErrorMessage = "{0}不能超过{1}字")] + + + public System.String decryptedData { get; set; } + + } -} \ No newline at end of file +} diff --git a/CoreCms.Net.Repository/User/CoreCmsUserTocashWeChatNotifyRepository.cs b/CoreCms.Net.Repository/User/CoreCmsUserTocashWeChatNotifyRepository.cs index 2833a281..d22573ab 100644 --- a/CoreCms.Net.Repository/User/CoreCmsUserTocashWeChatNotifyRepository.cs +++ b/CoreCms.Net.Repository/User/CoreCmsUserTocashWeChatNotifyRepository.cs @@ -1,10 +1,10 @@ /*********************************************************************** * Project: CoreCms - * ProjectName: 核心内容管理系统 - * Web: https://www.corecms.net - * Author: 大灰灰 - * Email: jianweie@163.com - * CreateTime: 2025/7/28 23:08:04 + * ProjectName: 核心内容管理系统 + * Web: https://www.corecms.net + * Author: 大灰灰 + * Email: jianweie@163.com + * CreateTime: 2025/8/1 23:54:59 * Description: 暂无 ***********************************************************************/ @@ -29,7 +29,6 @@ namespace CoreCms.Net.Repository public class CoreCmsUserTocashWeChatNotifyRepository : BaseRepository, ICoreCmsUserTocashWeChatNotifyRepository { private readonly IUnitOfWork _unitOfWork; - public CoreCmsUserTocashWeChatNotifyRepository(IUnitOfWork unitOfWork) : base(unitOfWork) { _unitOfWork = unitOfWork; @@ -37,6 +36,18 @@ namespace CoreCms.Net.Repository #region 实现重写增删改查操作========================================================== + + /// + /// 重写异步插入方法(返回序列) + /// + /// 实体数据 + /// + public async Task ExecuteReturnIdentityAsync(CoreCmsUserTocashWeChatNotify entity) + { + var id = await DbClient.Insertable(entity).ExecuteReturnIdentityAsync(); + return id; + } + /// /// 重写异步插入方法 /// @@ -69,7 +80,7 @@ namespace CoreCms.Net.Repository return jm; } //事物处理过程开始 - oldModel.id = entity.id; + //oldModel.id = entity.id; oldModel.callBackId = entity.callBackId; oldModel.create_time = entity.create_time; oldModel.resource_type = entity.resource_type; @@ -77,6 +88,11 @@ namespace CoreCms.Net.Repository oldModel.summary = entity.summary; oldModel.resource = entity.resource; oldModel.createTime = entity.createTime; + oldModel.wechatpaySerial = entity.wechatpaySerial; + oldModel.wechatpaySignature = entity.wechatpaySignature; + oldModel.wechatpayTimestamp = entity.wechatpayTimestamp; + oldModel.wechatpayNonce = entity.wechatpayNonce; + oldModel.decryptedData = entity.decryptedData; //事物处理过程结束 var bl = await DbClient.Updateable(oldModel).ExecuteCommandHasChangeAsync(); @@ -134,10 +150,9 @@ namespace CoreCms.Net.Repository return jm; } - #endregion 实现重写增删改查操作========================================================== + #endregion #region 重写根据条件查询分页数据 - /// /// 重写根据条件查询分页数据 /// @@ -168,6 +183,12 @@ namespace CoreCms.Net.Repository summary = p.summary, resource = p.resource, createTime = p.createTime, + wechatpaySerial = p.wechatpaySerial, + wechatpaySignature = p.wechatpaySignature, + wechatpayTimestamp = p.wechatpayTimestamp, + wechatpayNonce = p.wechatpayNonce, + decryptedData = p.decryptedData, + }).With(SqlWith.NoLock).ToPageListAsync(pageIndex, pageSize, totalCount); } else @@ -184,12 +205,19 @@ namespace CoreCms.Net.Repository summary = p.summary, resource = p.resource, createTime = p.createTime, + wechatpaySerial = p.wechatpaySerial, + wechatpaySignature = p.wechatpaySignature, + wechatpayTimestamp = p.wechatpayTimestamp, + wechatpayNonce = p.wechatpayNonce, + decryptedData = p.decryptedData, + }).ToPageListAsync(pageIndex, pageSize, totalCount); } var list = new PageList(page, pageIndex, pageSize, totalCount); return list; } - #endregion 重写根据条件查询分页数据 + #endregion + } -} \ No newline at end of file +} diff --git a/CoreCms.Net.Services/User/CoreCmsUserTocashWeChatNotifyServices.cs b/CoreCms.Net.Services/User/CoreCmsUserTocashWeChatNotifyServices.cs index 8a7157dd..e3c4fbc5 100644 --- a/CoreCms.Net.Services/User/CoreCmsUserTocashWeChatNotifyServices.cs +++ b/CoreCms.Net.Services/User/CoreCmsUserTocashWeChatNotifyServices.cs @@ -40,6 +40,16 @@ namespace CoreCms.Net.Services #region 实现重写增删改查操作========================================================== + /// + /// 重写异步插入方法(返回序列) + /// + /// 实体数据 + /// + public async Task ExecuteReturnIdentityAsync(CoreCmsUserTocashWeChatNotify entity) + { + return await _dal.ExecuteReturnIdentityAsync(entity); + } + /// /// 重写异步插入方法 /// diff --git a/CoreCms.Net.Web.WebApi/Controllers/PayNotify/WeChatPayController.cs b/CoreCms.Net.Web.WebApi/Controllers/PayNotify/WeChatPayController.cs index 6efd2376..0738fd8e 100644 --- a/CoreCms.Net.Web.WebApi/Controllers/PayNotify/WeChatPayController.cs +++ b/CoreCms.Net.Web.WebApi/Controllers/PayNotify/WeChatPayController.cs @@ -17,12 +17,15 @@ using CoreCms.Net.Model.FromBody; using Essensoft.Paylink.WeChatPay; using Essensoft.Paylink.WeChatPay.V2; using Essensoft.Paylink.WeChatPay.V2.Notify; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Newtonsoft.Json; using NLog; using System; +using System.Linq; using System.Threading.Tasks; +using SKIT.FlurlHttpClient.Wechat.TenpayV3; namespace CoreCms.Net.Web.WebApi.Controllers.PayNotify { @@ -39,18 +42,24 @@ namespace CoreCms.Net.Web.WebApi.Controllers.PayNotify private readonly IWeChatPayConfigServices _weChatPayConfigServices; private readonly ICoreCmsUserTocashWeChatNotifyServices _userTocashWeChatNotifyServices; + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly IWechatTenpayClientFactory _wechatTenpayClientFactory; + private readonly ICoreCmsUserTocashServices _userTocashServices; /// /// 构造函数 /// public WeChatPayController( - IWeChatPayNotifyClient client, ICoreCmsBillRefundServices billRefundServices, IRedisOperationRepository redisOperationRepository, IWeChatPayConfigServices weChatPayConfigServices, ICoreCmsUserTocashWeChatNotifyServices userTocashWeChatNotifyServices) + IWeChatPayNotifyClient client, ICoreCmsBillRefundServices billRefundServices, IRedisOperationRepository redisOperationRepository, IWeChatPayConfigServices weChatPayConfigServices, ICoreCmsUserTocashWeChatNotifyServices userTocashWeChatNotifyServices, IHttpContextAccessor httpContextAccessor, IWechatTenpayClientFactory wechatTenpayClientFactory, ICoreCmsUserTocashServices userTocashServices) { _client = client; _billRefundServices = billRefundServices; _redisOperationRepository = redisOperationRepository; _weChatPayConfigServices = weChatPayConfigServices; _userTocashWeChatNotifyServices = userTocashWeChatNotifyServices; + _httpContextAccessor = httpContextAccessor; + _wechatTenpayClientFactory = wechatTenpayClientFactory; + _userTocashServices = userTocashServices; } /// @@ -153,12 +162,17 @@ namespace CoreCms.Net.Web.WebApi.Controllers.PayNotify /// /// [HttpPost] - public async Task TransferBillsCallBack([FromBody] FMTransferBillsCallBack entity) + public async Task TransferBillsCallBack( + [FromHeader(Name = "Wechatpay-Timestamp")] string timestamp, + [FromHeader(Name = "Wechatpay-Nonce")] string nonce, + [FromHeader(Name = "Wechatpay-Signature")] string signature, + [FromHeader(Name = "Wechatpay-Serial")] string serialNumber, + [FromBody] FMTransferBillsCallBack entity) { try { NLogUtil.WriteAll(LogLevel.Trace, LogType.Refund, "商家转账回调通知", JsonConvert.SerializeObject(entity)); - + // 检查请求头是否包含必要的字段 if (entity == null) { var obj = new @@ -169,25 +183,108 @@ namespace CoreCms.Net.Web.WebApi.Controllers.PayNotify return new JsonResult(obj); } - var log = new CoreCmsUserTocashWeChatNotify(); - - log.callBackId = entity.id; - log.create_time = entity.create_time; - log.resource_type = entity.resource_type; - log.event_type = entity.event_type; - log.summary = entity.summary; - log.resource = JsonConvert.SerializeObject(entity.resource); - log.createTime = DateTime.Now; - - await _userTocashWeChatNotifyServices.InsertAsync(log); - - - if (entity.event_type== "MCHTRANSFER.BILL.FINISHED") + // 存储回调数据 + var log = new CoreCmsUserTocashWeChatNotify { - + wechatpayNonce = nonce, + wechatpaySerial = serialNumber, + wechatpaySignature = signature, + wechatpayTimestamp = timestamp, + callBackId = entity.id, + create_time = entity.create_time, + resource_type = entity.resource_type, + event_type = entity.event_type, + summary = entity.summary, + resource = JsonConvert.SerializeObject(entity.resource), + createTime = DateTime.Now + }; + // 获取返回序列 + var id = await _userTocashWeChatNotifyServices.ExecuteReturnIdentityAsync(log); + + // 获取支付配置 + var payConfig = await _weChatPayConfigServices.QueryByClauseAsync(p => + p.isDefault == true && p.isEnable == true && + p.appType == GlobalEnumVars.WeiChatPayTradeType.JSAPI.ToString()); + + // 构建WeChatPay客户端 + var client = await _wechatTenpayClientFactory.Create(payConfig.mchId); + + // 验证签名 + bool valid = await client.VerifyEventSignatureAsync( + webhookTimestamp: timestamp, + webhookNonce: nonce, + webhookBody: JsonConvert.SerializeObject(entity), + webhookSignature: signature, + webhookSerialNumber: serialNumber + ); + + // 如果验签失败,返回错误信息 + if (!valid) + { + return new JsonResult(new { code = "FAIL", message = "验签失败" }); } + // 反序列化回调模型 + var callbackModel = client.DeserializeEvent(JsonConvert.SerializeObject(entity)); + var eventType = callbackModel.EventType?.ToUpper(); + // 处理不同的事件类型 + if (eventType == "MCHTRANSFER.BILL.FINISHED") + { + var callbackResource = client.DecryptEventResource(callbackModel); + + if (callbackResource != null) + { + //更新解密数据 + await _userTocashWeChatNotifyServices.UpdateAsync(p => new CoreCmsUserTocashWeChatNotify + { + decryptedData = JsonConvert.SerializeObject(callbackResource) + }, p => p.id == id); + + //业务处理 + var usertocash = callbackResource.OutBillNumber.Replace("usertocash", ""); + var userTocashId = Convert.ToInt32(usertocash); + + switch (callbackResource.State) + { + //转账成功 + case "SUCCESS": + await _userTocashServices.UpdateAsync(p => new CoreCmsUserTocash() + { + needUserGet = false, + }, p => p.id == userTocashId); + break; + + //单据已受理 + case "ACCEPTED": + break; + + //单据处理中,转账结果尚未明确,如一直处于此状态,建议检查账户余额是否足够 + case "PROCESSING": + break; + + //待收款用户确认,可拉起微信收款确认页面进行收款确认 + case "WAIT_USER_CONFIRM": + break; + + //转账失败 + case "FAIL": + break; + + //撤销中 + case "CANCELING": + break; + + //撤销 + case "CANCELLED": + break; + } + } + } + else + { + // 其他情况略 + } return NoContent(); } diff --git a/CoreCms.Net.Web.WebApi/CoreCms.Net.Web.WebApi.xml b/CoreCms.Net.Web.WebApi/CoreCms.Net.Web.WebApi.xml index b18d5654..4d9c4e21 100644 --- a/CoreCms.Net.Web.WebApi/CoreCms.Net.Web.WebApi.xml +++ b/CoreCms.Net.Web.WebApi/CoreCms.Net.Web.WebApi.xml @@ -839,7 +839,7 @@ 微信支付异步通知 - + 构造函数 @@ -854,7 +854,7 @@ 退款结果通知 - + 商家转账回调通知 diff --git a/数据库/SqlServer/20250729/3、新增【用户提现使用商家转账微信回调通知表】CoreCmsUserTocashWeChatNotify.sql b/数据库/SqlServer/20250729/3、新增【用户提现使用商家转账微信回调通知表】CoreCmsUserTocashWeChatNotify.sql index d9a3054a..ad442fea 100644 --- a/数据库/SqlServer/20250729/3、新增【用户提现使用商家转账微信回调通知表】CoreCmsUserTocashWeChatNotify.sql +++ b/数据库/SqlServer/20250729/3、新增【用户提现使用商家转账微信回调通知表】CoreCmsUserTocashWeChatNotify.sql @@ -1,5 +1,5 @@ -/****** Object: Table [dbo].[CoreCmsUserTocashWeChatNotify] Script Date: 2025/7/29 0:16:28 ******/ +/****** Object: Table [dbo].[CoreCmsUserTocashWeChatNotify] Script Date: 2025/8/2 0:29:31 ******/ SET ANSI_NULLS ON GO @@ -15,6 +15,11 @@ CREATE TABLE [dbo].[CoreCmsUserTocashWeChatNotify]( [summary] [NVARCHAR](100) NOT NULL, [resource] [NVARCHAR](MAX) NOT NULL, [createTime] [DATETIME] NOT NULL, + [wechatpaySerial] [NVARCHAR](100) NULL, + [wechatpaySignature] [NVARCHAR](1000) NULL, + [wechatpayTimestamp] [NVARCHAR](50) NULL, + [wechatpayNonce] [NVARCHAR](100) NULL, + [decryptedData] [NVARCHAR](1000) NULL, CONSTRAINT [PK_CoreCmsUserTocashWeChatNotify] PRIMARY KEY CLUSTERED ( [id] ASC @@ -46,6 +51,21 @@ GO EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ʱ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'CoreCmsUserTocashWeChatNotify', @level2type=N'COLUMN',@level2name=N'createTime' GO +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ǩƽ̨֤кŻ֧ԿID' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'CoreCmsUserTocashWeChatNotify', @level2type=N'COLUMN',@level2name=N'wechatpaySerial' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ǩǩֵ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'CoreCmsUserTocashWeChatNotify', @level2type=N'COLUMN',@level2name=N'wechatpaySignature' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ǩʱ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'CoreCmsUserTocashWeChatNotify', @level2type=N'COLUMN',@level2name=N'wechatpayTimestamp' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ǩַ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'CoreCmsUserTocashWeChatNotify', @level2type=N'COLUMN',@level2name=N'wechatpayNonce' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'CoreCmsUserTocashWeChatNotify', @level2type=N'COLUMN',@level2name=N'decryptedData' +GO + EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'ûʹ̼ת΢Żص֪ͨ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'CoreCmsUserTocashWeChatNotify' GO