# wxpay **Repository Path**: tedi/wxpay ## Basic Information - **Project Name**: wxpay - **Description**: 微信支付接口 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 36 - **Forks**: 10 - **Created**: 2015-12-01 - **Last Updated**: 2023-04-19 ## Categories & Tags **Categories**: weixin-dev, payment-dev **Tags**: None ## README ##还是有问题,本行为测试 ##基于nodejs微信支付接口 本人初学nodejs,代码可能有诸多不完善的地方,请大家多多指教。 QQ:85920312 Email:tedi3231@qq.com ####微信支付提供三种方式: --- - 公众号支付 此场景主要针对有公众号的用户,商户拥有H5的商城网站,用户在页面中下单并调用微信端付款完成购买 - 扫码支付 商户根据微信支付规则,为不同商品生成不同的二维码,展示在各种场景,用于用户扫描购买,如PC网站集成的付款方式中可以使用微信扫码支付 - 刷卡支付 这个没有太深入研究,在全家等商店使用的微信付款即为此方式 ####本接口除实现公众号支付和扫码支付外还提供下面的功能: --- - 企业付款 提供企业向用户付款的功能,支付企业通过API接口付款,或通过微信支付商户平台网页功能操作付款 - 现金红包 暂未实现 - 代金券或立减优惠 暂未实现 #### 支付接口基本使用说明 ---- ###### 微信支付开发过程中遇到的问题做下总结: 1. 就是官方的文档不够详尽,如以XML方式提交参数而非JSON,返回值同样是XML而非JSON,开始走了不少弯路。 2. 签名的生成,其实这块也还好,但一定要注意参数是严格区分大小的,且值为空的参数不参加计算。 3. 各种token和ticket的获取容易让人混淆,加再上前后端参数不一致,抓狂是正常的 4. 很多同学所以调用不成功的另外一个原因是在公众平台中没有将公众号支付的开发配置项调好,尤其是支付授权目录,如果没有设置正确就可能出现无法支付成功的情况 5. 测试过程中有同学会将openid写死,嘎嘎,我也是其中之一,自己测试支付完全没问题,但发给其他人支付的时候一直会提示绑定银行卡 ###### 接口初始化
var config = {
	appid:"XXXX", //公众号Id
	mch_id:"XXX",	//商户号
	partner_key:"XXX", //这个是API密钥,一定要小心,必须为32位的字符,很多时候失败都是此参数设置错误
	cert:"certs/apiclient_cert.pem",	//如果需退款、企业付款等功能,证书是必须的,这两个参数都需要设置
	cert_key:"certs/apiclient_key.pem"
};
var api = new require("./index")(config);
接口中大部分函数都是返回promise,请使用下面的方式编写:
api.function1(参数).then(function(data){
	//调用成功后代码
}).fail(function(err){
	//调用失败后代码
});
**注意点** 下面的接口参数中显示需要下面参数的都不需要设置: * appid * mch_id * nonce_str * sign ###### 统一下单 除被扫支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再按扫码、JSAPI、APP等不同场景生成交易串调起支付。更多的参数请参考[微信开发文档](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)。
function test_unifiedorder(){
	var order_item = {
		notify_url:"http://wedo.avosapps.com/order/aa.php",
		openid:"opmukt4SZzas_TinMqpT5JkC3z6Q",
		out_trade_no:Number.parseInt(Math.random()*1000000),//请在业务系统中保证其唯一,正常情况下应为订单编号
		spbill_create_ip:"14.23.150.211",
		total_fee:1,			//此处以分为单位
		trade_type:"NATIVE",	//可以为JSAPI(公众号中调用JSSDK付款时)、NATIVE(网页扫码时也是此类型)、APP
		body:"aavv"				//商品描述
	};
	api.unifiedorder(order_item).then(function(data){
		console.log(data);
	}).fail(function(err){
		console.log(err);
	});
}
test_unifiedorder();
###### 查询订单 该接口提供所有微信支付订单的查询,商户可以通过该接口主动查询订单状态,完成下一步的业务逻辑。 需要调用查询接口的情况: * 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知; * 调用支付接口后,返回系统错误或未知交易状态情况; * 调用被扫支付API,返回USERPAYING的状态; * 调用关单或撤销接口API之前,需确认支付状态; 具体参数和返回值请参看[微信开发文档](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2) 此处只能查询单个记录,并批量查询功能,主要是根据微信订单号或商户订单号来查询,参数一为微信订单号,参数二为商户订单号,二者有一即可。
var params = {transaction_id:"1005450053201511261776573190"};
//var params = {out_trade_no:"239023900392"};
api.orderquery(params).then(function(data){
	console.log(data);
}).fail(function(err){
	console.log(err);
});
###### 关闭订单 以下情况需要调用关单接口:商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。 **注意:订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟。** 具体参数和返回值请参看[微信开发文档](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_3) 参数为**商户订单号**。
var params = {out_trade_no:"35370664"};
api.closeorder(params).then(function(data){
	console.log(data);
}).fail(function(err){
	console.log(err);
});
###### 申请退款 当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,微信支付将在收到退款请求并且验证成功之后,按照退款规则将支付款按原路退到买家帐号上。 **注意:** 1. 交易时间超过一年的订单无法提交退款; 2. 微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。一笔退款失败后重新提交,要采用原来的退款单号。总退款金额不能超过用户实际支付金额。 **注意:订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟。** 具体参数和返回值请参看[微信开发文档](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4)
	var params = {
		device_info:"WEB",
		transaction_id:"1005270053201511261778229445",
		out_refund_no:"REFUND0001",
		total_fee:1,
		refund_fee:1,
		refund_fee_type:"CNY",
		op_user_id:"1289247501"
	};	
	api.refund(params).then(function(data){
		console.log("refund data is ", data);
	}).fail(function(err){
		console.log("refund erro is",err);
	});
###### 查询退款 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。具体参数和返回值请参看[微信开发文档](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5) 。
var params = {
		device_info:"WEB",
		transaction_id:"1005270053201511261778229445",
		out_refund_no:"REFUND0001",
	};	
	api.refund(params).then(function(data){
		console.log("refundquery data is ", data);
	}).fail(function(err){
		console.log("refundquery erro is",err);
	});
###### 企业付款 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。 比如目前的保险行业向客户退保、给付、理赔。 企业付款将使用商户的可用余额,需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“[资金管理](https://pay.weixin.qq.com/)”进行操作。 **注意:与商户微信支付收款资金并非同一账户,需要单独充值。且需要双向证书。** 具体参数和返回值请参看[微信开发文档](https://pay.weixin.qq.com/wiki/doc/api/mch_pay.php?chapter=14_2) 。
var params = {
		device_info:"mac",
		partner_trade_no:"202143344343",
		openid:"opmukt4SZzas_TinMqpT5JkC3z6Q",
		check_name:"NO_CHECK",
		amount:101,
		desc:"理赔",
		spbill_create_ip:"192.168.0.1"
	};	
	api.company_transfers(params).then(function(data){
		console.log("company_transfers data",data);	
	}).fail(function(err){
		console.log("Company transfers error",err);
	});
###### 查询企业付款 用于商户的企业付款操作进行结果查询,返回付款操作详细结果。 具体参数和返回值请参看[微信开发文档](https://pay.weixin.qq.com/wiki/doc/api/mch_pay.php?chapter=14_3) 。
	var params = {
		partner_trade_no:"202143344343"
	};	
	api.company_get_transfers(params).then(function(data){
		console.log("company_get_transfers data",data);	
	}).fail(function(err){
		console.log("Company get transfers error",err);
	});
### 公众号支付 --- 公众号支付的主要流程如下: 用户进入公众号页面---> 提交订单 --> 业务系统生成订单 --> 调用微信统一下单接口 --> 返回预付订单信息prepay_id--> 生成供前端JS调用的对象并签名 --> 调用微信支付控件 --> 返回商户页面,显示购买成功。具体流程可参考此图: ![image](https://pay.weixin.qq.com/wiki/doc/api/img/chapter7_4_1.png) 1. 业务系统生成订单 此处可以没有,也可以放在微信统一下单动作之后,即本地业务系统的订单。我们先按放在统一下单前的方式操作。 2. 微信统一下单接口 在微信支付三种方式中都需要先调用统一下单接口在微信端生成预订单,这里需要注意此时在商户平台的交易订单中不会出现此预订单。提交预订单的代码如下:
	var order_item = {
		notify_url:"http://wedo.avosapps.com/order/succ",
		openid:"opmukt4SZzas_TinMqpT5JkC3z6Q",
		out_trade_no:Number.parseInt(Math.random()*1000000),
		spbill_create_ip:"14.23.150.211",
		total_fee:1,
		trade_type:"JSAPI",
		body:"aavv"
	};
	api.unifiedorder(order_item).then(function(data){
		console.log(data);
	}).fail(function(err){
		console.log(err);
	});
	
**注意点:** * openid 为当前用户在此公众号中的openid; * out_trade_no:如果是先调用的业务系统则应该是业务系统中的订单号; * trade_type 此处必须为"JSAPI"; * 具体参数请参阅微信支付的 [官方文档](https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1) 3. 生成prepay_id,生成前端JS调用的对象并签名 使用express的WEB示例代码如下,前端代码如下,请将下列代码放在script标签中,另外需要引用JSSDK的"http://res.wx.qq.com/open/js/jweixin-1.0.0.js":
        wx.config({
            debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
            appId: 'wxbd626ed750b05e5f', // 必填,公众号的唯一标识
            timestamp: '<%= timestamp%>', // 必填,生成签名的时间戳
            nonceStr: '<%= nonceStr%>', // 必填,生成签名的随机串
            signature: '<%= signature%>',// 必填,签名,见附录1
            jsApiList: [
                "chooseImage",
                "chooseImage",
                "uploadImage",
                "downloadImage",
				  "getBrandWCPayRequest"
            ] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
        });
        wx.ready(function(){
            console.log("wx ready function called!");
            var btn = document.getElementById("weixin");
            btn.onclick = function(){
                wx.chooseImage({
                    success:function(res){
                        var localIds = res.localIds;
                        alert(localIds);
                    }
                });
            };
        });
        wx.error(function(){
            console.log("wx init error ");
        });
        function onBridgeReady(){
           WeixinJSBridge.invoke(
               'getBrandWCPayRequest', {
                   "appId":"<%= pay_item.appId %>",//公众号名称,由商户传入     
                   "timeStamp":"<%= pay_item.timeStamp %>",//时间戳,自1970年以来的秒数     
                   "nonceStr":"<%= pay_item.nonceStr %>", //随机串     
                   "package":"<%= pay_item.package %>",     
                   "signType":"<%= pay_item.signType %>",         //微信签名方式:     
                   "paySign":"<%= pay_item.paySign %>" //微信签名 
               },
               function(res){    
                   alert(res); 
                   if(res.err_msg == "get_brand_wcpay_request:ok" ) {}     // 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回    ok,但并不保证它绝对可靠。 
               }
           ); 
        }
        if (typeof WeixinJSBridge == "undefined"){
           if( document.addEventListener ){
               document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
           }else if (document.attachEvent){
               document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
               document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
           }
        }else{
           onBridgeReady();
        }
	
后端代码:
	router.get("/pay/order2",function(req,res,next){
    var item = {title:"order",message:"demo"};
    var signURL = "http://" + req.hostname + req.url ;
    mywx.get_ticket(signURL).then(function(jsapi_ticket){
    //console.log("get_ticket result is ", jsapi_ticket );
        var ret = helper.get_ticket_sign(jsapi_ticket,signURL);
        //console.log("ret is ",ret);
        ret.title = "Wechat pay";
        ret.message = "hwhahaha";
        var order_item = {
            notify_url:"http://wedo.avosapps.com/pay/succ",
            openid:req.session.openid,
            out_trade_no:Number.parseInt(Math.random()*100000000),
            spbill_create_ip:"0.0.0.0",//req.connection.remoteAddress,
            total_fee:1,
            trade_type:"JSAPI",
            body:"hahahah"
        };
        payapi.unifiedorder(order_item).then(function(data){
            console.log("unifiedorder data is ",data);
            ret.pay_item = data;
            console.log("ret is %s",ret);
            res.render("order",ret);
        }).fail(function(err){
            console.log(err);
            next();
        });
  		});
	});
	
**注意点:** * 因为需要调用JSSDK,所以需要在每个需要调用JSSDK的页面获取TICKET信息,具体请参看jssdk的调用设置;另外对于 token和ticket的获取提供了另外一个模块wxapi.js文件,其中有ticket和token的获取的方法。此模块功能还不完善,仅供参考。 4. 调用微信支付控件,输入密码,付款成功 ### 扫码支付