修改创建订单回调地址

This commit is contained in:
zpc 2024-08-27 22:11:31 +08:00
parent 9047e3915c
commit 8dc9ee123c
7 changed files with 163 additions and 21 deletions

View 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();
}
}
}
}

View File

@ -55,7 +55,7 @@ namespace HuanMeng.MiaoYu.Code.Order
{
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);
t.UserId = _UserId;
Dao.daoDbMiaoYu.context.Add(t);

View File

@ -11,15 +11,16 @@ using Alipay.EasySDK.Kernel.Util;
using Alipay.EasySDK.Payment.FaceToFace.Models;
using StackExchange.Redis;
using HuanMeng.DotNetCore.MultiTenant.Contract;
using HuanMeng.MiaoYu.Code.Payment.WeChat;
namespace HuanMeng.MiaoYu.Code.Payment.Alipay
{
/// <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))
{
@ -30,11 +31,13 @@ namespace HuanMeng.MiaoYu.Code.Payment.Alipay
{
throw new ArgumentNullException($"价格不能为空!");
}
var orderId = GenerateTimestampIdWithOffset();
var orderId = PaymentExtend.GenerateCustomString("ZFB", userId, productId, "001");
//.SetOptions(GetConfig());
//AsyncNotify
//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);
if (!ResponseChecker.Success(response))
{

View File

@ -14,11 +14,15 @@ namespace HuanMeng.MiaoYu.Code.Payment.Contract
/// <summary>
/// 创建订单
/// </summary>
/// <param name="productId">产品id</param>
/// <param name="orderId">订单id</param>
/// <param name="productName">产品名称</param>
/// <param name="price">价格</param>
/// <param name="args">其它参数</param>
/// <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);
}
}

View File

@ -111,9 +111,9 @@ namespace HuanMeng.MiaoYu.Code.Payment
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>
@ -140,5 +140,98 @@ namespace HuanMeng.MiaoYu.Code.Payment
};
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);
}
}
}

View File

@ -4,20 +4,25 @@ using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;
using SKIT.FlurlHttpClient.Wechat.TenpayV3;
using Newtonsoft.Json;
using HuanMeng.DotNetCore.MultiTenant.Contract;
using System.Security.Cryptography;
namespace HuanMeng.MiaoYu.Code.Payment.WeChat
{
/// <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);
/* 以 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()
{
OutTradeNumber = orderId,
@ -34,16 +39,10 @@ namespace HuanMeng.MiaoYu.Code.Payment.WeChat
if (response.IsSuccessful())
{
var paramMap = client.GenerateParametersForAppPayRequest(request.AppId, response.PrepayId);
Console.WriteLine("PrepayId" + response.PrepayId);
//Console.WriteLine("PrepayId" + response.PrepayId);
return new(orderId, JsonConvert.SerializeObject(paramMap));
}
throw new Exception("微信下单失败");
}
private string GenerateTimestampIdWithOffset()
{
var timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(); // 获取Unix时间戳毫秒
var random = new Random().Next(1000, 9999); // 生成四位随机数
return $"WX0{timestamp}J001C{random}";
}
}
}

View File

@ -31,8 +31,8 @@ namespace HuanMeng.MiaoYu.WebPayApi.Controllers
/// ${tenant}/zfb/${orderId}
/// </summary>
/// <returns></returns>
[HttpPost("{tenant?}/{pay?}/{orderId?}")]
public async Task<string> Post(string? tenant, string? pay, string? orderId)
[HttpPost("{tenant?}/{pay?}/{orderId?}/{sign?}")]
public async Task<string> Post(string? tenant, string? pay, string? orderId,string? sign)
{
var context = httpContextAccessor.HttpContext;
context.Request.EnableBuffering(); // Enable buffering to allow the body to be read multiple times