这里只贴出支付的操作,如果 需要其它方法(退款、查询 、关闭订单等)可以发邮件9067874006@qq.com。
需要准备的参数
AppID(小程序ID):wx7405————9e7d
B2B商户号:17——-637
沙箱AppKey:NYf9s—————–TvgXGCVqf 或 现网AppKey:HcRiLtJa——————MBoOru
appSecret :获取access_token时使用
session_Key:微信小程序登录时获取的
请求对象类
/// <summary>
/// 创建订单请求对象
/// </summary>
public class WxB2bOrderReques
{
/// <summary>
/// 单位分
/// </summary>
public decimal Price { get; set; }
/// <summary>
/// 订单号
/// </summary>
public string Out_trade_no { get; set; }
/// <summary>
/// 商品描述
/// </summary>
public string Description { get; set; }
}
/// <summary>
/// 退款请求对象
/// </summary>
public class RefundRequestModel
{
/// <summary>
/// 商户订单号
/// </summary>
public string out_trade_no { get; set; }
/// <summary>
/// 退款金额(分)
/// </summary>
public decimal refund { get; set; }
/// <summary>
/// 退款来源,枚举值 1:人工客服退款 2:用户自己退款 3:其他
/// </summary>
public int refund_from { get; set; }
/// <summary>
/// 退款订单号
/// </summary>
public string out_refund_no { get; set; }
}
响应对象类
public class BaseResponse
{
/// <summary>
/// 0表示成功
/// </summary>
public int errcode { get; set; }
public string errmsg { get; set; }
}
/// <summary>
/// 退款响应对象
/// </summary>
public class RefundResponseModel: BaseResponse
{
public string refund_id { get; set; }
public string out_refund_no { get; set; }
public string order_id { get; set; }
public string out_trade_no { get; set; }
public string data { get; set; }
public bool IsApplySuccess {
get
{
return errcode == 0;
}
}
}
/// <summary>
/// 创建订单响应类
/// </summary>
public class CreateOrderRespones
{
/// <summary>
/// 支付签名
/// </summary>
public string paySign { get; set; }
/// <summary>
/// 用户状态签名
/// </summary>
public string signature { get; set; }
/// <summary>
/// 签名数据
/// </summary>
public string signData { get; set; }
/// <summary>
/// 支付类型
/// 支付类型,不同mode的signData不同,B2b支付固定填retail_pay_goods
/// 示例值:retail_pay_goods
/// </summary>
public string mode { get; set; }
}
B2b配置类
/// <summary>
/// 配置类
/// </summary>
public class PayB2bConfig
{
public string appid { get; set; }
public string appSecret { get; set; }
public string mchid { get; set; }
public string AppKey = “”;
public string session_Key = “”;
public string baseUrl = “https://api.weixin.qq.com”;
}
公共方法
#region
public string GetOrderNo(String Tag)
{
string strOrderNo = Tag + DateTime.Now.ToString(“yyyyMMddHHmmssfff”) + GenerateNonceStr();
return strOrderNo;
}
public string GenerateNonceStr()
{
return GetRandomUInt().ToString();
}
public uint GetRandomUInt()
{
var randomBytes = GenerateRandomBytes(sizeof(uint));
return BitConverter.ToUInt32(randomBytes, 0);
}
private byte[] GenerateRandomBytes(int bytesNumber)
{
RNGCryptoServiceProvider csp = new RNGCryptoServiceProvider();
byte[] buffer = new byte[bytesNumber];
csp.GetBytes(buffer);
return buffer;
}
/// <summary>
/// 获取支付签名
/// </summary>
/// <param name=”requestCommonPayment”>
/// uri,切记不可带参数,即去掉”?”及后面的部分
/// 如果是基础库的wx.requestCommonPayment,uri固定为requestCommonPayment
/// 其它的 举例:对于https://api.weixin.qq.com/retail/B2b/getorder 来说,uri = /retail/B2b/getorder</param>
/// <param name=”postdata”></param>
/// <returns></returns>
public string GetPaySign(string uri, string postdata)
{
string data = string.Concat(uri, “&”, postdata);
return HmacSHA256(data, payB2BConfig.AppKey);
}
/// <summary>
/// 获取用户签名
/// </summary>
/// <param name=”postdata”></param>
/// <param name=”session_key”></param>
/// <returns></returns>
public string GetSignature(string postdata)
{
return HmacSHA256(postdata, payB2BConfig.session_Key);
}
/// 引入 Org.BouncyCastle.Crypto
/// </summary>
/// <returns></returns>
public static string HmacSHA256(string message, string key)
{
byte[] keyBytes = Encoding.UTF8.GetBytes(key); // 使用你的密钥
byte[] messageBytes = Encoding.UTF8.GetBytes(message); // 要认证的消息
IMac hmac = new HMac(new Sha256Digest()); // 创建 HMAC-SHA256 实例
hmac.Init(new KeyParameter(keyBytes)); // 初始化 HMAC 实例,设置密钥
hmac.BlockUpdate(messageBytes, 0, messageBytes.Length); // 更新消息
byte[] result = new byte[hmac.GetMacSize()]; // 获取 HMAC 的大小
hmac.DoFinal(result, 0); // 计算最终的 HMAC 值
string hmacHex = BitConverter.ToString(result).Replace(“-“, “”).ToLower(); // 将结果转换为十六进制字符串
return hmacHex;
}
/// <summary>
/// 引入 Org.BouncyCastle.Crypto
/// </summary>
/// <returns></returns>
public static string Sha1Encrypt(string input)
{
byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
// 创建SHA1摘要对象
IDigest digest = new Sha1Digest();
// 更新摘要对象以包含输入数据
digest.BlockUpdate(inputBytes, 0, inputBytes.Length);
// 计算哈希值
byte[] hash = new byte[digest.GetDigestSize()];
digest.DoFinal(hash, 0);
// 将哈希值转换为十六进制字符串
string hashString = Hex.ToHexString(hash);
return hashString;
}
#endregion
1、B2B发起支付
B2B发起支付在服务端不需要请求微信的接口,只要根据参数生成相应的参数返回给微信小程序,然后由微信小程序带着参数进行发起支付。代码如下:
服务端(生成参数)
/// <summary>
/// 下单
/// 小程序接口 wx.requestCommonPayment(Object object)
/// </summary>
/// <returns></returns>
public CreateOrderRespones WxCreatePayOrder(WxB2bOrderReques reques)
{
string order_no = GetOrderNo(“P”);
var postData = new
{
mchid = payB2BConfig.mchid,
out_trade_no = order_no,
description = reques.Description,
env = 0,
amount = new
{
order_amount = Convert.ToInt32(reques.Price * 100) //单位为分
}
};
string jsonEncoding = Newtonsoft.Json.JsonConvert.SerializeObject(postData);
string paySign = GetPaySign(“requestCommonPayment”, jsonEncoding);
string signature = GetSignature(jsonEncoding);
//获取参数后返回给微信小程序
return new CreateOrderRespones()
{
mode = “retail_pay_goods”,
paySign = paySign,
signature = signature,
signData = jsonEncoding
};
}
/// <summary>
/// 创建B2b支付订单
/// </summary>
/// <returns></returns>
public JsonResult RequestToB2bPay()
{
string session_Key = Request[“session_Key”];
ApiResponeBase<CreateOrderRespones> res = new ApiResponeBase<CreateOrderRespones>();
res.error = (int)ErrorEnum.Error;
WeChatB2bPayServices payUtils = new WeChatB2bPayServices();
payUtils.payB2BConfig = GetPayB2bConfig();
payUtils.payB2BConfig.session_Key = session_Key;
string orderNo = payUtils.GetOrderNo(“P”);
WxB2bOrderReques wxOrderReques = new WxB2bOrderReques()
{
Description = “商品订单支付”,
Out_trade_no = orderNo ,
Price = 10 –单位分
};
CreateOrderRespones response = payUtils.WxCreatePayOrder(wxOrderReques);
res.error = (int)ErrorEnum.Success;
res.data = response;
res.msg = “创建支付订单成功!”;
return Json(res, JsonRequestBehavior.AllowGet);
}
微信小程序端
const RequestToB2bPay=(session_Key)=>{
return new Promise((resove,reject)=>{
httpUitls.httpAjax({
url:”WChatApi/WeChatB2bPayInfo/RequestToB2bPay”,
data:{session_Key:session_Key},
method:”POST”,
contentType:”FORM”,
callBack:function(res){
let paymentData = res.data
if (res.error == 0){
wx.requestCommonPayment({
mode:paymentData.mode,
signData:paymentData.signData,
paySig:paymentData.paySign,
signature:paymentData.signature,
success(res) {
if(res.errMsg == “requestCommonPayment:ok”){
resove({isPayed:true,errMsg:”支付成功!”});
}else{
resove({isPayed:false,errMsg:”支付失败!”+res.errMsg});
}
},
fail(res) {
reject({isPayed:false,errMsg:”支付失败!”+res.errMsg});
}
});
}else{
reject(“支付失败,请联系管理员”);
}
}
})
});
}
支付通知
//举例:假设填写的URL=”https://www.qq.com/revice”, Token=”AAAAA”。
//推送的URL链接:https://www.qq.com/revice?signature=f464b24fc39322e44b38aa78f5edd27bd1441696&echostr=4375120948345356249×tamp=1714036504&nonce=1514711492
//将token、timestamp、nonce三个参数进行字典序排序,排序后结果为:[“1514711492″,”1714036504″,”AAAAA”]。
//将三个参数字符串拼接成一个字符串:”15147114921714036504AAAAA”
//进行sha1计算签名:f464b24fc39322e44b38aa78f5edd27bd1441696
//与URL链接中的signature参数进行对比,相等说明请求来自微信服务器,合法。
//构造回包返回微信,回包消息体内容为URL链接中的echostr参数4375120948345356249。
/// <summary>
/// 以下地址设置到 微信小程序 消息通知中
/// </summary>
/// <returns></returns>
public string ReceiveNotifyByNoEncrypt()
{
string Toke = “7302366f3b4d———a70618c50a3”;//与 小程序后台 「开发管理」-「消息推送配置」设置TOKEN一致
string signature = Request[“signature”];
string timestamp = Request[“timestamp”];
string nonce = Request[“nonce”];
string echostr = Request[“echostr”];
string[] array = new string[] { Toke, timestamp, nonce };
Array.Sort(array);
string sign = Cryptography.Sha1Encrypt(string.Join(“”, array));
if (sign == signature && !string.IsNullOrEmpty(echostr))
{
return echostr;
}
//一、读取接口请求通知的内容
string notifyData = WB.BASE.COMMON.HttpServerInteface.GetInputStream();
WriteNotityLog(notifyData);
//未读取到请求内容,返回错误响应
if (string.IsNullOrEmpty(notifyData))
return “fail”;
//二、获取请求参数 作为第四名步解密使用
dynamic dynamicObj = JsonConvert.DeserializeObject<dynamic>(notifyData);
if (dynamicObj.Event == “retail_pay_notify” && dynamicObj.pay_status == “ORDER_PAY_SUCC”)
{
string order = dynamicObj.out_trade_no;
//支付成功
}
if (dynamicObj.Event == “retail_refund_notify”)
{
string out_refund_no = dynamicObj.out_refund_no;
string out_trade_no = dynamicObj.out_trade_no;
//退款成功
}
return “success”;
}
public static String GetInputStream()
{
//接收从微信后台POST过来的数据
System.IO.Stream s = System.Web.HttpContext.Current.Request.InputStream;
int count = 0;
byte[] buffer = new byte[1024];
StringBuilder builder = new StringBuilder();
while ((count = s.Read(buffer, 0, 1024)) > 0)
{
builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
}
s.Flush();
s.Close();
s.Dispose();
return builder.ToString();
}