Giter VIP home page Giter VIP logo

wechat-pay's Introduction

微信支付 for Nodejs

初始化

var Payment = require('wechat-pay').Payment;
var initConfig = {
  partnerKey: "<partnerkey>",
  appId: "<appid>",
  mchId: "<mchid>",
  notifyUrl: "<notifyurl>",
  pfx: fs.readFileSync("<location-of-your-apiclient-cert.p12>")
};
var payment = new Payment(initConfig);

所有参数都不是必须的,不过这样配置最省事。实际调用时候的参数若有同名会覆盖。

付个钱

var order = {
  body: '吮指原味鸡 * 1',
  attach: '{"部位":"三角"}',
  out_trade_no: 'kfc' + (+new Date),
  total_fee: 10 * 100,
  spbill_create_ip: req.ip,
  openid: req.user.openid,
  trade_type: 'JSAPI'
};

payment.getBrandWCPayRequestParams(order, function(err, payargs){
  res.json(payargs);
});

// 也可以使用`async/await`形式
// let payargs = await payment.getBrandWCPayRequestParams(order)

注:

  1. 页面的路径需要位于支付授权目录
  2. 由于每次呼出支付界面,无论用户是否支付成功,out_trade_no 都会失效(OUT_TRADE_NO_USED),所以这里使用timestamp保证每次的id不同。业务逻辑中应该自行维护之

前端通过

WeixinJSBridge.invoke('getBrandWCPayRequest', payargs, function(res){
  if(res.err_msg == "get_brand_wcpay_request:ok"){
    alert("支付成功");
    // 这里可以跳转到订单完成页面向用户展示
  }else{
    alert("支付失败,请重试");
  }
});

来呼出微信的支付界面

接收微信付款确认请求

var middleware = require('wechat-pay').middleware;
app.use('<notifyUrl>', middleware(initConfig).getNotify().done(function(message, req, res, next) {
  var openid = message.openid;
  var order_id = message.out_trade_no;
  var attach = {};
  try{
   attach = JSON.parse(message.attach);
  }catch(e){}

  /**
   * 查询订单,在自己系统里把订单标为已处理
   * 如果订单之前已经处理过了直接返回成功
   */
  res.reply('success');

  /**
   * 有错误返回错误,不然微信会在一段时间里以一定频次请求你
   * res.reply(new Error('...'))
   */
}));

退个款

payment.refund({
  out_trade_no: "kfc001",
  out_refund_no: 'kfc001_refund',
  total_fee: 10 * 100,
  refund_fee: 10 * 100
}, function(err, result){
  /**
   * 微信收到正确的请求后会给用户退款提醒
   * 这里一般不用处理,有需要的话有err的时候记录一下以便排查
   */
});

接收退款确认请求

var middleware = require('wechat-pay').middleware;
app.use('<notifyUrl>', middleware(initConfig).getRefundNotify().done(function(message, req, res, next) {
  var openid = message.openid;
  var refund_order_id = message.out_refund_no;
  var order_id = message.out_trade_no;
  var attach = {};
  try{
   attach = JSON.parse(message.attach);
  }catch(e){}

  /**
   * 查询订单,在自己系统里把订单标为已处理
   * 如果订单之前已经处理过了直接返回成功
   */
  res.reply('success');

  /**
   * 有错误返回错误,不然微信会在一段时间里以一定频次请求你
   * res.reply(new Error('...'))
   */
}));

发红包

payment.sendRedPacket({
  mch_billno: 'kfc002',
  send_name: '肯德基',
  re_openid: '',
  total_amount: 10 * 100,
  total_num: 1,
  wishing: '祝多多吃鸡',
  client_ip: '',
  act_name: '吃鸡大奖赛',
  remark: '记得吐骨头',
  scene_id: 'PRODUCT_1'
}, (err, result) => {
  /**
   * 微信收到正确的请求后会给用户发红包,用户不必关注公众号也能收到。
   * 红包没有通知回调,有需要的话标记订单状态,和有err的时候记录一下以便排查
   */
  });
});

查询红包状态

payment.redPacketQuery({
  mch_billno: 'kfc002'
}, (err, result) => {
  /**
   * 根据状态相应处理订单
   */
});

企业付款

payment.transfers({
  partner_trade_no: 'kfc003',
  openid: '',
  check_name: 'NO_CHECK',
  amount: 10 * 100,
  desc: '',
  spbill_create_ip: ''
}, (err, result) => {
  // 根据微信文档,当返回错误码为“SYSTEMERROR”时,一定要使用原单号重试,否则可能造成重复支付等资金风险。
});

查询历史订单

payment.downloadBill({
  bill_date: "20140913",
  bill_type: "ALL"
}, function(err, data){
  // 账单列表
  var list = data.list;
  // 账单统计信息
  var stat = data.stat;
});

错误处理

在回调的Error上的以name做了区分,有需要可以拿来做判断

  • ProtocolError 协议错误,看看有没有必须要传的参数没传
  • BusinessError 业务错误,可以从返回的data里面看看错误细节

wechat-pay's People

Contributors

gavin1990 avatar holymonson avatar kenspirit avatar loulin avatar supersheep avatar xjx5683 avatar xuming314 avatar yorkie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wechat-pay's Issues

签名错误

为什么总报,签名错误,核对了openid

给wechat-pay支持动态配置公众号参数

我们有这样的一个需求,有多个公众号商户,我们想可以同时使用,可不可以动态的配置支付配置参数?

还有paysignkey这个参数怎么没有呢?

如:

Basic.prototype.done = function (handler) {
  var self = this;
  var payment = self.payment;
  return function (req, res, next) {
///动态配置参数
    if (req.payConfig) {
      payment = new Payment(req.payConfig);
    }
    if (req.method !== 'POST') {
      var error = new Error();
      error.name = 'NotImplemented';
      return self.fail(error, res);
    }
    getRawBody(req, function (err, rawBody) {
      if (err) {
        err.name = 'BadMessage' + err.name;
        return self.fail(err, res);
      }
      payment.validate(rawBody, function(err, message){
        res.reply = function(data){
          if(data instanceof Error){
            self.fail(data, res);
          }else{
            self.success(data, res);
          }
        }

        if(err){
          return self.fail(err, res);
        }

        handler(message, req, res, next);
      });
    });
  };
};

请问在ThinkJS中怎么接收微信支付结果通知

readme示例中好像是基于express框架?

但是我用的是thinkjs框架,支付是成功了,

但是该怎么接收到微信推送的支付结果通知?

    async paybackAction() {
        let wxPayCfg = {
            // ....
        };

        middleware(wxPayCfg).getNotify().done((message, req, res, next)=>{
            console.log(message);
        });
    }

这样似乎不对。

退款申请遇到个问题

Error: Unable to load BIO
退款申请的时候node控制台报这个错,大神知道原因吗?是因为https的原因吗?

NATIVE 方式不显示code_url解决方法

在payment.js文件中找到Payment.prototype.getBrandWCPayRequestParams方法

Payment.prototype.getBrandWCPayRequestParams = function (order, callback) {
var self = this;
var default_params = {
appId: this.appId,
timeStamp: this._generateTimeStamp(),
nonceStr: this._generateNonceStr(),
signType: "MD5"
};

order = this._extendWithDefault(order, [
'notify_url'
]);

this.unifiedOrder(order, function (err, data) {
if (err) {
return callback(err);
}

var params = _.extend(default_params, {
  package: "prepay_id=" + data.prepay_id
});

params.paySign = self._getSign(params);
//=================================

 //这里要加一个判断,如果是NATIVE方式需要显示code_url,
if(order.trade_type="NATIVE"){
params.code_url=data.code_url;
}
//================================
callback(null, params);
});
};

egg 回调方法示例(koa应该也差不多)

  const xml2js = require('xml2js');

  const { ctx } = this;
  const order_id = ctx.params.id;
  function buildXml(obj) {
    const builder = new xml2js.Builder({ allowSurrogateChars: true });
    const xml = builder.buildObject({ xml: obj });
    return xml;
  };
  function buildJson(xml) {
    return new Promise((resolve, reject) => {
      const parser = new xml2js.Parser();
      parser.parseString(xml, (err, result) => {
        if (err) reject(err);
        resolve(result);
      });
    });
  }
  const body = await new Promise((resolve, reject) => {
    let data = '';
    ctx.req.on('data', (chunk) => {
       data += chunk;
    });
    ctx.req.on('end', async () => {
      const parsedData = await buildJson(data);
      resolve(parsedData);
    });
  });
  console.log(body); // body 即为解析后的json数据
  ctx.body = buildXml({
    return_code: 'SUCCESS',
  });

欢迎讨论有没有其他更简单的方法能直接拿到 rawBody ,一直没办法像文档里写的通过 ctx.request.rawBody 取得

另外回调url好像得同时支持 get 和 post 请求访问才行

建议去掉错误打印变成错误返回

// if (data.return_code == RETURN_CODES.FAIL) {
// error = new Error(data.return_msg);
// error.name = 'ProtocolError';
// } else if (data.result_code == RETURN_CODES.FAIL) {
// console.log("data.err_code======",data.err_code) ;
// error = data.err_code;
// error.name = 'BusinessError';
// } else if (data.appid && self.appId !== data.appid) {
// error = new Error();
// error.name = 'InvalidAppId';
// } else if (data.mch_id && self.mchId !== data.mch_id) {
// error = new Error();
// error.name = 'InvalidMchId';
// } else if (data.mchid && self.mchId !== data.mchid) {
// error = new Error();
// error.name = 'InvalidMchId';
// } else if (self.subMchId && self.subMchId !== data.sub_mch_id) {
// error = new Error();
// error.name = 'InvalidSubMchId';
// } else if (data.sign && self._getSign(data) !== data.sign) {
// error = new Error();
// error.name = 'InvalidSignature';
// }

注释掉这段即可

第一次支付都是返回undefined

payment.getBrandWCPayRequestParams(order, function(err, payargs){
res.json(payargs);
});

每次的第一次返回的payargs都是undefined,再次点击购买才能成功

为什么总是提示签名错误

我使用的参数是
var initConfig = {
partnerKey : "7***7",
appId : "wxb7**
766216",
mchId : "1281077801",
notifyUrl : "http://**
.
**.com/payment/notify",
pfx : fs.readFileSync("apiclient_cert.p12")
};

调用的接口是

var order = {
    body : '吮指原味鸡 * 1',
    attach : '{"部位":"三角"}',
    out_trade_no : 'kfc' + (Date.parse(new Date())),
    total_fee : 1,
    spbill_create_ip :  req.ip,
    openid : "otVC4wbMR1nHA6wDu2XG11CSF3fc",
    trade_type : 'JSAPI'
};

payment.getBrandWCPayRequestParams(order, function (err, payargs) {
    if (err) {
        console.log(err);
        res.send(err);
    } else {
        console.log(payargs);
        res.json(payargs);
    }
});

提示返回值

image

关于"接收微信付款确认请求"

示例中用的是

app.use('<notifyUrl>', ..... );

我想问一下 这个地方不用use, 改成 post/get/all 可以吗? 如果不可以 为什么呢?

我的理解是 支付后, 微信会发送请求到 notifyUrl , 我这边只要能接收到这个请求就可以了吧? 为什么要用use和中间件形式呢?
谢谢

新版有错误!

在 middleware.js 中 payment.validate 未定义!
在 payment.js 中只找到:Payment.prototype._validate

退款证书问题

请问官方说明的是退款等需要证书,可我在源码中没有找到证书相关代码,请问是怎么做到的?

header to long

var Payment = function (config) {
  this.appId = config.appId;
  this.partnerKey = config.partnerKey;
  this.mchId = config.mchId;
  this.subMchId = config.subMchId;
  this.notifyUrl = config.notifyUrl;
  this.passphrase = config.passphrase || config.mchId;
  this.pfx = config.pfx;
  this.key = config.key;
  this.cert = config.cert;
  //打开日志
  this.logger = config.logger || false
  return this;
};

Payment.prototype._httpsRequest = function(url, data, callback){

  var parsed_url = url_mod.parse(url);
  var logger = this.logger;
  option = {
      host: parsed_url.host,
      path: parsed_url.path,
      body:'xml',
      method: 'POST',
    key: this.key, 
    cert: this.cert 
  }

这段代码好像得改成这样才行,用p12证书会出现 header to long

不支持 支付端 是 IPv6 吗?

我这边的对外IP 是 IPv6,
执行 payment.getBrandWCPayRequestParams 时报错:

req.ip ::ffff:101.226.125.108
pay err { [ProtocolError: invalid spbill_create_ip] name: 'ProtocolError' }

在app中调用微信支付功能?

您好,我想在我的app中调用微信支付功能,我用的是Titanium 技术,但我现在不知道从何开始,能提供下思路吗? 谢谢!

body如果有emoji会出现崩溃

body如果有emoji会出现崩溃

信息如下

...
Unhandled rejection Error: Invalid character (�) in string: 如何 a%n?🏠 at index 10
    at XMLStringifier.module.exports.XMLStringifier.assertLegalChar (/home/Tinstone-Course-Server/node_modules/xmlbuilder/lib/XMLStringifier.js:149:15)
    at XMLStringifier.assertLegalChar (/home/Tinstone-Course-Server/node_modules/xmlbuilder/lib/XMLStringifier.js:4:59)
    at XMLStringifier.module.exports.XMLStringifier.eleText (/home/Tinstone-Course-Server/node_modules/xmlbuilder/lib/XMLStringifier.js:28:19)
    at new XMLText (/home/Tinstone-Course-Server/node_modules/xmlbuilder/lib/XMLText.js:19:35)
    at XMLElement.module.exports.XMLNode.text (/home/Tinstone-Course-Server/node_modules/xmlbuilder/lib/XMLNode.js:165:15)
    at XMLElement.module.exports.XMLNode.node (/home/Tinstone-Course-Server/node_modules/xmlbuilder/lib/XMLNode.js:157:15)
    at XMLElement.module.exports.XMLNode.element (/home/Tinstone-Course-Server/node_modules/xmlbuilder/lib/XMLNode.js:100:28)
    at XMLElement.module.exports.XMLNode.ele (/home/Tinstone-Course-Server/node_modules/xmlbuilder/lib/XMLNode.js:268:19)
    at /home/Tinstone-Course-Server/node_modules/wechat-pay/node_modules/xml2js/lib/xml2js.js:204:37
    at Builder.exports.Builder.Builder.buildObject (/home/Tinstone-Course-Server/node_modules/wechat-pay/node_modules/xml2js/lib/xml2js.js:216:14)
    at Payment.buildXml (/home/Tinstone-Course-Server/node_modules/wechat-pay/lib/payment.js:286:21)
    at Payment._signedQuery (/home/Tinstone-Course-Server/node_modules/wechat-pay/lib/payment.js:188:21)
    at Payment.unifiedOrder (/home/Tinstone-Course-Server/node_modules/wechat-pay/lib/payment.js:205:8)
    at Payment.getBrandWCPayRequestParams (/home/Tinstone-Course-Server/node_modules/wechat-pay/lib/payment.js:53:8)
...

Cannot read property 'toString' of undefined

qq 20150320101150

用了 wechat-pay 来做微信支付开发,出现下面的问题,请教是什么导致的?

TypeError: Cannot read property 'toString' of undefined
   at Payment._signedQuery (/data/www/node_modules/wechat-pay/lib/payment.js:126:30)
   at Payment.unifiedOrder (/data/www/node_modules/wechat-pay/lib/payment.js:151:8)
   at Payment.getBrandWCPayRequestParams (/data/www/node_modules/wechat-pay/lib/payment.js:52:8)
   at /data/www/node-weixin/route/wxpay.js:30:8
   at Layer.handle [as handle_request] (/data/www/node_modules/express/lib/router/layer.js:82:5)
   at next (/data/www/node_modules/express/lib/router/route.js:110:13)
   at Route.dispatch (/data/www/node_modules/express/lib/router/route.js:91:3)
   at Layer.handle [as handle_request] (/data/www/node_modules/express/lib/router/layer.js:82:5)
   at /data/www/node_modules/express/lib/router/index.js:267:22
   at Function.proto.process_params (/data/www/node_modules/express/lib/router/index.js:321:12)

package.josn里缺少request类库的引用声明

在npm install wechat-pay里下载安装的0.1.0版本,package.json的依赖性没有request声明:
"dependencies": {
"underscore": "^1.7.0",
"sha1": "^1.1.0",
"MD5": "^1.2.1",
"xml2js": "^0.4.4"
}
但github里源码的0.1.0版本有。

无法退款,报socket hang up错误

调用接口,报socket hang up 错误:

{ Error: socket hang up
    at createHangUpError (_http_client.js:331:15)
    at TLSSocket.socketOnEnd (_http_client.js:423:23)
    at emitNone (events.js:111:20)
    at TLSSocket.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1056:12)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9) code: 'ECONNRESET' }
2018-03-10 15:12:11,299 ERROR 18660 [-/127.0.0.1/-/78ms PUT /api/orders/refund/5155] nodejs.ECONNRESETError: socket hang up
    at createHangUpError (_http_client.js:331:15)
    at TLSSocket.socketOnEnd (_http_client.js:423:23)
    at emitNone (events.js:111:20)
    at TLSSocket.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1056:12)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)
code: 'ECONNRESET'
headers: { 'Access-Control-Allow-Origin': '*' }
name: 'ECONNRESETError'
pid: 18660

请求代码如下:

    const refundConfig = {
      out_trade_no: order.o_code,
      out_refund_no: `${order.o_code}_refund`,
      total_fee: 1,
      refund_fee: 1,
    };

    const res = await this.payment().refundPromise(refundConfig);
    console.log(res);

payment() {
    const payment = new Payment(this.app.config.wxPay);
    payment.refundPromise = param => {
      return new Promise((resolve, reject) => {
        payment.refund(param, function(error, result) {
          console.log(error);
          if (error) {
            return reject(error);
          }
          console.log(result);
          resolve(result);
        });
      });
    };

    return payment;
  }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.