修改创建订单回调地址
This commit is contained in:
parent
9047e3915c
commit
8dc9ee123c
43
src/0-core/HuanMeng.DotNetCore/Utility/MD5Encryption.cs
Normal file
43
src/0-core/HuanMeng.DotNetCore/Utility/MD5Encryption.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace HuanMeng.DotNetCore.Utility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public static class MD5Encryption
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// md5加密
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string ComputeMD5Hash(string input)
|
||||||
|
{
|
||||||
|
// 创建一个 MD5 哈希算法的实例
|
||||||
|
using (MD5 md5 = MD5.Create())
|
||||||
|
{
|
||||||
|
// 将输入字符串转换为字节数组
|
||||||
|
byte[] inputBytes = Encoding.UTF8.GetBytes(input);
|
||||||
|
|
||||||
|
// 计算 MD5 哈希值
|
||||||
|
byte[] hashBytes = md5.ComputeHash(inputBytes);
|
||||||
|
|
||||||
|
// 将字节数组转换为十六进制字符串
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < hashBytes.Length; i++)
|
||||||
|
{
|
||||||
|
sb.Append(hashBytes[i].ToString("x2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回哈希值字符串
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -55,7 +55,7 @@ namespace HuanMeng.MiaoYu.Code.Order
|
||||||
{
|
{
|
||||||
price = (decimal)0.01;
|
price = (decimal)0.01;
|
||||||
}
|
}
|
||||||
(var orderId, var order) = await payment.CreateOrder(product.ProductName, price, product, ip);
|
(var orderId, var order) = await payment.CreateOrder(product.Id,product.ProductName, price, product, ip);
|
||||||
var t = product.ToIntentOrder(paymentMethod, orderId);
|
var t = product.ToIntentOrder(paymentMethod, orderId);
|
||||||
t.UserId = _UserId;
|
t.UserId = _UserId;
|
||||||
Dao.daoDbMiaoYu.context.Add(t);
|
Dao.daoDbMiaoYu.context.Add(t);
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,16 @@ using Alipay.EasySDK.Kernel.Util;
|
||||||
using Alipay.EasySDK.Payment.FaceToFace.Models;
|
using Alipay.EasySDK.Payment.FaceToFace.Models;
|
||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
using HuanMeng.DotNetCore.MultiTenant.Contract;
|
using HuanMeng.DotNetCore.MultiTenant.Contract;
|
||||||
|
using HuanMeng.MiaoYu.Code.Payment.WeChat;
|
||||||
|
|
||||||
namespace HuanMeng.MiaoYu.Code.Payment.Alipay
|
namespace HuanMeng.MiaoYu.Code.Payment.Alipay
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AlipayPayment(Config config, ITenantInfo tenantInfo) : IPayment
|
public class AlipayPayment(Config config, ITenantInfo tenantInfo, int userId) : IPayment
|
||||||
{
|
{
|
||||||
public Task<(string orderId, string order)> CreateOrder(string productName, decimal price, params object[] args)
|
public Task<(string orderId, string order)> CreateOrder(int productId, string productName, decimal price, params object[] args)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(productName))
|
if (string.IsNullOrEmpty(productName))
|
||||||
{
|
{
|
||||||
|
|
@ -30,11 +31,13 @@ namespace HuanMeng.MiaoYu.Code.Payment.Alipay
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException($"价格不能为空!");
|
throw new ArgumentNullException($"价格不能为空!");
|
||||||
}
|
}
|
||||||
var orderId = GenerateTimestampIdWithOffset();
|
var orderId = PaymentExtend.GenerateCustomString("ZFB", userId, productId, "001");
|
||||||
//.SetOptions(GetConfig());
|
//.SetOptions(GetConfig());
|
||||||
//AsyncNotify
|
//AsyncNotify
|
||||||
//https://pay.shhuanmeng.com/api/${tenant}/zfb/${orderId}
|
//https://pay.shhuanmeng.com/api/${tenant}/zfb/${orderId}
|
||||||
var notifyUrl = config.NotifyUrl.Replace("${pay}", "zfb").Replace("${orderId}", orderId).Replace("${tenant}", tenantInfo.Identifier); ;
|
string sign = $"{tenantInfo.Identifier}{orderId}{userId}";
|
||||||
|
sign = MD5Encryption.ComputeMD5Hash(sign);
|
||||||
|
var notifyUrl = config.NotifyUrl.Replace("${pay}", "zfb").Replace("${orderId}", orderId).Replace("${tenant}", tenantInfo.Identifier).Replace("${sign}", sign);
|
||||||
var response = Factory.Payment.App().AsyncNotify(notifyUrl).Optional("passback_params", "PaymentType%3Dzfb").Pay(productName, orderId, priceStr);
|
var response = Factory.Payment.App().AsyncNotify(notifyUrl).Optional("passback_params", "PaymentType%3Dzfb").Pay(productName, orderId, priceStr);
|
||||||
if (!ResponseChecker.Success(response))
|
if (!ResponseChecker.Success(response))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,15 @@ namespace HuanMeng.MiaoYu.Code.Payment.Contract
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建订单
|
/// 创建订单
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="productId">产品id</param>
|
||||||
/// <param name="orderId">订单id</param>
|
/// <param name="orderId">订单id</param>
|
||||||
/// <param name="productName">产品名称</param>
|
/// <param name="productName">产品名称</param>
|
||||||
/// <param name="price">价格</param>
|
/// <param name="price">价格</param>
|
||||||
/// <param name="args">其它参数</param>
|
/// <param name="args">其它参数</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<(string orderId, string order)> CreateOrder(string productName, decimal price, params object[] args);
|
Task<(string orderId, string order)> CreateOrder(int productId, string productName, decimal price, params object[] args);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,9 +111,9 @@ namespace HuanMeng.MiaoYu.Code.Payment
|
||||||
|
|
||||||
if (payment == "zfb")
|
if (payment == "zfb")
|
||||||
{
|
{
|
||||||
return new AlipayPayment(AlipayConfig, miaoYuBase.TenantInfo);
|
return new AlipayPayment(AlipayConfig, miaoYuBase.TenantInfo, miaoYuBase._UserId);
|
||||||
}
|
}
|
||||||
return new WeChatPayment(wxClient, weChatConfig, miaoYuBase.TenantInfo);
|
return new WeChatPayment(wxClient, weChatConfig, miaoYuBase.TenantInfo, miaoYuBase._UserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -140,5 +140,98 @@ namespace HuanMeng.MiaoYu.Code.Payment
|
||||||
};
|
};
|
||||||
return t_User_IntentOrder;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,25 @@ using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
|
||||||
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
|
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using HuanMeng.DotNetCore.MultiTenant.Contract;
|
using HuanMeng.DotNetCore.MultiTenant.Contract;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace HuanMeng.MiaoYu.Code.Payment.WeChat
|
namespace HuanMeng.MiaoYu.Code.Payment.WeChat
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 微信支付
|
/// 微信支付
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WeChatPayment(WechatTenpayClient client, WeChatConfig weChatConfig, ITenantInfo tenantInfo) : IPayment
|
public class WeChatPayment(WechatTenpayClient client, WeChatConfig weChatConfig, ITenantInfo tenantInfo, int userId) : IPayment
|
||||||
{
|
{
|
||||||
public async Task<(string orderId, string order)> CreateOrder(string productName, decimal price, params object[] args)
|
public async Task<(string orderId, string order)> CreateOrder(int productId, string productName, decimal price, params object[] args)
|
||||||
{
|
{
|
||||||
var orderId = GenerateTimestampIdWithOffset();
|
//var orderId = GenerateTimestampIdWithOffset();
|
||||||
|
var orderId = PaymentExtend.GenerateCustomString("WX", userId, productId, "001");
|
||||||
//var client = new WechatTenpayClient(wechatTenpayClientOptions);
|
//var client = new WechatTenpayClient(wechatTenpayClientOptions);
|
||||||
/* 以 JSAPI 统一下单接口为例 */
|
/* 以 JSAPI 统一下单接口为例 */
|
||||||
var notifyUrl = weChatConfig.NotifyUrl.Replace("${pay}", "wx").Replace("${orderId}", orderId).Replace("${tenant}", tenantInfo.Identifier);
|
string sign = $"{tenantInfo.Identifier}{orderId}{userId}";
|
||||||
|
sign = MD5Encryption.ComputeMD5Hash(sign);
|
||||||
|
var notifyUrl = weChatConfig.NotifyUrl.Replace("${pay}", "wx").Replace("${orderId}", orderId).Replace("${tenant}", tenantInfo.Identifier).Replace("${sign}", sign);
|
||||||
|
|
||||||
var request = new CreatePayTransactionAppRequest()
|
var request = new CreatePayTransactionAppRequest()
|
||||||
{
|
{
|
||||||
OutTradeNumber = orderId,
|
OutTradeNumber = orderId,
|
||||||
|
|
@ -34,16 +39,10 @@ namespace HuanMeng.MiaoYu.Code.Payment.WeChat
|
||||||
if (response.IsSuccessful())
|
if (response.IsSuccessful())
|
||||||
{
|
{
|
||||||
var paramMap = client.GenerateParametersForAppPayRequest(request.AppId, response.PrepayId);
|
var paramMap = client.GenerateParametersForAppPayRequest(request.AppId, response.PrepayId);
|
||||||
Console.WriteLine("PrepayId:" + response.PrepayId);
|
//Console.WriteLine("PrepayId:" + response.PrepayId);
|
||||||
return new(orderId, JsonConvert.SerializeObject(paramMap));
|
return new(orderId, JsonConvert.SerializeObject(paramMap));
|
||||||
}
|
}
|
||||||
throw new Exception("微信下单失败");
|
throw new Exception("微信下单失败");
|
||||||
}
|
}
|
||||||
private string GenerateTimestampIdWithOffset()
|
|
||||||
{
|
|
||||||
var timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(); // 获取Unix时间戳(毫秒)
|
|
||||||
var random = new Random().Next(1000, 9999); // 生成四位随机数
|
|
||||||
return $"WX0{timestamp}J001C{random}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@ namespace HuanMeng.MiaoYu.WebPayApi.Controllers
|
||||||
/// ${tenant}/zfb/${orderId}
|
/// ${tenant}/zfb/${orderId}
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpPost("{tenant?}/{pay?}/{orderId?}")]
|
[HttpPost("{tenant?}/{pay?}/{orderId?}/{sign?}")]
|
||||||
public async Task<string> Post(string? tenant, string? pay, string? orderId)
|
public async Task<string> Post(string? tenant, string? pay, string? orderId,string? sign)
|
||||||
{
|
{
|
||||||
var context = httpContextAccessor.HttpContext;
|
var context = httpContextAccessor.HttpContext;
|
||||||
context.Request.EnableBuffering(); // Enable buffering to allow the body to be read multiple times
|
context.Request.EnableBuffering(); // Enable buffering to allow the body to be read multiple times
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user