nodejs-wechatpay
Version:
微信支付 服务商版本,普通商户版本 nodejs 接口实现 wechatpay apiv2 支付回调
570 lines (564 loc) • 18.4 kB
JavaScript
const lib = require("./paylib.js").lib
const request = require("request");
const {
sign,
sign256Xml,
signXml,
randomStr,
} = lib
const fs = require('fs');
var xml2js = require('xml2js');
var xmlParser = new xml2js.Parser({explicitArray : false, ignoreAttrs : true});
class WechatPayPartner {
constructor(opt){
this.appid = opt.appid;
this.mch_id = opt.mch_id;
this.key = opt.key;
this.sub_appid = opt.sub_appid;
this.sub_mch_id = opt.sub_mch_id;
this.notify_url = opt.notify_url;
this.profit_sharing = opt.profit_sharing || 'N' //默认不分账
this.cert = fs.readFileSync(opt.cert); //fs.readFileSync( '/apiclient_cert.p12');
this.ip = opt.ip || "8.8.8.8",
this.debug = opt.debug || false;
};
setDebug(debug){
this.debug = debug;
}
setOptions(opt){
for(let key in opt){
this[key] = opt[key]
}
}
unifiedorder(opt,success,complete){
let url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
let out_trade_no = opt.out_trade_no || randomStr();
let {body,openid,notify_url} = opt;
let money = parseInt(opt.money * 100);
let nonce_str = randomStr();
let params ={
appid: this.appid,
mch_id:this.mch_id,
sub_mch_id:this.sub_mch_id,
nonce_str:nonce_str,
sign_type:"MD5",
body:body,
out_trade_no:out_trade_no,
total_fee:money,
spbill_create_ip:this.ip,
notify_url: notify_url || this.notify_url,
trade_type:opt.trade_type || "JSAPI",
profit_sharing:opt.profit_sharing || this.profit_sharing
}
if(this.sub_appid){
params.sub_appid = this.sub_appid;
params.sub_openid = openid;
}else{
params.openid = openid;
}
let xml = signXml(params,this.key)
let appid = this.appid;
if(this.sub_appid){
appid = this.sub_appid;
}
let {fall} = opt;
if(!complete) complete = opt.complete;
if(!success) success = opt.success;
let key = this.key;
let that = this;
function paySign(xml){
xml = that.jsapi_paySign(xml,key,appid,out_trade_no)
success(xml);//sen
}
this.doTheReq(url,xml,paySign,fall,complete);
}
jsapi_paySign(xml,key,appid,out_trade_no){
let params = {
'timeStamp': parseInt(new Date().getTime()/1000).toString() ,
'nonceStr': randomStr(),
'package': "prepay_id=" + xml.prepay_id,
'signType': 'MD5',
'appId':appid
}
params = sign(params,"paySign",key);
delete params['appId'];
params.out_trade_no = out_trade_no;
xml.jsapi_sign = params;
return xml;//send
}
payNative(opt,complete){
opt.trade_type = 'NATIVE'
this.unifiedorder(opt,complete)
}
pay(opt,complete){
this.unifiedorder(opt,complete)
}
doTheReq(url,xml,success,fall,complete){
let option = {
url: url,
method: "POST",
body: xml,
agentOptions: {
pfx: this.cert,
passphrase: this.mch_id
}
}
if(this.debug) console.log('request sending:',xml);
request(option,function(err,req,body){
if(this.debug) console.log('request return:',body);
xmlParser.parseString(body, function (err, result) {
if(!result){
if(success) success(body);
if(complete) complete(body);
return;
}
let result_code = result && result.xml && result.xml.result_code
let return_code = result && result.xml && result.xml.return_code
if( return_code == 'FAIL' || result_code == 'FAIL'){
if(fall) fall(result.xml);
}else{
if(success) success(result.xml);
}
if(complete) complete(result.xml);
});
});
}
micropay(opt,complete){
/* 收银员使用扫码设备读取微信用户付款码以后,二维码或条码信息会传送至商户收银台,由商户收银台或者商户后台调用该接口发起支付。
提醒1:提交支付请求后微信会同步返回支付结果。当返回结果为“系统错误”时,商户系统等待5秒后调用【查询订单API】,查询支付实际交易结果;当返回结果为“USERPAYING”时,
商户系统可设置间隔时间(建议10秒)重新查询支付结果,直到支付成功或超时(建议45秒);
提醒2:在调用查询接口返回后,如果交易状况不明晰,请调用【撤销订单API】,此时如果交易失败则关闭订单,该单不能再支付成功;如果交易成功,则将扣款退回到用户账户。
当撤销无返回或错误时,请再次调用。注意:请勿调用扣款后立即调用【撤销订单API】,建议至少15s后再调用。撤销订单API需要双向证书。*/
let url = 'https://api.mch.weixin.qq.com/pay/micropay'
let out_trade_no = opt.out_trade_no || randomStr();
let auth_code = opt.auth_code;
let body = opt.body || randomStr();
let money = parseInt(opt.money * 100);
let nonce_str = randomStr();
let params ={
appid: this.appid,
mch_id:this.mch_id,
sub_appid:this.sub_appid,
sub_mch_id:this.sub_mch_id,
nonce_str:nonce_str,
sign_type:"MD5",
body:body,
out_trade_no:out_trade_no,
total_fee:money,
spbill_create_ip:this.ip,
notify_url:this.notify_url,
auth_code:auth_code,
profit_sharing:opt.profit_sharing || this.profit_sharing
}
let xml = signXml(params,this.key);
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
sendredpack(opt,complete){
let url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
let nonce_str = randomStr();
let {openid,money,out_trade_no,send_name,total_num,risk_info,scene_id} = opt;
money = parseInt(money * 100);
out_trade_no = out_trade_no || randomStr();
let params ={
wxappid: this.appid,
msgappid:this.sub_appid,
consume_mch_id:this.sub_mch_id,
mch_id:this.mch_id,
sub_mch_id:this.sub_mch_id,
nonce_str:nonce_str,
mch_billno:out_trade_no.substr(0,28),
send_name:send_name,
re_openid:openid,
act_name:opt.act_name || 'act_name',
remark:opt.remark || 'remark',
total_amount:money,
total_num:total_num ||1,
wishing:opt.wishing || 'wishing',
client_ip:this.ip,
}
if(risk_info){
params.risk_info = risk_info
}
if(scene_id){
params.scene_id = scene_id
}
let xml = signXml(params,this.key);
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
sendgroupredpack(opt,complete){
let url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack";
let nonce_str = randomStr();
let {openid,money,out_trade_no,send_name,total_num,risk_info,scene_id,amt_type} = opt;
money = parseInt(money * 100);
out_trade_no = out_trade_no || randomStr();
let params ={
wxappid: this.appid,
msgappid:this.sub_appid,
consume_mch_id:this.sub_mch_id,
mch_id:this.mch_id,
sub_mch_id:this.sub_mch_id,
nonce_str:nonce_str,
mch_billno:out_trade_no.substr(0,28),
send_name:send_name,
re_openid:openid,
act_name:opt.act_name || 'act_name',
remark:opt.remark || 'remark',
total_amount:money,
total_num:total_num ||1,
amt_type:amt_type || 'ALL_RAND',
wishing:opt.wishing || 'wishing',
client_ip:this.ip,
}
if(risk_info){
params.risk_info = risk_info
}
if(scene_id){
params.scene_id = scene_id
}
let xml = signXml(params,this.key);
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
gethbinfo(opt,complete){
let url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo";
let nonce_str = randomStr();
let {bill_type,money,out_trade_no} = opt;
money = parseInt(money * 100);
let params ={
appid: this.appid,
mch_id:this.mch_id,
nonce_str:nonce_str,
mch_billno:out_trade_no,
bill_type:bill_type,
}
let xml = signXml(params,this.key);
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
orderquery(opt,complete){
let {out_trade_no,transaction_id} = opt;
let url = "https://api.mch.weixin.qq.com/pay/orderquery";
let nonce_str = randomStr();
let params ={
appid:this.appid,
mch_id:this.mch_id,
sub_appid:this.sub_appid,
sub_mch_id:this.sub_mch_id,
nonce_str:nonce_str,
}
if(out_trade_no){
params.out_trade_no =out_trade_no
}
if(transaction_id){
params.transaction_id =transaction_id
}
let xml = signXml(params,this.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
closeorder(opt,complete){
let url = "https://api.mch.weixin.qq.com/pay/closeorder";
let out_trade_no = opt.out_trade_no;
let nonce_str = randomStr();
let params ={
appid:this.appid,
mch_id:this.mch_id,
sub_appid:this.sub_appid,
sub_mch_id:this.sub_mch_id,
nonce_str:nonce_str,
}
if(out_trade_no){
params.out_trade_no =out_trade_no
}
let xml = signXml(params,this.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
downloadBill(opt,complete){
let url = "https://api.mch.weixin.qq.com/pay/downloadbill";
let nonce_str = randomStr();
let billdate = opt.billdate;
let params ={
appid:this.appid,
sub_appid:this.sub_appid,
mch_id:this.mch_id,
sub_mch_id:this.sub_mch_id,
nonce_str:nonce_str,
sign_type:"HMAC-SHA256",
bill_date:billdate,
bill_type:"ALL"
}
let xml = sign256Xml(params,this.key);
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
refund(opt,complete){
let url = `https://api.mch.weixin.qq.com/secapi/pay/refund`;
let {total_fee,refund_fee,refund_desc,out_trade_no,notify_url} = opt;
let that = this;
let nonce_str = randomStr();
let out_refund_no = randomStr();
let params ={
appid:that.appid,
mch_id:that.mch_id,
sub_mch_id:that.sub_mch_id,
nonce_str:nonce_str,
out_trade_no:out_trade_no|| null,
transaction_id:transaction_id|| null,
out_refund_no:out_refund_no,
total_fee:total_fee,
refund_fee:refund_fee,
refund_desc:refund_desc,
notify_url:notify_url || this.notify_url,
}
let xml = signXml(params,this.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
refundquery(opt,complete){//查询退款
let url = `https://api.mch.weixin.qq.com/pay/refundquery`;
let {offset,refund_id,out_refund_no,out_trade_no,transaction_id} = opt;
let that = this;
let nonce_str = randomStr();
let params ={
appid:that.appid,
mch_id:that.mch_id,
sub_mch_id:that.sub_mch_id,
nonce_str:nonce_str,
out_trade_no:out_trade_no || null,
transaction_id:transaction_id|| null,
out_refund_no:out_refund_no|| null,
refund_id:refund_id || null,
offset:offset || null,
}
let xml = signXml(params,this.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
profitsharingaddreceiver(opt,complete){//添加分账接收方
let that = this;
let {receiver } = opt
let url = `https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver`;
let nonce_str = randomStr();
// let receiver = {
// type:'PERSONAL_OPENID',
// account:account,
// relation_type:'DISTRIBUTOR'
// }
receiver = JSON.stringify(receiver)
let params ={
appid:that.appid,
mch_id:that.mch_id,
sub_mch_id:that.sub_mch_id,
nonce_str:nonce_str,
receiver:receiver
}
let xml = sign256Xml(params,this.key);
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
profitsharingremovereceiver(opt,complete){//remove分账接收方
let that = this;
let { receiver} = opt
let url = `https://api.mch.weixin.qq.com/pay/profitsharingremovereceiver`;
let nonce_str = randomStr();
// let receiver = {
// type:'PERSONAL_OPENID',
// account:account,
// relation_type:'DISTRIBUTOR'
// }
receiver = JSON.stringify(receiver)
let params ={
appid:that.appid,
mch_id:that.mch_id,
sub_mch_id:that.sub_mch_id,
nonce_str:nonce_str,
receiver:receiver
}
let xml = sign256Xml(params,that.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
profitsharingfinish(opt,complete){//
let that = this;
let { transaction_id,description,brand_mch_id} = opt
let url = `https://api.mch.weixin.qq.com/secapi/pay/profitsharingfinish`;
let nonce_str = randomStr();
let out_order_no = randomStr();
let params ={
appid:that.appid,
mch_id:that.mch_id,
sub_mch_id:that.sub_mch_id,
transaction_id:transaction_id,
nonce_str:nonce_str,
out_order_no:out_order_no,
brand_mch_id:brand_mch_id || null,
description:description
}
let xml = sign256Xml(params,that.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
profitsharing(opt,complete){//单次分账
let that = this;
let { receivers,transaction_id,brand_mch_id} = opt
let url = `https://api.mch.weixin.qq.com/secapi/pay/profitsharing`;
let nonce_str = randomStr();
let out_order_no = randomStr();
// let receivers = [{
// "type": "PERSONAL_OPENID",
// "account":"o_FDOs_NZDWQMSeFnHkmEflQdD04",
// "amount":1,
// "description": "分到个人"
// }]
receivers = JSON.stringify(receivers)
let params ={
appid:that.appid,
mch_id:that.mch_id,
sub_mch_id:that.sub_mch_id,
brand_mch_id:brand_mch_id || null,
sub_appid:this.sub_appid || null,
transaction_id:transaction_id,
out_order_no:out_order_no,
nonce_str:nonce_str,
receivers:receivers
}
let xml = sign256Xml(params,that.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
multiprofitsharing(opt,complete){//多次词分账
let that = this;
let { receivers,transaction_id,brand_mch_id} = opt
let url = `https://api.mch.weixin.qq.com/secapi/pay/multiprofitsharing`;
let nonce_str = randomStr();
let out_order_no = randomStr();
// let receivers = [{
// "type": "PERSONAL_OPENID",
// "account":"o_FDOs_NZDWQMSeFnHkmEflQdD04",
// "amount":1,
// "description": "分到个人"
// }]
receivers = JSON.stringify(receivers)
let params ={
appid:that.appid,
mch_id:that.mch_id,
sub_mch_id:that.sub_mch_id,
brand_mch_id:brand_mch_id || null,
sub_appid:this.sub_appid || null,
transaction_id:transaction_id,
out_order_no:out_order_no,
nonce_str:nonce_str,
receivers:receivers
}
let xml = sign256Xml(params,that.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
profitsharingquery(opt,complete){//查询分账结果
let that = this;
let { transaction_id,out_order_no} = opt
let url = `https://api.mch.weixin.qq.com/secapi/pay/profitsharingquery`;
let nonce_str = randomStr();
let params ={
mch_id:that.mch_id,
sub_mch_id:that.sub_mch_id,
transaction_id:transaction_id,
nonce_str:nonce_str,
out_order_no:out_order_no
}
let xml = sign256Xml(params,that.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
profitsharingreturn(opt,complete){// 此功能需要接收方在商户平台-交易中心-分账-分账接收设置下,开启同意分账回退后,才能使用。
let that = this;
let { return_amount,description,out_order_no,return_account_type,order_id} = opt
let url = `https://api.mch.weixin.qq.com/secapi/pay/profitsharingreturn`;
let nonce_str = randomStr();
let params ={
mch_id:that.mch_id,
appid:that.appid,
sub_mch_id:that.sub_mch_id,
out_order_no:out_order_no || null,
order_id:order_id || null,
out_return_no: randomStr(),
return_account_type:return_account_type,
return_amount:return_amount,
description:description,
nonce_str:nonce_str,
}
let xml = sign256Xml(params,that.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
profitsharingreturnquery(opt,complete){//回退结果查询
let that = this;
let { order_id,out_return_no,out_order_no} = opt
let url = `https://api.mch.weixin.qq.com/pay/profitsharingreturnquery`;
let nonce_str = randomStr();
let params ={
mch_id:that.mch_id,
sub_mch_id: that.sub_mch_id,
order_id:order_id || null,
nonce_str:nonce_str,
out_return_no:out_return_no || null,
out_order_no:out_order_no || null,
}
let xml = sign256Xml(params,that.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
profitsharingmerchantratioquery(opt,complete){//查询最大分账比例API
let that = this;
let { transaction_id,brand_mch_id} = opt
let url = `https://api.mch.weixin.qq.com/pay/profitsharingmerchantratioquery`;
let nonce_str = randomStr();
let params ={
mch_id:that.mch_id,
sub_mch_id:(brand_mch_id && null ) == null || that.sub_mch_id,
transaction_id:transaction_id,
nonce_str:nonce_str,
brand_mch_id:brand_mch_id || null
}
let xml = sign256Xml(params,that.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
profitsharingorderamountquery(opt,complete){//服务商可通过调用此接口查询订单剩余待分金额。
let that = this;
let { transaction_id} = opt
let url = `https://api.mch.weixin.qq.com/pay/profitsharingorderamountquery`;
let nonce_str = randomStr();
let params ={
mch_id:that.mch_id,
transaction_id:transaction_id,
nonce_str:nonce_str,
}
let xml = sign256Xml(params,that.key)
let {success,fall} = opt;
if(!complete) complete = opt.complete;
this.doTheReq(url,xml,success,fall,complete)
}
}
module.exports = WechatPayPartner