接口【完善】完善接口端商家转账回调通知。

This commit is contained in:
jianweie code
2025-08-02 00:52:22 +08:00
parent 820d1a85cb
commit 8656d4ca36
9 changed files with 356 additions and 59 deletions

View File

@@ -26,6 +26,14 @@ namespace CoreCms.Net.IRepository
{
#region ===========================================================
/// <summary>
/// 重写异步插入方法(返回序列)
/// </summary>
/// <param name="entity">实体数据</param>
/// <returns></returns>
Task<int> ExecuteReturnIdentityAsync(CoreCmsUserTocashWeChatNotify entity);
/// <summary>
/// 重写异步插入方法
/// </summary>

View File

@@ -26,6 +26,13 @@ namespace CoreCms.Net.IServices
{
#region ===========================================================
/// <summary>
/// 重写异步插入方法(返回序列)
/// </summary>
/// <param name="entity">实体数据</param>
/// <returns></returns>
Task<int> ExecuteReturnIdentityAsync(CoreCmsUserTocashWeChatNotify entity);
/// <summary>
/// 重写异步插入方法
/// </summary>

View File

@@ -8397,6 +8397,11 @@
用户昵称
</summary>
</member>
<member name="P:CoreCms.Net.Model.Entities.CoreCmsUserTocash.merchantTransferData">
<summary>
商家转账反馈数据
</summary>
</member>
<member name="T:CoreCms.Net.Model.Entities.CoreCmsUserTocashWeChatNotify">
<summary>
用户提现使用商家转账微信回调通知
@@ -8447,6 +8452,31 @@
创建时间
</summary>
</member>
<member name="P:CoreCms.Net.Model.Entities.CoreCmsUserTocashWeChatNotify.wechatpaySerial">
<summary>
验签的平台证书序列号或支付公钥ID
</summary>
</member>
<member name="P:CoreCms.Net.Model.Entities.CoreCmsUserTocashWeChatNotify.wechatpaySignature">
<summary>
验签的签名值
</summary>
</member>
<member name="P:CoreCms.Net.Model.Entities.CoreCmsUserTocashWeChatNotify.wechatpayTimestamp">
<summary>
验签的时间戳
</summary>
</member>
<member name="P:CoreCms.Net.Model.Entities.CoreCmsUserTocashWeChatNotify.wechatpayNonce">
<summary>
验签的随机字符串
</summary>
</member>
<member name="P:CoreCms.Net.Model.Entities.CoreCmsUserTocashWeChatNotify.decryptedData">
<summary>
解密数据
</summary>
</member>
<member name="T:CoreCms.Net.Model.Entities.CoreCmsUserTocashWeChatResponse">
<summary>
用户提现使用商家转账回调记录

View File

@@ -4,7 +4,7 @@
* Web: https://www.corecms.net
* Author: 大灰灰
* Email: jianweie@163.com
* CreateTime: 2025/7/28 23:08:04
* CreateTime: 2025/8/1 23:54:59
* Description: 暂无
***********************************************************************/
@@ -30,62 +30,159 @@ namespace CoreCms.Net.Model.Entities
/// 序列
/// </summary>
[Display(Name = "序列")]
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
[Required(ErrorMessage = "请输入{0}")]
public System.Int32 id { get; set; }
public System.Int32 id { get; set; }
/// <summary>
/// 通知ID
/// </summary>
[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; }
/// <summary>
/// 通知创建时间
/// </summary>
[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; }
/// <summary>
/// 通知数据类型
/// </summary>
[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; }
/// <summary>
/// 通知类型
/// </summary>
[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; }
/// <summary>
/// 回调摘要
/// </summary>
[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; }
/// <summary>
/// 通知数据
/// </summary>
[Display(Name = "通知数据")]
[Required(ErrorMessage = "请输入{0}")]
public System.String resource { get; set; }
public System.String resource { get; set; }
/// <summary>
/// 创建时间
/// </summary>
[Display(Name = "创建时间")]
[Required(ErrorMessage = "请输入{0}")]
public System.DateTime createTime { get; set; }
public System.DateTime createTime { get; set; }
/// <summary>
/// 验签的平台证书序列号或支付公钥ID
/// </summary>
[Display(Name = "验签的平台证书序列号或支付公钥ID")]
[StringLength(maximumLength:100,ErrorMessage = "{0}不能超过{1}字")]
public System.String wechatpaySerial { get; set; }
/// <summary>
/// 验签的签名值
/// </summary>
[Display(Name = "验签的签名值")]
[StringLength(maximumLength:1000,ErrorMessage = "{0}不能超过{1}字")]
public System.String wechatpaySignature { get; set; }
/// <summary>
/// 验签的时间戳
/// </summary>
[Display(Name = "验签的时间戳")]
[StringLength(maximumLength:50,ErrorMessage = "{0}不能超过{1}字")]
public System.String wechatpayTimestamp { get; set; }
/// <summary>
/// 验签的随机字符串
/// </summary>
[Display(Name = "验签的随机字符串")]
[StringLength(maximumLength:100,ErrorMessage = "{0}不能超过{1}字")]
public System.String wechatpayNonce { get; set; }
/// <summary>
/// 解密数据
/// </summary>
[Display(Name = "解密数据")]
[StringLength(maximumLength:1000,ErrorMessage = "{0}不能超过{1}字")]
public System.String decryptedData { get; set; }
}
}

View File

@@ -4,7 +4,7 @@
* Web: https://www.corecms.net
* Author: 大灰灰
* Email: jianweie@163.com
* CreateTime: 2025/7/28 23:08:04
* CreateTime: 2025/8/1 23:54:59
* Description: 暂无
***********************************************************************/
@@ -29,7 +29,6 @@ namespace CoreCms.Net.Repository
public class CoreCmsUserTocashWeChatNotifyRepository : BaseRepository<CoreCmsUserTocashWeChatNotify>, ICoreCmsUserTocashWeChatNotifyRepository
{
private readonly IUnitOfWork _unitOfWork;
public CoreCmsUserTocashWeChatNotifyRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
{
_unitOfWork = unitOfWork;
@@ -37,6 +36,18 @@ namespace CoreCms.Net.Repository
#region ==========================================================
/// <summary>
/// 重写异步插入方法(返回序列)
/// </summary>
/// <param name="entity">实体数据</param>
/// <returns></returns>
public async Task<int> ExecuteReturnIdentityAsync(CoreCmsUserTocashWeChatNotify entity)
{
var id = await DbClient.Insertable(entity).ExecuteReturnIdentityAsync();
return id;
}
/// <summary>
/// 重写异步插入方法
/// </summary>
@@ -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
/// <summary>
/// 重写根据条件查询分页数据
/// </summary>
@@ -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<CoreCmsUserTocashWeChatNotify>(page, pageIndex, pageSize, totalCount);
return list;
}
#endregion
#endregion
}
}

View File

@@ -40,6 +40,16 @@ namespace CoreCms.Net.Services
#region ==========================================================
/// <summary>
/// 重写异步插入方法(返回序列)
/// </summary>
/// <param name="entity">实体数据</param>
/// <returns></returns>
public async Task<int> ExecuteReturnIdentityAsync(CoreCmsUserTocashWeChatNotify entity)
{
return await _dal.ExecuteReturnIdentityAsync(entity);
}
/// <summary>
/// 重写异步插入方法
/// </summary>

View File

@@ -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;
/// <summary>
/// 构造函数
/// </summary>
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;
}
/// <summary>
@@ -153,12 +162,17 @@ namespace CoreCms.Net.Web.WebApi.Controllers.PayNotify
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> TransferBillsCallBack([FromBody] FMTransferBillsCallBack entity)
public async Task<IActionResult> 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<SKIT.FlurlHttpClient.Wechat.TenpayV3.Events.MerchantTransferBillFinishedResource>(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();
}

View File

@@ -839,7 +839,7 @@
微信支付异步通知
</summary>
</member>
<member name="M:CoreCms.Net.Web.WebApi.Controllers.PayNotify.WeChatPayController.#ctor(Essensoft.Paylink.WeChatPay.V2.IWeChatPayNotifyClient,CoreCms.Net.IServices.ICoreCmsBillRefundServices,CoreCms.Net.Caching.AutoMate.RedisCache.IRedisOperationRepository,CoreCms.Net.IServices.IWeChatPayConfigServices,CoreCms.Net.IServices.ICoreCmsUserTocashWeChatNotifyServices)">
<member name="M:CoreCms.Net.Web.WebApi.Controllers.PayNotify.WeChatPayController.#ctor(Essensoft.Paylink.WeChatPay.V2.IWeChatPayNotifyClient,CoreCms.Net.IServices.ICoreCmsBillRefundServices,CoreCms.Net.Caching.AutoMate.RedisCache.IRedisOperationRepository,CoreCms.Net.IServices.IWeChatPayConfigServices,CoreCms.Net.IServices.ICoreCmsUserTocashWeChatNotifyServices,Microsoft.AspNetCore.Http.IHttpContextAccessor,CoreCms.Net.IServices.IWechatTenpayClientFactory,CoreCms.Net.IServices.ICoreCmsUserTocashServices)">
<summary>
构造函数
</summary>
@@ -854,7 +854,7 @@
退款结果通知
</summary>
</member>
<member name="M:CoreCms.Net.Web.WebApi.Controllers.PayNotify.WeChatPayController.TransferBillsCallBack(CoreCms.Net.Model.FromBody.FMTransferBillsCallBack)">
<member name="M:CoreCms.Net.Web.WebApi.Controllers.PayNotify.WeChatPayController.TransferBillsCallBack(System.String,System.String,System.String,System.String,CoreCms.Net.Model.FromBody.FMTransferBillsCallBack)">
<summary>
商家转账回调通知
</summary>

View File

@@ -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'<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>' , @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'<EFBFBD><EFBFBD>ǩ<EFBFBD><EFBFBD>ƽ̨֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>кŻ<EFBFBD>֧<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Կ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'<EFBFBD><EFBFBD>ǩ<EFBFBD><EFBFBD>ǩ<EFBFBD><EFBFBD>ֵ' , @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'<EFBFBD><EFBFBD>ǩ<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>' , @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'<EFBFBD><EFBFBD>ǩ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>' , @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'<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>' , @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'<EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD><EFBFBD>̼<EFBFBD>ת<EFBFBD><EFBFBD>΢<EFBFBD>Żص<EFBFBD>֪ͨ' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'CoreCmsUserTocashWeChatNotify'
GO