后端【新增】新增商家转账功能后台处理及接口回调获取。

This commit is contained in:
jianweie code
2025-07-29 00:51:57 +08:00
parent 596225acb1
commit c8b4bbd78d
38 changed files with 3385 additions and 436 deletions

View File

@@ -16,6 +16,7 @@
<PackageReference Include="Qiniu" Version="8.7.0" />
<PackageReference Include="QRCoder" Version="1.6.0" />
<PackageReference Include="SixLabors.ImageSharp.Web" Version="3.1.3" />
<PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.13.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.9.0" />
<PackageReference Include="System.Drawing.Common" Version="9.0.0" />
<PackageReference Include="Tencent.QCloud.Cos.Sdk" Version="5.4.40" />

View File

@@ -0,0 +1,129 @@
/***********************************************************************
* Project: CoreCms
* ProjectName: 核心内容管理系统
* Web: https://www.corecms.net
* Author: 大灰灰
* Email: jianweie@163.com
* CreateTime: 2025/7/21 20:36:56
* Description: 暂无
***********************************************************************/
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using CoreCms.Net.Configuration;
using CoreCms.Net.IRepository;
using CoreCms.Net.IRepository.UnitOfWork;
using CoreCms.Net.IServices;
using CoreCms.Net.Model.Entities;
using CoreCms.Net.Model.ViewModels.Basics;
using CoreCms.Net.Model.ViewModels.UI;
using SqlSugar;
namespace CoreCms.Net.Services
{
/// <summary>
/// 微信支付平台证书 接口实现
/// </summary>
public class CoreCmsWeChatPayPlatformCertificateServices : BaseServices<CoreCmsWeChatPayPlatformCertificate>, ICoreCmsWeChatPayPlatformCertificateServices
{
private readonly ICoreCmsWeChatPayPlatformCertificateRepository _dal;
private readonly IUnitOfWork _unitOfWork;
public CoreCmsWeChatPayPlatformCertificateServices(IUnitOfWork unitOfWork, ICoreCmsWeChatPayPlatformCertificateRepository dal)
{
this._dal = dal;
base.BaseDal = dal;
_unitOfWork = unitOfWork;
}
#region ==========================================================
/// <summary>
/// 重写异步插入方法
/// </summary>
/// <param name="entity">实体数据</param>
/// <returns></returns>
public async Task<AdminUiCallBack> InsertAsync(CoreCmsWeChatPayPlatformCertificate entity)
{
return await _dal.InsertAsync(entity);
}
/// <summary>
/// 重写异步更新方法方法
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> UpdateAsync(CoreCmsWeChatPayPlatformCertificate entity)
{
return await _dal.UpdateAsync(entity);
}
/// <summary>
/// 重写异步更新方法方法
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> UpdateAsync(List<CoreCmsWeChatPayPlatformCertificate> entity)
{
return await _dal.UpdateAsync(entity);
}
/// <summary>
/// 重写删除指定ID的数据
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> DeleteByIdAsync(object id)
{
return await _dal.DeleteByIdAsync(id);
}
/// <summary>
/// 重写删除指定ID集合的数据(批量删除)
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> DeleteByIdsAsync(int[] ids)
{
return await _dal.DeleteByIdsAsync(ids);
}
#endregion ==========================================================
#region ==========================================================
/// <summary>
/// 获取缓存的所有数据
/// </summary>
/// <returns></returns>
public async Task<List<CoreCmsWeChatPayPlatformCertificate>> GetCaChe()
{
return await _dal.GetCaChe();
}
#endregion ==========================================================
#region
/// <summary>
/// 重写根据条件查询分页数据
/// </summary>
/// <param name="predicate">判断集合</param>
/// <param name="orderByType">排序方式</param>
/// <param name="pageIndex">当前页面索引</param>
/// <param name="pageSize">分布大小</param>
/// <param name="orderByExpression"></param>
/// <param name="blUseNoLock">是否使用WITH(NOLOCK)</param>
/// <returns></returns>
public async Task<IPageList<CoreCmsWeChatPayPlatformCertificate>> QueryPageAsync(Expression<Func<CoreCmsWeChatPayPlatformCertificate, bool>> predicate,
Expression<Func<CoreCmsWeChatPayPlatformCertificate, object>> orderByExpression, OrderByType orderByType, int pageIndex = 1,
int pageSize = 20, bool blUseNoLock = false)
{
return await _dal.QueryPageAsync(predicate, orderByExpression, orderByType, pageIndex, pageSize, blUseNoLock);
}
#endregion
}
}

View File

@@ -8,11 +8,6 @@
* Description: 暂无
***********************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using CoreCms.Net.Caching.AccressToken;
using CoreCms.Net.Configuration;
using CoreCms.Net.IRepository;
@@ -31,14 +26,27 @@ using Essensoft.Paylink.WeChatPay.V2;
using Essensoft.Paylink.WeChatPay.V2.Request;
using Essensoft.Paylink.WeChatPay.V3.Domain;
using Essensoft.Paylink.WeChatPay.V3.Request;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using SKIT.FlurlHttpClient.Wechat.Api.Models;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using System.Threading.Tasks;
using Yitter.IdGenerator;
using Microsoft.AspNetCore.Hosting;
using NLog;
using static SKIT.FlurlHttpClient.Wechat.Api.Models.ECFinderLiveGetFinderLiveNoticeRecordListResponse.Types;
namespace CoreCms.Net.Services
@@ -60,11 +68,12 @@ namespace CoreCms.Net.Services
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly IWeChatPayConfigServices _weChatPayConfigServices;
private readonly IWechatTenpayClientFactory _wechatTenpayClientFactory;
private readonly ICoreCmsUserTocashWeChatResponseServices _userTocashWeChatResponseServices;
public CoreCmsUserTocashServices(IUnitOfWork unitOfWork, ICoreCmsUserTocashRepository dal,
IServiceProvider serviceProvider, ICoreCmsUserServices userServices, ICoreCmsUserBalanceServices userBalanceServices, ICoreCmsUserWeChatInfoServices weChatInfoServices, IWeChatPayClient v2Client, IHttpContextAccessor httpContextAccessor, IWebHostEnvironment webHostEnvironment, Essensoft.Paylink.WeChatPay.V3.IWeChatPayClient v3Client, IWeChatPayConfigServices weChatPayConfigServices)
IServiceProvider serviceProvider, ICoreCmsUserServices userServices, ICoreCmsUserBalanceServices userBalanceServices, ICoreCmsUserWeChatInfoServices weChatInfoServices, IWeChatPayClient v2Client, IHttpContextAccessor httpContextAccessor, IWebHostEnvironment webHostEnvironment, Essensoft.Paylink.WeChatPay.V3.IWeChatPayClient v3Client, IWeChatPayConfigServices weChatPayConfigServices, IWechatTenpayClientFactory wechatTenpayClientFactory, ICoreCmsUserTocashWeChatResponseServices userTocashWeChatResponseServices)
{
this._dal = dal;
base.BaseDal = dal;
@@ -78,6 +87,8 @@ namespace CoreCms.Net.Services
_webHostEnvironment = webHostEnvironment;
_v3Client = v3Client;
_weChatPayConfigServices = weChatPayConfigServices;
_wechatTenpayClientFactory = wechatTenpayClientFactory;
_userTocashWeChatResponseServices = userTocashWeChatResponseServices;
}
/// <summary>
@@ -508,6 +519,122 @@ namespace CoreCms.Net.Services
break;
}
case (int)GlobalEnumVars.UserTocashType.:
{
var user = await _userServices.QueryByIdAsync(info.userId);
if (user == null)
{
jm.msg = "用户信息获取失败";
return jm;
}
var weChatUserInfo = await _weChatInfoServices.QueryByClauseAsync(p => p.userId == info.userId);
if (weChatUserInfo == null)
{
jm.msg = "微信用户数据获取失败";
return jm;
}
var config = await _weChatPayConfigServices.QueryByClauseAsync(p => p.isDefault == true && p.isEnable == true);
if (config == null)
{
jm.msg = "支付配置信息获取失败";
return jm;
}
var client = await _wechatTenpayClientFactory.Create(config.mchId);
var request = new CreateFundAppMerchantTransferBillRequest();
request.WechatpaySerialNumber = config.payType switch
{
(int)GlobalEnumVars.WeChatPayIdentityVerificationMethods.PlatformCertificate => config
.platformSerialNumber,
(int)GlobalEnumVars.WeChatPayIdentityVerificationMethods.PlatformPublicKey => config
.platformPublicKeyId,
_ => request.WechatpaySerialNumber
};
request.AppId = config.appId;
request.OutBillNumber = "usertocash" + info.id;
request.TransferSceneId = "1000";
request.OpenId = weChatUserInfo.openid;
//按分计算
request.TransferAmount = Convert.ToInt32(info.money * 100);
if (request.TransferAmount > 30)
{
request.UserName = info.accountName;
}
request.TransferRemark = "客户推广业务佣金提现处理";
request.NotifyUrl = config.transferBillsUrl;
request.TransferSceneReportInfoList = new List<CreateFundAppMerchantTransferBillRequest.Types.TransferSceneReportInfo>()
{
new CreateFundAppMerchantTransferBillRequest.Types.TransferSceneReportInfo()
{
InfoType = "活动名称",
InfoContent = "分销佣金提现",
},
new CreateFundAppMerchantTransferBillRequest.Types.TransferSceneReportInfo()
{
InfoType = "奖励说明",
InfoContent = "用户分销佣金提现申请",
}
};
var response = await client.ExecuteCreateFundAppMerchantTransferBillAsync(request);
if (response.IsSuccessful())
{
status = (int)GlobalEnumVars.UserTocashStatus.;
var message = JsonConvert.SerializeObject(new
{
response
});
var bl = await _dal.UpdateAsync(p => new CoreCmsUserTocash() { status = status, updateTime = DateTime.Now, message = message, type = type }, p => p.id == id && (p.status == (int)GlobalEnumVars.UserTocashStatus. || p.status == (int)GlobalEnumVars.UserTocashStatus.));
NLogUtil.WriteAll(LogLevel.Trace, LogType.Refund, "微信提现商家转账回调(成功)", JsonConvert.SerializeObject(new
{
response,
request
}));
var log = new CoreCmsUserTocashWeChatResponse();
log.out_bill_no = response.OutBillNumber;
log.transfer_bill_no = response.TransferBillNumber;
log.state = response.State;
log.create_time = response.CreateTime.DateTime;
log.package_info = response.PackageInfo;
log.message = response.FailReason;
log.createTime = DateTime.Now;
await _userTocashWeChatResponseServices.InsertAsync(log);
jm.status = bl;
jm.data = status;
}
else
{
status = (int)GlobalEnumVars.UserTocashStatus.;
var message = JsonConvert.SerializeObject(new
{
response
});
var bl = await _dal.UpdateAsync(p => new CoreCmsUserTocash() { status = status, updateTime = DateTime.Now, message = message, type = type }, p => p.id == id && (p.status == (int)GlobalEnumVars.UserTocashStatus. || p.status == (int)GlobalEnumVars.UserTocashStatus.));
NLogUtil.WriteAll(LogLevel.Trace, LogType.Refund, "微信提现商家转账回调(失败)", JsonConvert.SerializeObject(new
{
response,
request
}));
jm.status = bl;
jm.data = status;
}
break;
}
default:
jm.msg = "提现方式获取失败";
jm.status = false;

View File

@@ -0,0 +1,116 @@
/***********************************************************************
* Project: CoreCms
* ProjectName: 核心内容管理系统
* Web: https://www.corecms.net
* Author: 大灰灰
* Email: jianweie@163.com
* CreateTime: 2025/7/28 23:08:04
* Description: 暂无
***********************************************************************/
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using CoreCms.Net.Configuration;
using CoreCms.Net.IRepository;
using CoreCms.Net.IRepository.UnitOfWork;
using CoreCms.Net.IServices;
using CoreCms.Net.Model.Entities;
using CoreCms.Net.Model.ViewModels.Basics;
using CoreCms.Net.Model.ViewModels.UI;
using SqlSugar;
namespace CoreCms.Net.Services
{
/// <summary>
/// 用户提现使用商家转账微信回调通知 接口实现
/// </summary>
public class CoreCmsUserTocashWeChatNotifyServices : BaseServices<CoreCmsUserTocashWeChatNotify>, ICoreCmsUserTocashWeChatNotifyServices
{
private readonly ICoreCmsUserTocashWeChatNotifyRepository _dal;
private readonly IUnitOfWork _unitOfWork;
public CoreCmsUserTocashWeChatNotifyServices(IUnitOfWork unitOfWork, ICoreCmsUserTocashWeChatNotifyRepository dal)
{
this._dal = dal;
base.BaseDal = dal;
_unitOfWork = unitOfWork;
}
#region ==========================================================
/// <summary>
/// 重写异步插入方法
/// </summary>
/// <param name="entity">实体数据</param>
/// <returns></returns>
public async Task<AdminUiCallBack> InsertAsync(CoreCmsUserTocashWeChatNotify entity)
{
return await _dal.InsertAsync(entity);
}
/// <summary>
/// 重写异步更新方法方法
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> UpdateAsync(CoreCmsUserTocashWeChatNotify entity)
{
return await _dal.UpdateAsync(entity);
}
/// <summary>
/// 重写异步更新方法方法
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> UpdateAsync(List<CoreCmsUserTocashWeChatNotify> entity)
{
return await _dal.UpdateAsync(entity);
}
/// <summary>
/// 重写删除指定ID的数据
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> DeleteByIdAsync(object id)
{
return await _dal.DeleteByIdAsync(id);
}
/// <summary>
/// 重写删除指定ID集合的数据(批量删除)
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> DeleteByIdsAsync(int[] ids)
{
return await _dal.DeleteByIdsAsync(ids);
}
#endregion ==========================================================
#region
/// <summary>
/// 重写根据条件查询分页数据
/// </summary>
/// <param name="predicate">判断集合</param>
/// <param name="orderByType">排序方式</param>
/// <param name="pageIndex">当前页面索引</param>
/// <param name="pageSize">分布大小</param>
/// <param name="orderByExpression"></param>
/// <param name="blUseNoLock">是否使用WITH(NOLOCK)</param>
/// <returns></returns>
public async Task<IPageList<CoreCmsUserTocashWeChatNotify>> QueryPageAsync(Expression<Func<CoreCmsUserTocashWeChatNotify, bool>> predicate,
Expression<Func<CoreCmsUserTocashWeChatNotify, object>> orderByExpression, OrderByType orderByType, int pageIndex = 1,
int pageSize = 20, bool blUseNoLock = false)
{
return await _dal.QueryPageAsync(predicate, orderByExpression, orderByType, pageIndex, pageSize, blUseNoLock);
}
#endregion
}
}

View File

@@ -0,0 +1,116 @@
/***********************************************************************
* Project: CoreCms
* ProjectName: 核心内容管理系统
* Web: https://www.corecms.net
* Author: 大灰灰
* Email: jianweie@163.com
* CreateTime: 2025/7/23 16:37:18
* Description: 暂无
***********************************************************************/
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using CoreCms.Net.Configuration;
using CoreCms.Net.IRepository;
using CoreCms.Net.IRepository.UnitOfWork;
using CoreCms.Net.IServices;
using CoreCms.Net.Model.Entities;
using CoreCms.Net.Model.ViewModels.Basics;
using CoreCms.Net.Model.ViewModels.UI;
using SqlSugar;
namespace CoreCms.Net.Services
{
/// <summary>
/// 用户提现使用商家转账回调记录 接口实现
/// </summary>
public class CoreCmsUserTocashWeChatResponseServices : BaseServices<CoreCmsUserTocashWeChatResponse>, ICoreCmsUserTocashWeChatResponseServices
{
private readonly ICoreCmsUserTocashWeChatResponseRepository _dal;
private readonly IUnitOfWork _unitOfWork;
public CoreCmsUserTocashWeChatResponseServices(IUnitOfWork unitOfWork, ICoreCmsUserTocashWeChatResponseRepository dal)
{
this._dal = dal;
base.BaseDal = dal;
_unitOfWork = unitOfWork;
}
#region ==========================================================
/// <summary>
/// 重写异步插入方法
/// </summary>
/// <param name="entity">实体数据</param>
/// <returns></returns>
public async Task<AdminUiCallBack> InsertAsync(CoreCmsUserTocashWeChatResponse entity)
{
return await _dal.InsertAsync(entity);
}
/// <summary>
/// 重写异步更新方法方法
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> UpdateAsync(CoreCmsUserTocashWeChatResponse entity)
{
return await _dal.UpdateAsync(entity);
}
/// <summary>
/// 重写异步更新方法方法
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> UpdateAsync(List<CoreCmsUserTocashWeChatResponse> entity)
{
return await _dal.UpdateAsync(entity);
}
/// <summary>
/// 重写删除指定ID的数据
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> DeleteByIdAsync(object id)
{
return await _dal.DeleteByIdAsync(id);
}
/// <summary>
/// 重写删除指定ID集合的数据(批量删除)
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public async Task<AdminUiCallBack> DeleteByIdsAsync(int[] ids)
{
return await _dal.DeleteByIdsAsync(ids);
}
#endregion ==========================================================
#region
/// <summary>
/// 重写根据条件查询分页数据
/// </summary>
/// <param name="predicate">判断集合</param>
/// <param name="orderByType">排序方式</param>
/// <param name="pageIndex">当前页面索引</param>
/// <param name="pageSize">分布大小</param>
/// <param name="orderByExpression"></param>
/// <param name="blUseNoLock">是否使用WITH(NOLOCK)</param>
/// <returns></returns>
public async Task<IPageList<CoreCmsUserTocashWeChatResponse>> QueryPageAsync(Expression<Func<CoreCmsUserTocashWeChatResponse, bool>> predicate,
Expression<Func<CoreCmsUserTocashWeChatResponse, object>> orderByExpression, OrderByType orderByType, int pageIndex = 1,
int pageSize = 20, bool blUseNoLock = false)
{
return await _dal.QueryPageAsync(predicate, orderByExpression, orderByType, pageIndex, pageSize, blUseNoLock);
}
#endregion
}
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using CoreCms.Net.Configuration;
using CoreCms.Net.IServices;
using Microsoft.Extensions.Options;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
namespace CoreCms.Net.Services
{
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings;
/// <summary>
/// 微信支付链接管理器实现
/// </summary>
internal partial class WechatTenpayClientFactory : IWechatTenpayClientFactory
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IWeChatPayConfigServices _weChatPayConfigServices;
private readonly ICoreCmsWeChatPayPlatformCertificateServices _weChatPayPlatformCertificateServices;
public WechatTenpayClientFactory(IHttpClientFactory httpClientFactory, IWeChatPayConfigServices weChatPayConfigServices, ICoreCmsWeChatPayPlatformCertificateServices weChatPayPlatformCertificateServices)
{
_httpClientFactory = httpClientFactory;
_weChatPayConfigServices = weChatPayConfigServices;
_weChatPayPlatformCertificateServices = weChatPayPlatformCertificateServices;
}
public async Task<WechatTenpayClient> Create(string merchantId)
{
var tenpayMerchantOptions = await _weChatPayConfigServices.QueryByClauseAsync(p => p.mchId == merchantId && p.isDefault == true && p.isEnable == true);
if (tenpayMerchantOptions == null)
{
throw new Exception("未在配置项中找到该 MerchantId 对应的微信商户号。");
}
var wechatTenpayClientOptions = new WechatTenpayClientOptions()
{
MerchantId = tenpayMerchantOptions.mchId,
MerchantV3Secret = tenpayMerchantOptions.apiV3Key,
MerchantCertificateSerialNumber = tenpayMerchantOptions.certificateSerialNumber,
MerchantCertificatePrivateKey = tenpayMerchantOptions.certificatePrivateKey,
AutoEncryptRequestSensitiveProperty = true,
AutoDecryptResponseSensitiveProperty = false,
};
// 基于平台证书的认证方式还需设置以下参数:
if (tenpayMerchantOptions.payType == (int)GlobalEnumVars.WeChatPayIdentityVerificationMethods.PlatformCertificate)
{
wechatTenpayClientOptions.PlatformAuthScheme = PlatformAuthScheme.Certificate;
var certificate = await _weChatPayPlatformCertificateServices.QueryByClauseAsync(p => p.merchantId == tenpayMerchantOptions.mchId);
if (certificate != null)
{
var entity = new CertificateEntry(certificate.algorithmType, certificate.serialNumber, certificate.certificate, certificate.effectiveTime, certificate.expireTime);
wechatTenpayClientOptions.PlatformCertificateManager.AddEntry(entity);
}
}
// 基于平台公钥的认证方式还需设置以下参数:
if (tenpayMerchantOptions.payType == (int)GlobalEnumVars.WeChatPayIdentityVerificationMethods.PlatformPublicKey)
{
wechatTenpayClientOptions.PlatformAuthScheme = PlatformAuthScheme.PublicKey;
wechatTenpayClientOptions.PlatformPublicKeyManager.AddEntry(
new PublicKeyEntry(
PublicKeyEntry.ALGORITHM_TYPE_RSA,
tenpayMerchantOptions.platformPublicKeyId!,
tenpayMerchantOptions.platformPublicKey!)
);
}
var wechatTenpayClient = WechatTenpayClientBuilder.Create(wechatTenpayClientOptions).Build();
return wechatTenpayClient;
}
}
}