提交代码,增加创建微信、支付接口
This commit is contained in:
parent
a6768ca942
commit
5ae53b3cde
|
|
@ -0,0 +1,49 @@
|
||||||
|
using CloudGaming.Api.Base;
|
||||||
|
using CloudGaming.Code.Mall;
|
||||||
|
using CloudGaming.DtoModel.Mall;
|
||||||
|
|
||||||
|
using HuanMeng.DotNetCore.Base;
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace CloudGaming.Api.Controllers;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class PaymentController : CloudGamingControllerBase
|
||||||
|
{
|
||||||
|
public PaymentController(IServiceProvider _serviceProvider) : base(_serviceProvider)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建订单
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="intentOrder"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IntentOrderDto> CreateOrder([FromBody] IntentOrderRequest intentOrder)
|
||||||
|
{
|
||||||
|
OrderBLL orderBLL = new OrderBLL(ServiceProvider);
|
||||||
|
return await orderBLL.CreateOrder(intentOrder.PaymentMethod, intentOrder.ProductId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取订单状态
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="orderId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<BaseResponse<bool>> GetOrderRewardsInfo(string orderId)
|
||||||
|
{
|
||||||
|
OrderBLL orderBLL = new OrderBLL(ServiceProvider);
|
||||||
|
return await orderBLL.GetOrderRewardsInfo(orderId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -389,7 +389,7 @@ namespace CloudGaming.Code.Account
|
||||||
// 将用户身份证号设置成 "前四位*后四位"
|
// 将用户身份证号设置成 "前四位*后四位"
|
||||||
if (!string.IsNullOrEmpty(userInfoDto.IdCard) && userInfoDto.IdCard.Length >= 8)
|
if (!string.IsNullOrEmpty(userInfoDto.IdCard) && userInfoDto.IdCard.Length >= 8)
|
||||||
{
|
{
|
||||||
userInfo.IdCard = userInfoDto.IdCard.Substring(0, 4) + "*********" + userInfoDto.IdCard.Substring(userInfoDto.IdCard.Length - 4);
|
userInfoDto.IdCard = userInfoDto.IdCard.Substring(0, 4) + "*********" + userInfoDto.IdCard.Substring(userInfoDto.IdCard.Length - 4);
|
||||||
}
|
}
|
||||||
return userInfoDto;
|
return userInfoDto;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,7 @@ namespace CloudGaming.Code.Account
|
||||||
userInfo.IsJuveniles = user.UserRealNameStatus == 2;
|
userInfo.IsJuveniles = user.UserRealNameStatus == 2;
|
||||||
userInfo.UserName = user.UserName ?? "";
|
userInfo.UserName = user.UserName ?? "";
|
||||||
userInfo.IdCard = user.IDCard ?? "";
|
userInfo.IdCard = user.IDCard ?? "";
|
||||||
|
userInfo.IsTest = user.IsTest ?? false;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (userData != null)
|
if (userData != null)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
using Alipay.EasySDK.Factory;
|
||||||
|
using Alipay.EasySDK.Kernel.Util;
|
||||||
|
|
||||||
|
using CloudGaming.Code.Contract;
|
||||||
|
using CloudGaming.Code.Payment;
|
||||||
|
|
||||||
|
using HuanMeng.DotNetCore.MultiTenant;
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CloudGaming.Code.Aliyun;
|
||||||
|
|
||||||
|
public class AlipayPayment(AppConfig appConfig, int userId) : IPayment
|
||||||
|
{
|
||||||
|
public Task<(string orderId, string order)> CreateOrder(int productId, string productName, decimal price, params object[] args)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(productName))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException($"产品名称不能为空!");
|
||||||
|
}
|
||||||
|
var priceStr = price.ToString();
|
||||||
|
if (string.IsNullOrEmpty(priceStr))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException($"价格不能为空!");
|
||||||
|
}
|
||||||
|
var orderId = PaymentExtend.GenerateCustomString("ZFB", userId, productId, "001");
|
||||||
|
//.SetOptions(GetConfig());
|
||||||
|
//AsyncNotify
|
||||||
|
//https://pay.shhuanmeng.com/api/${tenant}/zfb/${orderId}
|
||||||
|
string sign = $"{appConfig.Identifier}{orderId}{userId}";
|
||||||
|
sign = MD5Encryption.ComputeMD5Hash(sign);
|
||||||
|
var notifyUrl = appConfig.Payment?.AlipayConfig?.NotifyUrl;
|
||||||
|
if (string.IsNullOrEmpty(notifyUrl))
|
||||||
|
{
|
||||||
|
notifyUrl = "";
|
||||||
|
}
|
||||||
|
var app = appConfig.Payment?.App();
|
||||||
|
if (app == null)
|
||||||
|
{
|
||||||
|
throw new Exception("支付宝配置错误");
|
||||||
|
}
|
||||||
|
notifyUrl = notifyUrl.Replace("${pay}", "zfb").Replace("${orderId}", orderId).Replace("${tenant}", appConfig.Identifier).Replace("${sign}", sign);
|
||||||
|
var response = app.AsyncNotify(notifyUrl).Optional("passback_params", "PaymentType%3Dzfb").Pay(productName, orderId, priceStr);
|
||||||
|
if (!ResponseChecker.Success(response))
|
||||||
|
{
|
||||||
|
throw new Exception("创建订单失败!" + response.Body);
|
||||||
|
}
|
||||||
|
//.PreCreate("Apple iPhone11 128G", "2234567234890", "5799.00");
|
||||||
|
var zfbOrderId = response.Body;
|
||||||
|
return Task.FromResult((orderId, zfbOrderId));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using CloudGaming.Code.AppExtend.Config;
|
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
@ -61,7 +62,7 @@ public class AppConfig
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 项目支付数据
|
/// 项目支付数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
//public PaymentModel? Payment { get; set; }
|
public PaymentModel? Payment { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// oss阿里云配置
|
/// oss阿里云配置
|
||||||
|
|
|
||||||
|
|
@ -186,12 +186,14 @@ namespace CloudGaming.Code.AppExtend
|
||||||
newAppConfig.ExtConnectionString = appConfig.ExtConnectionString;
|
newAppConfig.ExtConnectionString = appConfig.ExtConnectionString;
|
||||||
newAppConfig.PhoneConnectionString = appConfig.PhoneConnectionString;
|
newAppConfig.PhoneConnectionString = appConfig.PhoneConnectionString;
|
||||||
newAppConfig.AliyunConfig = appConfig.AliyunConfig;
|
newAppConfig.AliyunConfig = appConfig.AliyunConfig;
|
||||||
newAppConfig.DefaultLanguage = appConfig.DefaultLanguage;
|
newAppConfig.DefaultLanguage = appConfig.DefaultLanguage ?? "zh";
|
||||||
if (appConfig.UserConfig == null)
|
if (appConfig.UserConfig == null)
|
||||||
{
|
{
|
||||||
appConfig.UserConfig = new UserConfig();
|
appConfig.UserConfig = new UserConfig();
|
||||||
}
|
}
|
||||||
newAppConfig.UserConfig = appConfig.UserConfig;
|
newAppConfig.UserConfig = appConfig.UserConfig;
|
||||||
|
newAppConfig.Payment = appConfig.Payment;
|
||||||
|
|
||||||
return newAppConfig;
|
return newAppConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CloudGaming.Code.AppExtend.Config;
|
namespace CloudGaming.Code.AppExtend.ConfigModel;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
using Alipay.EasySDK.Kernel;
|
||||||
|
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
|
||||||
|
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
|
||||||
|
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
namespace CloudGaming.Code.AppExtend.ConfigModel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class PaymentModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 微信支付数据
|
||||||
|
/// </summary>
|
||||||
|
public WeChatConfig? WeChatConfig { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 支付宝支付数据
|
||||||
|
/// </summary>
|
||||||
|
public Alipay.EasySDK.Kernel.Config? AlipayConfig { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
private WechatTenpayClient _wxClient;
|
||||||
|
/// <summary>
|
||||||
|
/// 微信支付客户端
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public WechatTenpayClient? WxClient
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_wxClient == null)
|
||||||
|
{
|
||||||
|
if (WeChatConfig == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var manager = new InMemoryCertificateManager();
|
||||||
|
/* 仅列出必须配置项。也包含一些诸如超时时间、UserAgent 等的配置项 */
|
||||||
|
var wechatTenpayClientOptions = new WechatTenpayClientOptions()
|
||||||
|
{
|
||||||
|
|
||||||
|
MerchantId = WeChatConfig.MchId,
|
||||||
|
MerchantV3Secret = WeChatConfig.Key,
|
||||||
|
MerchantCertificateSerialNumber = WeChatConfig.MerchantCertificateSerialNumber,
|
||||||
|
MerchantCertificatePrivateKey = WeChatConfig.MerchantCertificatePrivateKey,
|
||||||
|
PlatformCertificateManager = manager
|
||||||
|
};
|
||||||
|
_wxClient = new WechatTenpayClient(wechatTenpayClientOptions);
|
||||||
|
}
|
||||||
|
return _wxClient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// var conf = appConfig.Payment?.AlipayConfig ?? new Alipay.EasySDK.Kernel.Config();
|
||||||
|
//var context = new Alipay.EasySDK.Kernel.Context(conf, "alipay-easysdk-net-2.1.0");
|
||||||
|
//var app = new Alipay.EasySDK.Payment.App.Client(new Alipay.EasySDK.Kernel.Client(context));
|
||||||
|
|
||||||
|
private Alipay.EasySDK.Kernel.Context _aliPayContext;
|
||||||
|
[JsonIgnore]
|
||||||
|
public Alipay.EasySDK.Kernel.Context AliPayContext
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_aliPayContext == null)
|
||||||
|
{
|
||||||
|
if (AlipayConfig != null)
|
||||||
|
{
|
||||||
|
_aliPayContext = new Alipay.EasySDK.Kernel.Context(AlipayConfig, "alipay-easysdk-net-2.1.0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _aliPayContext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CloudGaming.Code.AppExtend.Config;
|
namespace CloudGaming.Code.AppExtend.ConfigModel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用户默认配置
|
/// 用户默认配置
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CloudGaming.Code.AppExtend.ConfigModel;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class WeChatConfig
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// appId
|
||||||
|
/// </summary>
|
||||||
|
public string AppId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// appkey
|
||||||
|
/// </summary>
|
||||||
|
public string AppSecret { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Key { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 商户id
|
||||||
|
/// </summary>
|
||||||
|
public string MchId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 回调地址
|
||||||
|
/// </summary>
|
||||||
|
public string NotifyUrl { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string MerchantCertificateSerialNumber { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string MerchantCertificatePrivateKey { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -12,11 +12,14 @@
|
||||||
<PackageReference Include="AgileConfig.Client" Version="1.7.3" />
|
<PackageReference Include="AgileConfig.Client" Version="1.7.3" />
|
||||||
<PackageReference Include="AlibabaCloud.SDK.Cloudauth20190307" Version="3.2.0" />
|
<PackageReference Include="AlibabaCloud.SDK.Cloudauth20190307" Version="3.2.0" />
|
||||||
<PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="3.1.0" />
|
<PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="3.1.0" />
|
||||||
|
<PackageReference Include="AlipayEasySDK" Version="2.1.3" />
|
||||||
|
<PackageReference Include="AlipayEasySDK.Kernel" Version="1.0.6" />
|
||||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||||
<PackageReference Include="Bogus" Version="35.6.1" />
|
<PackageReference Include="Bogus" Version="35.6.1" />
|
||||||
<PackageReference Include="FastMember" Version="1.5.0" />
|
<PackageReference Include="FastMember" Version="1.5.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.1" />
|
||||||
|
<PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.9.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
23
src/CloudGaming/Code/CloudGaming.Code/Contract/IPayment.cs
Normal file
23
src/CloudGaming/Code/CloudGaming.Code/Contract/IPayment.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CloudGaming.Code.Contract;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 支付接口
|
||||||
|
/// </summary>
|
||||||
|
public interface IPayment
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 创建订单
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="productId">产品id</param>
|
||||||
|
/// <param name="productName">产品名称</param>
|
||||||
|
/// <param name="price">价格</param>
|
||||||
|
/// <param name="args">其它参数</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<(string orderId, string order)> CreateOrder(int productId, string productName, decimal price, params object[] args);
|
||||||
|
}
|
||||||
12
src/CloudGaming/Code/CloudGaming.Code/Extend/OrderExtend.cs
Normal file
12
src/CloudGaming/Code/CloudGaming.Code/Extend/OrderExtend.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CloudGaming.Code.Extend
|
||||||
|
{
|
||||||
|
internal class OrderExtend
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,5 +19,6 @@ global using Microsoft.EntityFrameworkCore;
|
||||||
global using Microsoft.Extensions.Configuration;
|
global using Microsoft.Extensions.Configuration;
|
||||||
global using Microsoft.Extensions.DependencyInjection;
|
global using Microsoft.Extensions.DependencyInjection;
|
||||||
global using Microsoft.Extensions.Hosting;
|
global using Microsoft.Extensions.Hosting;
|
||||||
global using CloudGaming.Code.AppExtend.Config;
|
global using System.Diagnostics;
|
||||||
global using System.Diagnostics;
|
|
||||||
|
global using CloudGaming.Code.AppExtend.ConfigModel;
|
||||||
108
src/CloudGaming/Code/CloudGaming.Code/Mall/OrderBLL.cs
Normal file
108
src/CloudGaming/Code/CloudGaming.Code/Mall/OrderBLL.cs
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
using CloudGaming.Code.DataAccess;
|
||||||
|
using CloudGaming.Code.Payment;
|
||||||
|
using CloudGaming.DtoModel.Account.User;
|
||||||
|
using CloudGaming.DtoModel.Mall;
|
||||||
|
|
||||||
|
using HuanMeng.DotNetCore.Redis;
|
||||||
|
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CloudGaming.Code.Mall;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 订单数据
|
||||||
|
/// </summary>
|
||||||
|
public class OrderBLL : CloudGamingBase
|
||||||
|
{
|
||||||
|
public OrderBLL(IServiceProvider serviceProvider) : base(serviceProvider)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建订单
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="paymentMethod"></param>
|
||||||
|
/// <param name="productId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
|
/// <exception cref="NullReferenceException"></exception>
|
||||||
|
/// <exception cref="Exception"></exception>
|
||||||
|
public async Task<IntentOrderDto> CreateOrder(string paymentMethod, string productId)
|
||||||
|
{
|
||||||
|
if (_UserId == 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("未登录");
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(productId))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("产品不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
var products = Cache.ProductCacheList;
|
||||||
|
var product = products.FirstOrDefault(it => it.ProductId == productId);
|
||||||
|
if (product == null)
|
||||||
|
{
|
||||||
|
throw new NullReferenceException("未找到所属产品");
|
||||||
|
}
|
||||||
|
var redisLock = $"lock:payment:{_UserId}:{productId}";
|
||||||
|
if (!RedisCache.StringSetLock(redisLock, "", 5))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException("重复创建订单");
|
||||||
|
}
|
||||||
|
|
||||||
|
//productEntityCache.get
|
||||||
|
IntentOrderDto intentOrderDto = null;
|
||||||
|
//创建订单
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var ip = HttpContextAccessor.HttpContext.GetClientIpAddress();
|
||||||
|
var price = product.Price;
|
||||||
|
var payment = PaymentExtend.GetPayment(paymentMethod, this);
|
||||||
|
//UserInfoBLL userInfo = new UserInfoBLL(Dao, _UserId);
|
||||||
|
if (UserInfo.IsTest)
|
||||||
|
{
|
||||||
|
price = (decimal)0.01;
|
||||||
|
}
|
||||||
|
(var orderId, var order) = await payment.CreateOrder(product.Id, product.ProductName, price, product, ip);
|
||||||
|
var t = product.ToIntentOrder(paymentMethod, orderId);
|
||||||
|
t.UserId = _UserId;
|
||||||
|
await Dao.DaoUser.Context.AddAsync(t);
|
||||||
|
await Dao.DaoUser.Context.SaveChangesAsync();
|
||||||
|
intentOrderDto = new IntentOrderDto()
|
||||||
|
{
|
||||||
|
OrderId = orderId,
|
||||||
|
Payment = order
|
||||||
|
};
|
||||||
|
RedisCache.KeyDelete(redisLock);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
RedisCache.KeyDelete(redisLock);
|
||||||
|
throw new Exception("创建订单失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
return intentOrderDto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取订单状态
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="orderId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<BaseResponse<bool>> GetOrderRewardsInfo(string orderId)
|
||||||
|
{
|
||||||
|
var tips = await Dao.DaoUser.Context.T_User_OrderItems.Where(it => it.OrderId == orderId).Select(it => it.RewardTips).FirstOrDefaultAsync();
|
||||||
|
if (string.IsNullOrEmpty(tips))
|
||||||
|
{
|
||||||
|
return new BaseResponse<bool>(ResonseCode.Success, "", false);
|
||||||
|
}
|
||||||
|
return new BaseResponse<bool>(ResonseCode.Success, tips, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
278
src/CloudGaming/Code/CloudGaming.Code/Payment/PaymentExtend.cs
Normal file
278
src/CloudGaming/Code/CloudGaming.Code/Payment/PaymentExtend.cs
Normal file
|
|
@ -0,0 +1,278 @@
|
||||||
|
using Alipay.EasySDK.Factory;
|
||||||
|
|
||||||
|
using CloudGaming.Code.Aliyun;
|
||||||
|
using CloudGaming.Code.Contract;
|
||||||
|
using CloudGaming.Code.WeChat;
|
||||||
|
using CloudGaming.DtoModel.Mall;
|
||||||
|
using CloudGaming.DtoModel.Payment;
|
||||||
|
|
||||||
|
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
|
||||||
|
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Settings;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CloudGaming.Code.Payment;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public static class PaymentExtend
|
||||||
|
{
|
||||||
|
private static WechatTenpayClientOptions wechatTenpayClientOptions { get; set; } = new WechatTenpayClientOptions();
|
||||||
|
private static WeChatConfig weChatConfig { get; set; }
|
||||||
|
private static WechatTenpayClient wxClient { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 支付
|
||||||
|
/// </su0mmary>
|
||||||
|
/// <param name="builder"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IHostApplicationBuilder AddPayment(this IHostApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
|
||||||
|
AddAlipay(builder.Configuration);
|
||||||
|
AddWeChat(builder.Configuration);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 加载微信支付
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration"></param>
|
||||||
|
public static void AddWeChat(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var _weChatConfig = configuration.GetSection("Payment:WeChatConfig").Get<WeChatConfig>();
|
||||||
|
if (_weChatConfig == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("微信支付失败");
|
||||||
|
//throw new Exception("微信支付失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
weChatConfig = _weChatConfig;
|
||||||
|
var manager = new InMemoryCertificateManager();
|
||||||
|
/* 仅列出必须配置项。也包含一些诸如超时时间、UserAgent 等的配置项 */
|
||||||
|
wechatTenpayClientOptions = new WechatTenpayClientOptions()
|
||||||
|
{
|
||||||
|
|
||||||
|
MerchantId = weChatConfig.MchId,
|
||||||
|
MerchantV3Secret = weChatConfig.Key,
|
||||||
|
MerchantCertificateSerialNumber = weChatConfig.MerchantCertificateSerialNumber,
|
||||||
|
MerchantCertificatePrivateKey = weChatConfig.MerchantCertificatePrivateKey,
|
||||||
|
PlatformCertificateManager = manager
|
||||||
|
};
|
||||||
|
wxClient = new WechatTenpayClient(wechatTenpayClientOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public static Alipay.EasySDK.Kernel.Config AlipayConfig { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 支付
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="configuration"></param>
|
||||||
|
public static void AddAlipay(IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var _config = configuration.GetSection("Payment:AlipayConfig").Get<Alipay.EasySDK.Kernel.Config>();
|
||||||
|
|
||||||
|
if (_config == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("接入支付失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var config = new Alipay.EasySDK.Kernel.Config()
|
||||||
|
{
|
||||||
|
Protocol = "https",
|
||||||
|
GatewayHost = "openapi.alipay.com",
|
||||||
|
SignType = "RSA2",
|
||||||
|
AppId = _config.AppId,
|
||||||
|
// 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中
|
||||||
|
MerchantPrivateKey = _config.MerchantPrivateKey,
|
||||||
|
// 如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
|
||||||
|
AlipayPublicKey = _config.AlipayPublicKey,
|
||||||
|
//可设置异步通知接收服务地址(可选)
|
||||||
|
NotifyUrl = _config.NotifyUrl,
|
||||||
|
};
|
||||||
|
AlipayConfig = config;
|
||||||
|
Factory.SetOptions(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///获取支付方式
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="payment"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static IPayment GetPayment(string payment, CloudGamingBase cloudGamingBase)
|
||||||
|
{
|
||||||
|
//miaoYuBase.AppConfig.Payment
|
||||||
|
if (payment == "zfb")
|
||||||
|
{
|
||||||
|
return new AlipayPayment(cloudGamingBase.AppConfig, cloudGamingBase._UserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cloudGamingBase.AppConfig != null)
|
||||||
|
{
|
||||||
|
if (cloudGamingBase.AppConfig.Payment == null)
|
||||||
|
{
|
||||||
|
cloudGamingBase.AppConfig.Payment = new PaymentModel()
|
||||||
|
{
|
||||||
|
WeChatConfig = weChatConfig
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (cloudGamingBase.AppConfig.Payment.WeChatConfig == null)
|
||||||
|
{
|
||||||
|
cloudGamingBase.AppConfig.Payment.WeChatConfig = weChatConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _weChatConfig = cloudGamingBase.AppConfig.Payment.WeChatConfig ?? weChatConfig;
|
||||||
|
var _wxClient = cloudGamingBase.AppConfig.Payment.WxClient ?? wxClient;
|
||||||
|
if (payment == "xcx")
|
||||||
|
{
|
||||||
|
if (cloudGamingBase._UserId == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("请先登录");
|
||||||
|
}
|
||||||
|
var userAccount = cloudGamingBase.Dao.DaoUser.Context.T_User_MiniProgram_Account.FirstOrDefault(it => it.UserId == cloudGamingBase._UserId);
|
||||||
|
if (userAccount == null)
|
||||||
|
{
|
||||||
|
throw new Exception("未找到人员数据,请先登录");
|
||||||
|
}
|
||||||
|
|
||||||
|
//return new WeChatMiniProgram(_wxClient, _weChatConfig, miaoYuBase.TenantInfo, miaoYuBase._UserId, userAccount.OpenId);
|
||||||
|
}
|
||||||
|
return new WeChatPayment(_wxClient, _weChatConfig, cloudGamingBase.AppConfig, cloudGamingBase._UserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取支付包支付接口
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="payment"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static Alipay.EasySDK.Payment.App.Client App(this PaymentModel payment)
|
||||||
|
{
|
||||||
|
return new Alipay.EasySDK.Payment.App.Client(new Alipay.EasySDK.Kernel.Client(payment.AliPayContext));
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="productCache"></param>
|
||||||
|
/// <param name="payment"></param>
|
||||||
|
/// <param name="orderId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T_User_IntentOrder ToIntentOrder(this ProductCache productCache, string payment, string orderId)
|
||||||
|
{
|
||||||
|
T_User_IntentOrder t_User_IntentOrder = new T_User_IntentOrder()
|
||||||
|
{
|
||||||
|
Price = productCache.Price,
|
||||||
|
CreatedAt = DateTime.Now,
|
||||||
|
IntentAt = DateTime.Now,
|
||||||
|
Method = payment,
|
||||||
|
Notes = "",
|
||||||
|
ProductId = productCache.ProductId,
|
||||||
|
Quantity = 1,
|
||||||
|
Status = (int)OrderState.已下单,
|
||||||
|
UpdatedAt = DateTime.Now,
|
||||||
|
OrderId = orderId,
|
||||||
|
};
|
||||||
|
return t_User_IntentOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生成订单编号
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="identifier"></param>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <param name="machineCode"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="ArgumentException"></exception>
|
||||||
|
public static string GenerateCustomString(string identifier, int userId, int producId, string machineCode)
|
||||||
|
{
|
||||||
|
// 确保标识符为3位,不足补0
|
||||||
|
string identifierPadded = identifier.PadRight(3, '0');
|
||||||
|
|
||||||
|
// 获取当前时间戳
|
||||||
|
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||||
|
|
||||||
|
// 将用户ID补足6位,不足补0
|
||||||
|
string userIdPadded = userId.ToString().PadLeft(6, '0');
|
||||||
|
// 产品id补足3位
|
||||||
|
string producIdPadded = producId.ToString().PadLeft(3, '0');
|
||||||
|
// 确保机器码为3位,不足补0
|
||||||
|
string machineCodePadded = machineCode.PadLeft(3, '0');
|
||||||
|
|
||||||
|
// 计算随机字符串应占用的位数
|
||||||
|
int randomStringLength = 32 - (identifierPadded.Length + 1 + 10 + 1 + userIdPadded.Length + 1 + machineCodePadded.Length + 1 + producIdPadded.Length + 1);
|
||||||
|
|
||||||
|
// 生成指定长度的随机字符串(字母和数字混合)
|
||||||
|
string randomPadded = GenerateRandomString(randomStringLength);
|
||||||
|
|
||||||
|
// 使用 StringBuilder 拼接成最终字符串
|
||||||
|
var sb = new StringBuilder(32);
|
||||||
|
sb.Append(identifierPadded)
|
||||||
|
.Append('T').Append(timestamp)
|
||||||
|
.Append('U').Append(userIdPadded)
|
||||||
|
.Append('P').Append(producIdPadded)
|
||||||
|
.Append('M').Append(machineCodePadded)
|
||||||
|
.Append('R').Append(randomPadded);
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateRandomString(int length)
|
||||||
|
{
|
||||||
|
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
|
var random = new Random();
|
||||||
|
var result = new char[length];
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
result[i] = chars[random.Next(chars.Length)];
|
||||||
|
}
|
||||||
|
return new string(result);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 解析订单号
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="customString"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="ArgumentException"></exception>
|
||||||
|
public static (string Identifier, long Timestamp, int UserId, int ProductId, string MachineCode, string RandomString) ParseCustomString(string customString)
|
||||||
|
{
|
||||||
|
if (customString.Length != 32)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Custom string must be exactly 32 characters long.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过索引位置缓存各个部分的起始位置
|
||||||
|
int tIndex = customString.IndexOf('T');
|
||||||
|
|
||||||
|
int uIndex = customString.IndexOf('U');
|
||||||
|
int pIndex = customString.IndexOf('P');
|
||||||
|
int mIndex = customString.IndexOf('M');
|
||||||
|
int rIndex = customString.IndexOf('R');
|
||||||
|
|
||||||
|
// 提取并去掉标识符的末尾零
|
||||||
|
string identifier = customString.Substring(0, tIndex).TrimEnd('0');
|
||||||
|
|
||||||
|
// 提取时间戳
|
||||||
|
long timestamp = long.Parse(customString.Substring(tIndex + 1, uIndex - tIndex - 1));
|
||||||
|
|
||||||
|
// 提取用户ID
|
||||||
|
int userId = int.Parse(customString.Substring(uIndex + 1, pIndex - uIndex - 1));
|
||||||
|
|
||||||
|
// 提取产品ID
|
||||||
|
int productId = int.Parse(customString.Substring(pIndex + 1, mIndex - pIndex - 1));
|
||||||
|
|
||||||
|
// 提取机器码
|
||||||
|
string machineCode = customString.Substring(mIndex + 1, rIndex - mIndex - 1);
|
||||||
|
|
||||||
|
// 提取随机字符串
|
||||||
|
string randomString = customString.Substring(rIndex + 1);
|
||||||
|
|
||||||
|
return (identifier, timestamp, userId, productId, machineCode, randomString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
using CloudGaming.Code.Contract;
|
||||||
|
using CloudGaming.Code.Payment;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
|
||||||
|
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CloudGaming.Code.WeChat;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 微信支付
|
||||||
|
/// </summary>
|
||||||
|
public class WeChatPayment(WechatTenpayClient client, WeChatConfig weChatConfig, AppConfig appConfig, int userId) : IPayment
|
||||||
|
{
|
||||||
|
public async Task<(string orderId, string order)> CreateOrder(int productId, string productName, decimal price, params object[] args)
|
||||||
|
{
|
||||||
|
//var orderId = GenerateTimestampIdWithOffset();
|
||||||
|
var orderId = PaymentExtend.GenerateCustomString("WX", userId, productId, "001");
|
||||||
|
//var client = new WechatTenpayClient(wechatTenpayClientOptions);
|
||||||
|
/* 以 JSAPI 统一下单接口为例 */
|
||||||
|
string sign = $"{appConfig.Identifier}{orderId}{userId}";
|
||||||
|
sign = MD5Encryption.ComputeMD5Hash(sign);
|
||||||
|
var notifyUrl = weChatConfig.NotifyUrl.Replace("${pay}", "wx").Replace("${orderId}", orderId).Replace("${tenant}", appConfig.Identifier).Replace("${sign}", sign);
|
||||||
|
|
||||||
|
var request = new CreatePayTransactionAppRequest()
|
||||||
|
{
|
||||||
|
OutTradeNumber = orderId,
|
||||||
|
AppId = weChatConfig.AppId,
|
||||||
|
Description = productName,
|
||||||
|
ExpireTime = DateTimeOffset.Now.AddMinutes(20),
|
||||||
|
NotifyUrl = notifyUrl,
|
||||||
|
Amount = new CreatePayTransactionJsapiRequest.Types.Amount()
|
||||||
|
{
|
||||||
|
Total = (int)(price * 100)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await client.ExecuteCreatePayTransactionAppAsync(request);
|
||||||
|
if (response.IsSuccessful())
|
||||||
|
{
|
||||||
|
var paramMap = client.GenerateParametersForAppPayRequest(request.AppId, response.PrepayId);
|
||||||
|
//Console.WriteLine("PrepayId:" + response.PrepayId);
|
||||||
|
return new(orderId, JsonConvert.SerializeObject(paramMap));
|
||||||
|
}
|
||||||
|
throw new Exception("微信下单失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -44,6 +44,11 @@ namespace CloudGaming.DtoModel.Account.User
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string> GameCollects { get; set; }
|
public List<string> GameCollects { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否测试账号
|
||||||
|
/// </summary>
|
||||||
|
public bool IsTest { get; set; }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CloudGaming.DtoModel.Mall
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class IntentOrderDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 订单编号
|
||||||
|
/// </summary>
|
||||||
|
public string OrderId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 支付信息
|
||||||
|
/// </summary>
|
||||||
|
public object Payment { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CloudGaming.DtoModel.Mall;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class IntentOrderRequest
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 产品编号
|
||||||
|
/// </summary>
|
||||||
|
public string ProductId { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 支付方式
|
||||||
|
/// </summary>
|
||||||
|
public string PaymentMethod { get; set; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CloudGaming.DtoModel.Payment;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 订单状态
|
||||||
|
/// </summary>
|
||||||
|
public enum OrderState
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 已下单
|
||||||
|
/// </summary>
|
||||||
|
已下单 = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// 正在发货
|
||||||
|
/// </summary>
|
||||||
|
正在发货 = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// 已完成
|
||||||
|
/// </summary>
|
||||||
|
已完成 = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// 发货失败
|
||||||
|
/// </summary>
|
||||||
|
发货失败 = 3
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user