{"id":13602132,"url":"https://github.com/befinal/node-tenpay","last_synced_at":"2025-04-11T08:31:37.972Z","repository":{"id":55509148,"uuid":"74559455","full_name":"befinal/node-tenpay","owner":"befinal","description":"微信支付 for nodejs","archived":false,"fork":false,"pushed_at":"2020-11-12T06:09:27.000Z","size":140,"stargazers_count":1096,"open_issues_count":15,"forks_count":239,"subscribers_count":30,"default_branch":"master","last_synced_at":"2024-04-25T06:21:33.130Z","etag":null,"topics":["nodejs","pay","payment","wechat","weixin"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/befinal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-11-23T09:07:27.000Z","updated_at":"2024-04-24T08:45:40.000Z","dependencies_parsed_at":"2022-08-15T02:01:11.034Z","dependency_job_id":null,"html_url":"https://github.com/befinal/node-tenpay","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/befinal%2Fnode-tenpay","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/befinal%2Fnode-tenpay/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/befinal%2Fnode-tenpay/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/befinal%2Fnode-tenpay/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/befinal","download_url":"https://codeload.github.com/befinal/node-tenpay/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248361556,"owners_count":21090931,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["nodejs","pay","payment","wechat","weixin"],"created_at":"2024-08-01T18:01:14.916Z","updated_at":"2025-04-11T08:31:37.663Z","avatar_url":"https://github.com/befinal.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# 微信支付 for nodejs\n[![travis][travis]][travis-u] [![npm][npm]][npm-u] [![node][node]][node-u] [![issues][issues]][issues-u] [![commit][commit]][commit-u]\n\n## 功能概述\n- `通知类中间件` - 支付结果通知, 退款结果通知\n- `前端支付支持` - 支持JSAPI, WeixinJSBridge, 小程序, APP, H5\n- `支付模式支持` - 付款码/公众号/小程序/APP/H5/扫码支付\n- `支付工具支持` - 微信红包, 企业付款(支持付款到零钱和银行卡)\n- `营销功能支持` - 微信代金券\n- `对帐账单支持` - 支持微信对帐单, 微信资金帐单\n- `服务商模式支持` - 所有api均可自行传入sub_appid, sub_mch_id\n- `微信支付仿真测试系统` - 支持沙盒模式, 用于完成支付验收流程\n\n## 交流群\nQQ群：157964097，使用疑问，开发，贡献代码请加群。\n\n## 使用前必读\n#### 版本要求\nnodejs \u003e= 8.3.0\n\n#### 关于传入值和微信返回值的数据类型\n\u003e 因涉及金额等敏感问题, API和中间件并没有对数据字段做类型转换\n\u003e\n\u003e `微信返回值XML做JSON转换之后的字段均为字符串类型, 请自行转换后再进行数据运算`\n\n#### 重点关注问题\n- 字符串与数字运算结果问题 `'1' + 0 = '10'`\n- 金额单位问题 `微信支付中传入的金额单位为分`\n\n#### 关于错误\n\u003e API和中间件均对所有错误进行了处理, 统一通过error返回, 包括:\n\n- `网络类错误` - 网络中断, 连接超时等\n- `微信返回值检验错误` - 微信返回值非法(伪造请求等, 可能性非常低)\n- `业务逻辑错误` - 订单重复, 退款金额大于支付金额等\n- `其它错误` - 应传参数未传入等\n\n#### 关于返回值\n\u003e 未出错时正常返回为JSON格式数据\n\n- **特殊情况:** `downloadBill`和`downloadFundflow`下载的帐单返回值为字符串文本\n\n## 安装\n```Bash\nnpm i tenpay\n\n# 如已安装旧版, 重新安装最新版\nnpm i tenpay@latest\n```\n\n## 实例化\n```javascript\nconst tenpay = require('tenpay');\nconst config = {\n  appid: '公众号ID',\n  mchid: '微信商户号',\n  partnerKey: '微信支付安全密钥',\n  pfx: require('fs').readFileSync('证书文件路径'),\n  notify_url: '支付回调网址',\n  spbill_create_ip: 'IP地址'\n};\n// 方式一\nconst api = new tenpay(config);\n// 方式二\nconst api = tenpay.init(config);\n\n// 调试模式(传入第二个参数为true, 可在控制台输出数据)\nconst api = new tenpay(config, true);\n\n// 沙盒模式(用于微信支付验收)\nconst sandboxAPI = await tenpay.sandbox(config);\n```\n\n#### config说明:\n- `appid` - 公众号ID(必填)\n- `mchid` - 微信商户号(必填)\n- `partnerKey` - 微信支付安全密钥(必填, 在微信商户管理界面获取)\n- `pfx` - 证书文件(选填, 在微信商户管理界面获取)\n  - 当不需要调用依赖证书的API时可不填此参数\n  - 若业务流程中使用了依赖证书的API则需要在初始化时传入此参数\n- `notify_url` - 支付结果通知回调地址(选填)\n  - 可以在初始化的时候传入设为默认值, 不传则需在调用相关API时传入\n  - 调用相关API时传入新值则使用新值\n- `refund_url` - 退款结果通知回调地址(选填)\n  - 可以在初始化的时候传入设为默认值, 不传则使用微信商户后台配置\n  - 调用相关API时传入新值则使用新值\n- `spbill_create_ip` - IP地址(选填)\n  - 可以在初始化的时候传入设为默认值, 不传则默认值为`127.0.0.1`\n  - 调用相关API时传入新值则使用新值\n\n#### 关于可选参数的最佳实践:\n- 如业务流程中用到含证书请求的API, 则必须在初始时传入pfx参数\n- 如回调地址不需要按业务变化, 建议在初始化时传入统一的回调地址\n- 如IP地址不需要按业务变化, 建议在初始化时传入统一的IP地址\n\n## 中间件・微信消息通知\n- middleware参数: `pay\u003c支付结果通知, 默认\u003e` `refund\u003c退款结果通知\u003e` `nativePay\u003c扫码支付模式一回调\u003e`\n- 需自行添加bodyParser接收post data\n- 中间件会对通知消息进行合法性验证, 并将消息解析为json格式放入req.weixin(Express)或ctx.request.weixin(Koa)\n- reply()会自动封装SUCCESS消息, reply('some error_msg')会自动封装FAIL消息\n\n#### Express中使用\n```javascript\napp.use(bodyParser.text({type: '*/xml'}));\n\n// 支付结果通知/退款结果通知\nrouter.post('/xxx', api.middlewareForExpress('pay'), (req, res) =\u003e {\n  let info = req.weixin;\n\n  // 业务逻辑...\n\n  // 回复消息(参数为空回复成功, 传值则为错误消息)\n  res.reply('错误消息' || '');\n});\n\n// 扫码支付模式一回调\nrouter.post('/xxx', api.middlewareForExpress('nativePay'), (req, res) =\u003e {\n  let info = req.weixin;\n\n  // 业务逻辑和统一下单获取prepay_id...\n\n  // 响应成功或失败(第二个可选参数为输出错误信息)\n  res.replyNative(prepay_id, err_msg);\n});\n```\n\n#### Koa中使用\n```javascript\napp.use(bodyParser({\n  enableTypes: ['json', 'form', 'text'],\n  extendTypes: {\n    text: ['text/xml', 'application/xml']\n  }\n}));\n\nrouter.post('/xxx', api.middleware('refund'), async ctx =\u003e {\n  let info = ctx.request.weixin;\n\n  // 业务逻辑...\n\n  // 回复消息(参数为空回复成功, 传值则为错误消息)\n  ctx.reply('错误消息' || '');\n\n  // 扫码支付模式一模式\n  ctx.replyNative(prepay_id);\n});\n```\n\n## API 列表\n- 某些API预设了某些必传字段的默认值, 调用时不传参数则使用默认值\n- 初始化时已传入的参数无需调用时重复传入, 如`appid` `mchid`\n- 签名(sign)会在调用API时自动处理, 无需手动传入\n- 随机字符串(nonce_str)会在调用API时自动处理, 无需手动传入\n\n### getPayParams: 获取微信JSSDK支付参数(自动下单, 兼容小程序)\n```javascript\nlet result = await api.getPayParams({\n  out_trade_no: '商户内部订单号',\n  body: '商品简单描述',\n  total_fee: '订单金额(分)',\n  openid: '付款用户的openid'\n});\n```\n##### 相关默认值:\n- `trade_type` - JSAPI\n\n### getPayParamsByPrepay: 获取微信JSSDK支付参数(通过预支付会话标识, 兼容小程序)\n```javascript\n// 该方法需先调用api.unifiedOrder统一下单, 获取prepay_id;\nlet result = await api.getPayParamsByPrepay({\n  prepay_id: '预支付会话标识'\n});\n```\n\n### getAppParams: 获取APP支付参数(自动下单)\n```javascript\nlet result = await api.getAppParams({\n  out_trade_no: '商户内部订单号',\n  body: '商品简单描述',\n  total_fee: '订单金额(分)'\n});\n```\n##### 相关默认值:\n- `trade_type` - APP\n\n### getAppParamsByPrepay: 获取APP支付参数(通过预支付会话标识)\n```javascript\n// 该方法需先调用api.unifiedOrder统一下单\u003c注意传入trade_type: 'APP'\u003e, 获取prepay_id;\nlet result = await api.getAppParamsByPrepay({\n  prepay_id: '预支付会话标识'\n});\n```\n\n### getNativeUrl: 扫码支付(模式一)\n```javascript\nlet result = await api.getNativeUrl({\n  product_id: '商品ID'\n});\n```\n\n### 扫码支付(模式二)\n```javascript\n// 使用统一下单API可直接获取code_url, 需自行生成二维码图片\nlet {prepay_id, code_url} = await api.unifiedOrder({\n  out_trade_no: '商户内部订单号',\n  body: '商品简单描述',\n  total_fee: '订单金额(分)',\n  openid: '用户openid',\n  trade_type: 'NATIVE',\n  product_id: '商品id'\n});\n```\n\n### micropay: 刷卡支付\n```javascript\nlet result = await api.micropay({\n  out_trade_no: '商户内部订单号',\n  body: '商品简单描述',\n  total_fee: '订单金额(分)',\n  auth_code: '授权码'\n});\n```\n\n### unifiedOrder: 微信统一下单\n```javascript\nlet result = await api.unifiedOrder({\n  out_trade_no: '商户内部订单号',\n  body: '商品简单描述',\n  total_fee: '订单金额(分)',\n  openid: '用户openid'\n});\n```\n##### 相关默认值:\n- `trade_type` - JSAPI\n- `notify_url` - 默认为初始化时传入的值或空\n- `spbill_create_ip` - 默认为初始化时传入的值或`127.0.0.1`\n\n### orderQuery: 查询订单\n```javascript\nlet result = await api.orderQuery({\n  // transaction_id, out_trade_no 二选一\n  // transaction_id: '微信的订单号',\n  out_trade_no: '商户内部订单号'\n});\n```\n\n### reverse: 撤消订单\n```javascript\nlet result = await api.reverse({\n  // transaction_id, out_trade_no 二选一\n  // transaction_id: '微信的订单号',\n  out_trade_no: '商户内部订单号'\n});\n```\n\n### closeOrder: 关闭订单\n```javascript\nlet result = await api.closeOrder({\n  out_trade_no: '商户内部订单号'\n});\n```\n\n### refund: 申请退款\n```javascript\nlet result = await api.refund({\n  // transaction_id, out_trade_no 二选一\n  // transaction_id: '微信的订单号',\n  out_trade_no: '商户内部订单号',\n  out_refund_no: '商户内部退款单号',\n  total_fee: '订单金额(分)',\n  refund_fee: '退款金额(分)'\n});\n```\n##### 相关默认值:\n- `op_user_id` - 默认为商户号(此字段在小程序支付文档中出现)\n- `notify_url` - 默认为初始化时传入的refund_url, 无此参数则使用商户后台配置的退款通知地址\n\n### refundQuery: 查询退款\n```javascript\nlet result = await api.refundQuery({\n  // 以下参数 四选一\n  // transaction_id: '微信的订单号',\n  // out_trade_no: '商户内部订单号',\n  // out_refund_no: '商户内部退款单号',\n  refund_id: '微信退款单号'\n});\n```\n\n### downloadBill: 下载对帐单\n```javascript\n/**\n * 新增一个format参数(默认: false), 用于自动转化帐单为json格式\n * json.total_title: 统计数据的标题数组 - [\"总交易单数\",\"总交易额\",\"总退款金额\", ...],\n * json.total_data: 统计数据的数组 - [\"3\", \"88.00\", \"0.00\", ...],\n * json.list_title: 详细数据的标题数组 - [\"﻿交易时间\",\"公众账号ID\",\"商户号\", ...],\n * json.list_data: 详细数据的二维数据 - [[\"2017-12-26 19:20:39\",\"wx12345\", \"12345\", ...], ...]\n */\nlet result = await api.downloadBill({\n  bill_date: '账单日期'\n}, true);\n```\n##### 相关默认值:\n- `bill_type` - ALL\n- `format` - false\n\n### downloadFundflow: 下载资金帐单\n```javascript\n/**\n * 新增一个format参数(默认: false), 用于自动转化帐单为json格式\n * json.total_title: 统计数据的标题数组 - [\"资金流水总笔数\",\"收入笔数\",\"收入金额\", ...],\n * json.total_data: 统计数据的数组 - [\"20.0\", \"17.0\", \"0.35\", ...],\n * json.list_title: 详细数据的标题数组 - [\"记账时间\",\"微信支付业务单号\",\"资金流水单号\", ...],\n * json.list_data: 详细数据的二维数据 - [[\"2018-02-01 04:21:23\",\"12345\", \"12345\", ...], ...]\n */\nlet result = await api.downloadFundflow({\n  bill_date: '账单日期'\n}, true);\n```\n##### 相关默认值:\n- `account_type` - Basic\n- `format` - false\n\n### sendCoupon: 发放代金券\n```javascript\nlet result = await api.sendCoupon({\n  coupon_stock_id: '代金券批次id',\n  partner_trade_no: '商户单据号',\n  openid: '用户openid'\n});\n```\n\n### queryCouponStock: 查询代金券批次\n```javascript\nlet result = await api.queryCouponStock({\n  coupon_stock_id: '代金券批次id'\n});\n```\n\n### queryCouponInfo: 查询代金券信息\n```javascript\nlet result = await api.queryCouponInfo({\n  coupon_id: '代金券id',\n  openid: '用户openid',\n  stock_id: '批次号'\n});\n```\n\n### transfers: 企业付款\n```javascript\nlet result = await api.transfers({\n  partner_trade_no: '商户内部付款订单号',\n  openid: '用户openid',\n  re_user_name: '用户真实姓名',\n  amount: '付款金额(分)',\n  desc: '企业付款描述信息'\n});\n```\n##### 相关默认值:\n- `check_name` - FORCE_CHECK\n- `spbill_create_ip` - 默认为初始化时传入的值或`127.0.0.1`\n\n### transfersQuery: 查询企业付款\n```javascript\nlet result = await api.transfersQuery({\n  partner_trade_no: '商户内部付款订单号'\n});\n```\n\n### payBank: 企业付款到银行卡\n```javascript\nlet result = await api.payBank({\n  partner_trade_no: '商户内部付款订单号',\n  bank_code: '收款方开户行',\n  enc_bank_no: '收款方银行卡号',\n  enc_true_name: '收款方用户名',\n  amount: '付款金额(分)',\n  desc: '企业付款到银行卡描述信息'\n});\n```\n\n### queryBank: 查询企业付款到银行卡\n```javascript\nlet result = await api.queryBank({\n  partner_trade_no: '商户内部付款订单号'\n});\n```\n\n### sendRedpack: 发放普通红包\n```javascript\nlet result = await api.sendRedpack({\n  // mch_billno, mch_autono 二选一\n  // mch_billno: '商户内部付款订单号',\n  mch_autono: '10位当日唯一数字, 用于自动生成mch_billno',\n  send_name: '商户名称',\n  re_openid: '用户openid',\n  total_amount: '红包金额(分)',\n  wishing: '红包祝福语',\n  act_name: '活动名称',\n  remark: '备注信息'\n});\n```\n##### 相关默认值和其它说明:\n- `mch_billno` - 商户内部订单号(传入则mch_autono失效)\n- `mch_autono` - 当日10位唯一数字, 用于自动处理商户内部订单号逻辑\n- `total_num` - 1\n- `client_ip` - 默认为初始化时的spbill_create_ip参数值或`127.0.0.1`\n- `scene_id` - 空, 当红包金额大于`2元`时必传(微信文档说明为200元, 实测为2元)\n\n### sendGroupRedpack: 发放裂变红包\n```javascript\nlet result = await api.sendGroupRedpack({\n  // mch_billno, mch_autono 二选一\n  // mch_billno: '商户内部付款订单号',\n  mch_autono: '10位当日唯一数字, 用于自动生成mch_billno',\n  send_name: '商户名称',\n  re_openid: '种子用户openid',\n  total_amount: '红包金额(分)',\n  wishing: '红包祝福语',\n  act_name: '活动名称',\n  remark: '备注信息'\n});\n```\n##### 相关默认值和其它说明:\n- `mch_billno` - 商户内部订单号(传入则mch_autono失效)\n- `mch_autono` - 当日10位唯一数字, 用于自动处理商户内部订单号逻辑\n- `total_num` - 3, 分裂红包要求值为3~20之间\n- `amt_type` - ALL_RAND\n- `scene_id` - 空, 当红包金额大于`2元`时必传(文档中未说明)\n\n### redpackQuery: 查询红包记录\n```javascript\napi.redpackQuery({\n  mch_billno: '商户内部付款订单号'\n});\n```\n##### 相关默认值:\n- `bill_type` - MCHT\n\n[travis]: https://img.shields.io/travis/befinal/node-tenpay.svg\n[travis-u]: https://travis-ci.org/befinal/node-tenpay\n\n[npm]: https://img.shields.io/npm/v/tenpay.svg\n[npm-u]: https://www.npmjs.com/package/tenpay\n\n[node]: https://img.shields.io/node/v/tenpay.svg\n[node-u]: https://nodejs.org/en/download/\n\n[commit]: https://img.shields.io/github/last-commit/befinal/node-tenpay.svg\n[commit-u]: https://github.com/befinal/node-tenpay/commits/master\n\n[issues]: https://img.shields.io/github/issues/befinal/node-tenpay.svg\n[issues-u]: https://github.com/befinal/node-tenpay/issues\n\n[downloads]: https://img.shields.io/npm/dm/tenpay.svg\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbefinal%2Fnode-tenpay","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbefinal%2Fnode-tenpay","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbefinal%2Fnode-tenpay/lists"}