找回密码
 立即注册
首页 资源区 代码 微信小程序 B2B支付程序C#、.NET

微信小程序 B2B支付程序C#、.NET

123qwe 2025-5-28 22:07:23
这里只贴出支付的操作,如果 需要其它方法(退款、查询 、关闭订单等)可以发邮件9067874006@qq.com。
需要准备的参数
AppID(小程序ID):wx7405------------9e7d
B2B商户号:17-------637
沙箱AppKey:NYf9s-----------------TvgXGCVqf  现网AppKey:HcRiLtJa------------------MBoOru
appSecret :获取access_token时使用
session_Key:微信小程序登录时获取的
 
请求对象类
/// 
    /// 创建订单请求对象
    /// 
    public class WxB2bOrderReques
    {
        /// 
        /// 单位分
        /// 
        public decimal Price { get; set; }
        /// 
        /// 订单号
        /// 
        public string Out_trade_no { get; set; }
        /// 
        /// 商品描述
        /// 
        public string Description { get; set; }
    }
    /// 
    /// 退款请求对象
    /// 
    public class RefundRequestModel
    {
        /// 
        /// 商户订单号
        /// 
        public string out_trade_no { get; set; }
        /// 
        /// 退款金额(分)
        /// 
        public decimal refund { get; set; }
        /// 
        /// 退款来源,枚举值 1:人工客服退款   2:用户自己退款   3:其他
        /// 
        public int refund_from { get; set; }
        /// 
        /// 退款订单号
        /// 
        public string out_refund_no { get; set; }
}
响应对象类
 public class BaseResponse
    {
        /// 
        /// 0表示成功
        /// 
        public int errcode { get; set; }
        public string errmsg { get; set; }
    }
    /// 
    /// 退款响应对象
    /// 
    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;
            }
        }
    }
    /// 
    /// 创建订单响应类
    /// 
    public class CreateOrderRespones
    {
        /// 
        /// 支付签名
        /// 
        public string paySign { get; set; }
        /// 
        /// 用户状态签名
        /// 
        public string signature { get; set; }
        /// 
        /// 签名数据
        /// 
        public string signData { get; set; }
        /// 
        /// 支付类型
        /// 支付类型,不同mode的signData不同,B2b支付固定填retail_pay_goods
        /// 示例值:retail_pay_goods
        /// 
        public string mode { get; set; }
    }
B2b配置类
/// 
    /// 配置类
    /// 
    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;
        }
 /// 
        /// 获取支付签名
        /// 
        /// 
        /// uri,切记不可带参数,即去掉"?"及后面的部分
        /// 如果是基础库的wx.requestCommonPayment,uri固定为requestCommonPayment
        /// 其它的 举例:对于https://api.weixin.qq.com/retail/B2b/getorder 来说,uri = /retail/B2b/getorder
        ///  
        /// 
        public string GetPaySign(string uri, string postdata)
        {
            string data = string.Concat(uri, "&", postdata);
            return HmacSHA256(data, payB2BConfig.AppKey);
        }
        /// 
        /// 获取用户签名
        ///  
        /// 
        /// 
        /// 
        public string GetSignature(string postdata)
        {
            return HmacSHA256(postdata, payB2BConfig.session_Key);
        }
  /// 引入  Org.BouncyCastle.Crypto
        /// 
        /// 
        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;
        }
/// 
        /// 引入  Org.BouncyCastle.Crypto
        /// 
        /// 
        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发起支付在服务端不需要请求微信的接口,只要根据参数生成相应的参数返回给微信小程序,然后由微信小程序带着参数进行发起支付。代码如下:
服务端(生成参数)
 /// 
        /// 下单
        /// 小程序接口 wx.requestCommonPayment(Object object)
        /// 
        /// 
        public CreateOrderRespones WxCreatePayOrder(WxB2bOrderReques reques)
        {
            string order_no = GetOrderNo("");
            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
            };
   }
  /// 
        /// 创建B2b支付订单
        /// 
        /// 
        public JsonResult RequestToB2bPay()
        { 
            string session_Key = Request["session_Key"];
            ApiResponeBase res = new ApiResponeBase();
            res.error = (int)ErrorEnum.Error;
            
            WeChatB2bPayServices payUtils = new WeChatB2bPayServices();
            payUtils.payB2BConfig = GetPayB2bConfig();
            payUtils.payB2BConfig.session_Key = session_Key;
            string orderNo = payUtils.GetOrderNo("");
             
            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:"OST",
      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 == "requestCommonPaymentk"){
                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。
        /// 
        /// 以下地址设置到 微信小程序 消息通知中
        /// 
        /// 
        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(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();
        }

来源:新程序网络收集,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册