├── LICENSE ├── README.md ├── index.js ├── lib ├── alipay.js └── utl.js ├── package.json └── test ├── index.js └── pem ├── sandbox_ali_public.pem └── sandbox_iobox_private.pem /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017, Ference Fu. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # alipay-node-sdk 2 | 3 | > 支付宝新版App支付nodejs版sdk. 4 | 5 | **Examples** 6 | 7 | 8 | ```js 9 | const path = require('path'); 10 | const Alipay = require('alipay-node-sdk'); 11 | 12 | let outTradeId = Date.now().toString(); 13 | 14 | /** 15 | * 16 | * @param {Object} opts 17 | * @param {String} opts.appId 支付宝的appId 18 | * @param {String} opts.notifyUrl 支付宝服务器主动通知商户服务器里指定的页面http/https路径 19 | * @param {String} opts.rsaPrivate 商户私钥pem文件路径 20 | * @param {String} opts.rsaPublic 支付宝公钥pem文件路径 21 | * @param {String} opts.signType 签名方式, 'RSA' or 'RSA2' 22 | * @param {Boolean} [opts.sandbox] 是否是沙盒环境 23 | * @constructor 24 | */ 25 | var ali = new Alipay({ 26 | appId: '2016080300159077', 27 |    notifyUrl: 'http://www.xxx.com/callback/alipay', 28 | rsaPrivate: path.resolve('./pem/sandbox_private.pem'), 29 | rsaPublic: path.resolve('./pem/sandbox_ali_public.pem'), 30 | sandbox: true, 31 | signType: 'RSA' 32 | }); 33 | 34 | 35 | /** 36 | * 生成支付参数供客户端使用 37 | * @param {Object} opts 38 | * @param {String} opts.subject 商品的标题/交易标题/订单标题/订单关键字等 39 | * @param {String} [opts.body] 对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body 40 | * @param {String} opts.outTradeId 商户网站唯一订单号 41 | * @param {String} [opts.timeout] 设置未付款支付宝交易的超时时间,一旦超时,该笔交易就会自动被关闭。 42 | 当用户进入支付宝收银台页面(不包括登录页面),会触发即刻创建支付宝交易,此时开始计时。 43 | 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 44 | 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 45 | * @param {String} opts.amount 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] 46 | * @param {String} [opts.sellerId] 收款支付宝用户ID。 如果该值为空,则默认为商户签约账号对应的支付宝用户ID 47 | * @param {String} opts.goodsType 商品主类型:0—虚拟类商品,1—实物类商品 注:虚拟类商品不支持使用花呗渠道 48 | * @param {String} [opts.passbackParams] 公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。支付宝会在异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付宝 49 | * @param {String} [opts.promoParams] 优惠参数(仅与支付宝协商后可用) 50 | * @param {String} [opts.extendParams] 业务扩展参数 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.3oJPAi&treeId=193&articleId=105465&docType=1#kzcs 51 | * @param {String} [opts.enablePayChannels] 可用渠道,用户只能在指定渠道范围内支付。当有多个渠道时用“,”分隔。注:与disable_pay_channels互斥 52 | * @param {String} [opts.disablePayChannels] 禁用渠道,用户不可用指定渠道支付。当有多个渠道时用“,”分隔。 注:与enable_pay_channels互斥 53 | * @param {String} [opts.storeId] 商户门店编号 54 | */ 55 | var params = ali.appPay({ 56 | subject: '测试商品', 57 | body: '测试商品描述', 58 | outTradeId: outTradeId, 59 | timeout: '10m', 60 | amount: '10.00', 61 | goodsType: '0' 62 | }); 63 | console.log(params); 64 | 65 | 66 | /** 67 | * 生成支付参数供web端使用 68 | * @param {Object} opts 69 | * @param {String} opts.subject 商品的标题/交易标题/订单标题/订单关键字等 70 | * @param {String} [opts.body] 对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body 71 | * @param {String} opts.outTradeId 商户网站唯一订单号 72 | * @param {String} [opts.timeout] 设置未付款支付宝交易的超时时间,一旦超时,该笔交易就会自动被关闭。 73 | 当用户进入支付宝收银台页面(不包括登录页面),会触发即刻创建支付宝交易,此时开始计时。 74 | 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 75 | 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 76 | * @param {String} opts.amount 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] 77 | * @param {String} [opts.sellerId] 收款支付宝用户ID。 如果该值为空,则默认为商户签约账号对应的支付宝用户ID 78 | * @param {String} opts.goodsType 商品主类型:0—虚拟类商品,1—实物类商品 注:虚拟类商品不支持使用花呗渠道 79 | * @param {String} [opts.passbackParams] 公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。支付宝会在异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付宝 80 | * @param {String} [opts.promoParams] 优惠参数(仅与支付宝协商后可用) 81 | * @param {String} [opts.extendParams] 业务扩展参数 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.3oJPAi&treeId=193&articleId=105465&docType=1#kzcs 82 | * @param {String} [opts.enablePayChannels] 可用渠道,用户只能在指定渠道范围内支付。当有多个渠道时用“,”分隔。注:与disable_pay_channels互斥 83 | * @param {String} [opts.disablePayChannels] 禁用渠道,用户不可用指定渠道支付。当有多个渠道时用“,”分隔。 注:与enable_pay_channels互斥 84 | * @param {String} [opts.storeId] 商户门店编号 85 | * @param {String} [opts.return_url] 客户端回调地址,HTTP/HTTPS开头字符串 86 | */ 87 | var params = ali.wapPay({ 88 | subject: '测试商品', 89 | body: '测试商品描述', 90 | outTradeId: outTradeId, 91 | timeout: '10m', 92 | amount: '10.00', 93 | goodsType: '0' 94 | }); 95 | console.log(params); 96 | 97 | /** 98 | * 生成支付参数供电脑网站使用 99 | * @param {Object} opts 100 | * @param {String} opts.outTradeId 商户网站唯一订单号 101 | * @param {String} opts.subject 商品的标题/交易标题/订单标题/订单关键字等 102 | * @param {String} opts.amount 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] 103 | * @param {String} [opts.body] 对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body 104 | * @param {String} [opts.timeout] 设置未付款支付宝交易的超时时间,一旦超时,该笔交易就会自动被关闭。 105 | * 当用户进入支付宝收银台页面(不包括登录页面),会触发即刻创建支付宝交易,此时开始计时。 106 | * 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 107 | * 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 108 | * @param {String} [opts.goodsType] 商品主类型:0—虚拟类商品,1—实物类商品 注:虚拟类商品不支持使用花呗渠道 109 | * @param {String} [opts.goodsDetail] 订单包含的商品列表信息,JSON格式,例如:{"show_url":"https://example/good/id"} 110 | * @param {String} [opts.passbackParams] 公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。支付宝会在异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付宝 111 | * @param {String} [opts.extendParams] 业务扩展参数 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.3oJPAi&treeId=193&articleId=105465&docType=1#kzcs 112 | * @param {String} [opts.enablePayChannels] 可用渠道,用户只能在指定渠道范围内支付。当有多个渠道时用“,”分隔。注:与disable_pay_channels互斥 113 | * @param {String} [opts.disablePayChannels] 禁用渠道,用户不可用指定渠道支付。当有多个渠道时用“,”分隔。 注:与enable_pay_channels互斥 114 | * @param {String} [opts.qrPayMode] PC扫码支付的方式,支持前置模式和跳转模式。前置模式是将二维码前置到商户的订单确认页的模式,需要商户在自己的页面中以 iframe 方式请求支付宝页面。 115 | * 具体分为以下几种: 116 | * 0,订单码-简约前置模式,对应 iframe 宽度不能小于600px,高度不能小于300px 117 | * 1,订单码-前置模式,对应 iframe 宽度不能小于300px,高度不能小于600px 118 | * 3,订单码-迷你模式,对应 iframe 宽度不能小于75px,高度不能小于75px 119 | * 4,订单码-可定义宽度的嵌入式二维码,商户可根据需要设定二维码的大小 120 | * 跳转模式下,用户的扫码界面是由支付宝生成的,不存在商户的域名下,具体为: 121 | * 2,订单码-跳转模式 122 | * @param {String} [opts.qrcodeWidte] 商户自定义二维码宽度。注:qrPayMode = 4 时该参数生效 123 | * @param {String} [opts.return_url] 客户端回调地址,HTTP/HTTPS开头字符串 124 | */ 125 | var params = ali.pagePay({ 126 | subject: '测试商品', 127 | body: '测试商品描述', 128 | outTradeId: outTradeId, 129 | timeout: '10m', 130 | amount: '10.00', 131 | goodsType: '0', 132 | qrPayMode: 0 133 | }); 134 | console.log(params); 135 | 136 | 137 | /** 138 | * 签名校验 139 | * @param {Object} response 解析后的支付宝响应报文、支付宝支付结果通知报文 140 | * returns {boolean} 141 | */ 142 | let ok = ali.signVerify(response); 143 | 144 | 145 | /** 146 | * 查询交易状态 https://doc.open.alipay.com/doc2/apiDetail.htm?spm=a219a.7629065.0.0.PlTwKb&apiId=757&docType=4 147 | * @param {Object} opts 148 | * @param {String} [opts.outTradeId] 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 tradeId,outTradeId如果同时存在优先取tradeId 149 | * @param {String} [opts.tradeId] 支付宝交易号,和商户订单号不能同时为空 150 | * @param {String} [opts.appAuthToken] https://doc.open.alipay.com/doc2/detail.htm?treeId=216&articleId=105193&docType=1 151 | */ 152 | ali.query({ 153 | outTradeId: outTradeId 154 | }).then(function (ret) { 155 | console.log("***** ret.body=" + ret.body); 156 | 157 | //签名校验 158 | var ok = ali.signVerify(ret.json()); 159 | }); 160 | 161 | 162 | /** 163 | * 统一收单交易关闭接口 https://doc.open.alipay.com/doc2/apiDetail.htm?spm=a219a.7629065.0.0.6VzMcn&apiId=1058&docType=4 164 | * @param {Object} opts 165 | * @param {String} [opts.outTradeId] 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 tradeId,outTradeId如果同时存在优先取tradeId 166 | * @param {String} [opts.tradeId] 支付宝交易号,和商户订单号不能同时为空 167 | * @param {String} [opts.operatorId] 卖家端自定义的的操作员 ID 168 | * @param {String} [opts.appAuthToken] https://doc.open.alipay.com/doc2/detail.htm?treeId=216&articleId=105193&docType=1 169 | */ 170 | ali.close({ 171 | outTradeId: outTradeId 172 | }).then(function (ret) { 173 | console.log("***** ret.body=" + ret.body); 174 | }); 175 | 176 | 177 | /** 178 | * 统一收单交易退款接口 https://doc.open.alipay.com/doc2/apiDetail.htm?spm=a219a.7629065.0.0.PlTwKb&apiId=759&docType=4 179 | * @param {Object} opts 180 | * @param {String} [opts.outTradeId] 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 tradeId,outTradeId如果同时存在优先取tradeId 181 | * @param {String} [opts.tradeId] 支付宝交易号,和商户订单号不能同时为空 182 | * @param {String} [opts.operatorId] 卖家端自定义的的操作员 ID 183 | * @param {String} [opts.appAuthToken] https://doc.open.alipay.com/doc2/detail.htm?treeId=216&articleId=105193&docType=1 184 | * @param {String} opts.refundAmount 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数 185 | * @param {String} [opts.refundReason] 退款的原因说明 186 | * @param {String} [opts.outRequestId] 标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传。 187 | * @param {String} [opts.storeId] 商户的门店编号 188 | * @param {String} [opts.terminalId] 商户的终端编号 189 | */ 190 | ali.refund({ 191 | outTradeId: outTradeId, 192 | operatorId: 'XX001', 193 | refundAmount: '2.01', 194 | refundReason: '退款' 195 | }).then(function (ret) { 196 | console.log("***** ret.body=" + ret.body); 197 | }); 198 | 199 | 200 | /** 201 | * 统一收单交易退款查询 https://doc.open.alipay.com/doc2/apiDetail.htm?docType=4&apiId=1049 202 | * @param {Object} opts 203 | * @param {String} [opts.outTradeId] 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 tradeId,outTradeId如果同时存在优先取tradeId 204 | * @param {String} [opts.tradeId] 支付宝交易号,和商户订单号不能同时为空 205 | * @param {String} [opts.outRequestId] 请求退款接口时,传入的退款请求号,如果在退款请求时未传入,则该值为创建交易时的外部交易号 206 | * @param {String} [opts.appAuthToken] https://doc.open.alipay.com/doc2/detail.htm?treeId=216&articleId=105193&docType=1 207 | */ 208 | ali.refundQuery({...}).then(function(ret) { 209 | console.log("***** ret.body=" + ret.body); 210 | }); 211 | 212 | 213 | /** 214 | * 查询对账单下载地址 https://doc.open.alipay.com/doc2/apiDetail.htm?spm=a219a.7629065.0.0.iX5mPA&apiId=1054&docType=4 215 | * @param {Object} opts 216 | * @param {String} [opts.billType] 账单类型,商户通过接口或商户经开放平台授权后其所属服务商通过接口可以获取以下账单类型: 217 | trade、signcustomer;trade指商户基于支付宝交易收单的业务账单;signcustomer是指基于商户支付宝余额收入及支出等资金变动的帐务账单; 218 | * @param {String} [opts.billDate] 账单时间:日账单格式为yyyy-MM-dd,月账单格式为yyyy-MM。 219 | * @param {String} [opts.appAuthToken] https://doc.open.alipay.com/doc2/detail.htm?treeId=216&articleId=105193&docType=1 220 | */ 221 | ali.billDownloadUrlQuery({ 222 | billType: 'trade', 223 | billDate: '2017-03' 224 | }).then(function (ret) { 225 | console.log("***** ret.body=" + ret.body); 226 | }); 227 | 228 | ``` 229 | 230 | ## 注意 231 | ```sh 232 | 支付宝的公钥下载后需要格式化才能使用(添加首尾、以每行64字符进行断行),参考test/pem/sandbox_ali_public.pem 233 | ``` 234 | 235 | ## Install 236 | 237 | Install with [npm](https://www.npmjs.com/) 238 | 239 | ```sh 240 | $ npm i alipay-node-sdk --save 241 | ``` 242 | 243 | ## 贡献者 244 |  [@Allidylls](https://github.com/Allidylls) 245 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by ference on 2017/4/8. 3 | */ 4 | 5 | module.exports = require('./lib/alipay'); -------------------------------------------------------------------------------- /lib/alipay.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by ference on 2017/4/8. 3 | */ 4 | 5 | var fs = require('fs'); 6 | var path = require('path'); 7 | var utl = require('./utl'); 8 | 9 | var alipay_gate_way = 'https://openapi.alipay.com/gateway.do'; 10 | var alipay_gate_way_sandbox = 'https://openapi.alipaydev.com/gateway.do'; 11 | 12 | /** 13 | * 14 | * @param {Object} opts 15 | * @param {String} opts.appId 支付宝的appId 16 | * @param {String} opts.notifyUrl 支付宝服务器主动通知商户服务器里指定的页面http/https路径 17 | * @param {String | Buffer} opts.rsaPrivate 商户私钥pem文件路径 18 | * @param {String | Buffer} opts.rsaPublic 支付宝公钥pem文件路径 19 | * @param {String} opts.signType 签名方式, 'RSA' or 'RSA2' 20 | * @param {Boolean} [opts.sandbox] 是否是沙盒环境 21 | * @constructor 22 | */ 23 | function Alipay(opts) { 24 | this.appId = opts.appId; 25 | this.notifyUrl = opts.notifyUrl; 26 | this.signType = opts.signType; 27 | 28 | this.rsaPrivate = Buffer.isBuffer(opts.rsaPrivate) ? opts.rsaPrivate : fs.readFileSync(opts.rsaPrivate, 'utf-8'); 29 | this.rsaPublic = Buffer.isBuffer(opts.rsaPublic) ? opts.rsaPublic : fs.readFileSync(opts.rsaPublic, 'utf-8'); 30 | 31 | this.sandbox = !!opts.sandbox; 32 | } 33 | 34 | var props = Alipay.prototype; 35 | 36 | props.makeParams = function(method, biz_content) { 37 | return { 38 | app_id: this.appId, 39 | method: method, 40 | format: 'JSON', 41 | charset: 'utf-8', 42 | sign_type: this.signType, 43 | timestamp: new Date().format('yyyy-MM-dd hh:mm:ss'), 44 | version: '1.0', 45 | biz_content: JSON.stringify(biz_content) 46 | }; 47 | }; 48 | 49 | /** 50 | * 生成支付参数供App端使用 51 | * @param {Object} opts 52 | * @param {String} opts.subject 商品的标题/交易标题/订单标题/订单关键字等 53 | * @param {String} [opts.body] 对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body 54 | * @param {String} opts.outTradeId 商户网站唯一订单号 55 | * @param {String} [opts.timeout] 设置未付款支付宝交易的超时时间,一旦超时,该笔交易就会自动被关闭。 56 | * 当用户进入支付宝收银台页面(不包括登录页面),会触发即刻创建支付宝交易,此时开始计时。 57 | * 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 58 | * 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 59 | * @param {String} opts.amount 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] 60 | * @param {String} [opts.sellerId] 收款支付宝用户ID。 如果该值为空,则默认为商户签约账号对应的支付宝用户ID 61 | * @param {String} opts.goodsType 商品主类型:0—虚拟类商品,1—实物类商品 注:虚拟类商品不支持使用花呗渠道 62 | * @param {String} [opts.passbackParams] 公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。支付宝会在异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付宝 63 | * @param {String} [opts.promoParams] 优惠参数(仅与支付宝协商后可用) 64 | * @param {String} [opts.extendParams] 业务扩展参数 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.3oJPAi&treeId=193&articleId=105465&docType=1#kzcs 65 | * @param {String} [opts.enablePayChannels] 可用渠道,用户只能在指定渠道范围内支付。当有多个渠道时用“,”分隔。注:与disable_pay_channels互斥 66 | * @param {String} [opts.disablePayChannels] 禁用渠道,用户不可用指定渠道支付。当有多个渠道时用“,”分隔。 注:与enable_pay_channels互斥 67 | * @param {String} [opts.storeId] 商户门店编号 68 | */ 69 | props.appPay = function (opts) { 70 | 71 | var biz_content = { 72 | body: opts.body, 73 | subject: opts.subject, 74 | out_trade_no: opts.outTradeId, 75 | timeout_express: opts.timeout, 76 | total_amount: opts.amount, 77 | seller_id: opts.sellerId, 78 | product_code: 'QUICK_MSECURITY_PAY', 79 | goods_type: opts.goodsType, 80 | passback_params: opts.passbackParams, 81 | promo_params: opts.promoParams, 82 | extend_params: opts.extendParams, 83 | enable_pay_channels: opts.enablePayChannels, 84 | disable_pay_channels: opts.disablePayChannels, 85 | store_id: opts.storeId 86 | }; 87 | 88 | var params = this.makeParams('alipay.trade.app.pay', biz_content); 89 | params.notify_url = this.notifyUrl; 90 | 91 | return utl.processParams(params, this.rsaPrivate, this.signType); 92 | }; 93 | 94 | /** 95 | * 生成支付参数供手机网站使用 96 | * @param {Object} opts 97 | * @param {String} opts.subject 商品的标题/交易标题/订单标题/订单关键字等 98 | * @param {String} [opts.body] 对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body 99 | * @param {String} opts.outTradeId 商户网站唯一订单号 100 | * @param {String} [opts.timeout] 设置未付款支付宝交易的超时时间,一旦超时,该笔交易就会自动被关闭。 101 | * 当用户进入支付宝收银台页面(不包括登录页面),会触发即刻创建支付宝交易,此时开始计时。 102 | * 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 103 | * 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 104 | * @param {String} opts.amount 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] 105 | * @param {String} [opts.sellerId] 收款支付宝用户ID。 如果该值为空,则默认为商户签约账号对应的支付宝用户ID 106 | * @param {String} opts.goodsType 商品主类型:0—虚拟类商品,1—实物类商品 注:虚拟类商品不支持使用花呗渠道 107 | * @param {String} [opts.passbackParams] 公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。支付宝会在异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付宝 108 | * @param {String} [opts.promoParams] 优惠参数(仅与支付宝协商后可用) 109 | * @param {String} [opts.extendParams] 业务扩展参数 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.3oJPAi&treeId=193&articleId=105465&docType=1#kzcs 110 | * @param {String} [opts.enablePayChannels] 可用渠道,用户只能在指定渠道范围内支付。当有多个渠道时用“,”分隔。注:与disable_pay_channels互斥 111 | * @param {String} [opts.disablePayChannels] 禁用渠道,用户不可用指定渠道支付。当有多个渠道时用“,”分隔。 注:与enable_pay_channels互斥 112 | * @param {String} [opts.storeId] 商户门店编号 113 | * @param {String} [opts.return_url] 客户端回调地址,HTTP/HTTPS开头字符串 114 | */ 115 | props.wapPay = function (opts) { 116 | 117 | var biz_content = { 118 | body: opts.body, 119 | subject: opts.subject, 120 | out_trade_no: opts.outTradeId, 121 | timeout_express: opts.timeout, 122 | total_amount: opts.amount, 123 | seller_id: opts.sellerId, 124 | product_code: 'QUICK_WAP_PAY', 125 | goods_type: opts.goodsType, 126 | passback_params: opts.passbackParams, 127 | promo_params: opts.promoParams, 128 | extend_params: opts.extendParams, 129 | enable_pay_channels: opts.enablePayChannels, 130 | disable_pay_channels: opts.disablePayChannels, 131 | store_id: opts.storeId 132 | }; 133 | 134 | var params = this.makeParams('alipay.trade.wap.pay', biz_content); 135 | params.notify_url = this.notifyUrl; 136 | params.return_url = opts.return_url; 137 | 138 | return utl.processParams(params, this.rsaPrivate, this.signType); 139 | }; 140 | 141 | /** 142 | * 生成支付参数供电脑网站使用 143 | * @param {Object} opts 144 | * @param {String} opts.outTradeId 商户网站唯一订单号 145 | * @param {String} opts.subject 商品的标题/交易标题/订单标题/订单关键字等 146 | * @param {String} opts.amount 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] 147 | * @param {String} [opts.body] 对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body 148 | * @param {String} [opts.timeout] 设置未付款支付宝交易的超时时间,一旦超时,该笔交易就会自动被关闭。 149 | * 当用户进入支付宝收银台页面(不包括登录页面),会触发即刻创建支付宝交易,此时开始计时。 150 | * 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 151 | * 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 152 | * @param {String} [opts.goodsType] 商品主类型:0—虚拟类商品,1—实物类商品 注:虚拟类商品不支持使用花呗渠道 153 | * @param {String} [opts.goodsDetail] 订单包含的商品列表信息,JSON格式,例如:{"show_url":"https://example/good/id"} 154 | * @param {String} [opts.passbackParams] 公用回传参数,如果请求时传递了该参数,则返回给商户时会回传该参数。支付宝会在异步通知时将该参数原样返回。本参数必须进行UrlEncode之后才可以发送给支付宝 155 | * @param {String} [opts.extendParams] 业务扩展参数 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.3oJPAi&treeId=193&articleId=105465&docType=1#kzcs 156 | * @param {String} [opts.enablePayChannels] 可用渠道,用户只能在指定渠道范围内支付。当有多个渠道时用“,”分隔。注:与disable_pay_channels互斥 157 | * @param {String} [opts.disablePayChannels] 禁用渠道,用户不可用指定渠道支付。当有多个渠道时用“,”分隔。 注:与enable_pay_channels互斥 158 | * @param {String} [opts.qrPayMode] PC扫码支付的方式,支持前置模式和跳转模式。前置模式是将二维码前置到商户的订单确认页的模式,需要商户在自己的页面中以 iframe 方式请求支付宝页面。 159 | * 具体分为以下几种: 160 | * 0,订单码-简约前置模式,对应 iframe 宽度不能小于600px,高度不能小于300px 161 | * 1,订单码-前置模式,对应 iframe 宽度不能小于300px,高度不能小于600px 162 | * 3,订单码-迷你模式,对应 iframe 宽度不能小于75px,高度不能小于75px 163 | * 4,订单码-可定义宽度的嵌入式二维码,商户可根据需要设定二维码的大小 164 | * 跳转模式下,用户的扫码界面是由支付宝生成的,不存在商户的域名下,具体为: 165 | * 2,订单码-跳转模式 166 | * @param {String} [opts.qrcodeWidth] 商户自定义二维码宽度。注:qrPayMode = 4 时该参数生效 167 | * @param {String} [opts.return_url] 客户端回调地址,HTTP/HTTPS开头字符串 168 | */ 169 | props.pagePay = function (opts) { 170 | 171 | var biz_content = { 172 | out_trade_no: opts.outTradeId, 173 | subject: opts.subject, 174 | total_amount: opts.amount, 175 | product_code: 'FAST_INSTANT_TRADE_PAY', 176 | body: opts.body, 177 | timeout_express: opts.timeout, 178 | goods_type: opts.goodsType, 179 | goods_detail: opts.goodsDetail, 180 | passback_params: opts.passbackParams, 181 | extend_params: opts.extendParams, 182 | enable_pay_channels: opts.enablePayChannels, 183 | disable_pay_channels: opts.disablePayChannels, 184 | qr_pay_mode: opts.qrPayMode, 185 | qrcode_width: opts.qrcodeWidth 186 | }; 187 | 188 | var params = this.makeParams('alipay.trade.page.pay', biz_content); 189 | params.notify_url = this.notifyUrl; 190 | params.return_url = opts.return_url; 191 | 192 | return utl.processParams(params, this.rsaPrivate, this.signType); 193 | }; 194 | 195 | /** 196 | * 生成支付参数供当面付使用 197 | * @param {Object} opts 198 | * @param {String} opts.outTradeId 商户网站唯一订单号 199 | * @param {String} opts.subject 商品的标题/交易标题/订单标题/订单关键字等 200 | * @param {String} opts.amount 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000] 201 | * @param {String} [opts.body] 对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body 202 | * @param {String} [opts.timeout] 设置未付款支付宝交易的超时时间,一旦超时,该笔交易就会自动被关闭。 203 | * 当用户进入支付宝收银台页面(不包括登录页面),会触发即刻创建支付宝交易,此时开始计时。 204 | * 取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 205 | * 该参数数值不接受小数点, 如 1.5h,可转换为 90m。 206 | * @param {String} [opts.goodsDetail] 订单包含的商品列表信息,JSON格式,例如:{"show_url":"https://example/good/id"} 207 | * @param {String} [opts.extendParams] 业务扩展参数 https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.3oJPAi&treeId=193&articleId=105465&docType=1#kzcs 208 | * @param {String} [opts.enablePayChannels] 可用渠道,用户只能在指定渠道范围内支付。当有多个渠道时用“,”分隔。注:与disable_pay_channels互斥 209 | * @param {String} [opts.disablePayChannels] 禁用渠道,用户不可用指定渠道支付。当有多个渠道时用“,”分隔。 注:与enable_pay_channels互斥 210 | */ 211 | props.preCreate = function (opts) { 212 | var biz_content = { 213 | out_trade_no: opts.outTradeId, 214 | subject: opts.subject, 215 | total_amount: opts.amount, 216 | body: opts.body, 217 | timeout_express: opts.timeout, 218 | goods_detail: opts.goodsDetail, 219 | extend_params: opts.extendParams, 220 | enable_pay_channels: opts.enablePayChannels, 221 | disable_pay_channels: opts.disablePayChannels 222 | }; 223 | 224 | var params = this.makeParams('alipay.trade.precreate', biz_content); 225 | params.notify_url = this.notifyUrl; 226 | params.return_url = opts.return_url; 227 | 228 | return utl.processParams(params, this.rsaPrivate, this.signType); 229 | }; 230 | 231 | 232 | /** 233 | * 签名校验 234 | * @param {Object} response 支付宝的响应报文 235 | */ 236 | props.signVerify = function (response) { 237 | var ret = utl.copy(response); 238 | var sign = ret['sign']; 239 | ret.sign = undefined; 240 | ret.sign_type = undefined; 241 | 242 | var response_type = [ 243 | 'alipay_trade_app_pay_response', 244 | 'alipay_trade_create_response', 245 | 'alipay_trade_query_response', 246 | 'alipay_trade_refund_response', 247 | 'alipay_trade_precreate_response', 248 | 'alipay_trade_pay_response', 249 | 'alipay_trade_cancel_response', 250 | 'alipay_trade_close_response', 251 | 'alipay_trade_order_settle_response', 252 | 'alipay_trade_fastpay_refund_query_response' 253 | ]; 254 | // 支付宝(电脑网站支付)响应报文的结构 https://docs.open.alipay.com/api_1/alipay.trade.fastpay.refund.query/ 255 | var res = response_type.reduce(function(prev, currentType){ 256 | if (currentType in ret) return ret[currentType]; 257 | return prev; 258 | }, null); 259 | 260 | if(res) { 261 | return utl.signVerify(JSON.stringify(res), sign, this.rsaPublic, this.signType); 262 | } else { 263 | var tmp = utl.encodeParams(ret); 264 | return utl.signVerify(tmp.unencode, sign, this.rsaPublic, this.signType); 265 | } 266 | } 267 | 268 | /** 269 | * 查询交易状态 https://doc.open.alipay.com/doc2/apiDetail.htm?spm=a219a.7629065.0.0.PlTwKb&apiId=757&docType=4 270 | * @param {Object} opts 271 | * @param {String} [opts.outTradeId] 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 tradeId,outTradeId如果同时存在优先取tradeId 272 | * @param {String} [opts.tradeId] 支付宝交易号,和商户订单号不能同时为空 273 | * @param {String} [opts.appAuthToken] https://doc.open.alipay.com/doc2/detail.htm?treeId=216&articleId=105193&docType=1 274 | */ 275 | props.query = function (opts) { 276 | 277 | var biz_content = { 278 | out_trade_no: opts.outTradeId, 279 | trade_no: opts.tradeId 280 | }; 281 | 282 | var params = this.makeParams('alipay.trade.query', biz_content); 283 | if(this.appAuthToken) { 284 | params.app_auth_token = this.appAuthToken; 285 | } 286 | 287 | var body = utl.processParams(params, this.rsaPrivate, this.signType); 288 | 289 | return utl.request({ 290 | method: 'GET', 291 | url: (this.sandbox? alipay_gate_way_sandbox : alipay_gate_way) + '?' + body 292 | }); 293 | }; 294 | 295 | 296 | /** 297 | * 统一收单交易关闭接口 https://doc.open.alipay.com/doc2/apiDetail.htm?spm=a219a.7629065.0.0.6VzMcn&apiId=1058&docType=4 298 | * @param {Object} opts 299 | * @param {String} [opts.outTradeId] 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 tradeId,outTradeId如果同时存在优先取tradeId 300 | * @param {String} [opts.tradeId] 支付宝交易号,和商户订单号不能同时为空 301 | * @param {String} [opts.operatorId] 卖家端自定义的的操作员 ID 302 | * @param {String} [opts.appAuthToken] https://doc.open.alipay.com/doc2/detail.htm?treeId=216&articleId=105193&docType=1 303 | */ 304 | props.close = function (opts) { 305 | 306 | var biz_content = { 307 | out_trade_no: opts.outTradeId, 308 | trade_no: opts.tradeId, 309 | operator_id: opts.operatorId 310 | }; 311 | 312 | var params = this.makeParams('alipay.trade.close', biz_content); 313 | if(this.appAuthToken) { 314 | params.app_auth_token = this.appAuthToken; 315 | } 316 | 317 | var body = utl.processParams(params, this.rsaPrivate, this.signType); 318 | 319 | return utl.request({ 320 | method: 'GET', 321 | url: (this.sandbox? alipay_gate_way_sandbox : alipay_gate_way) + '?' + body 322 | }); 323 | }; 324 | 325 | 326 | /** 327 | * 统一收单交易退款接口 https://doc.open.alipay.com/doc2/apiDetail.htm?spm=a219a.7629065.0.0.PlTwKb&apiId=759&docType=4 328 | * @param {Object} opts 329 | * @param {String} [opts.outTradeId] 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 tradeId,outTradeId如果同时存在优先取tradeId 330 | * @param {String} [opts.tradeId] 支付宝交易号,和商户订单号不能同时为空 331 | * @param {String} [opts.operatorId] 卖家端自定义的的操作员 ID 332 | * @param {String} [opts.appAuthToken] https://doc.open.alipay.com/doc2/detail.htm?treeId=216&articleId=105193&docType=1 333 | * @param {String} opts.refundAmount 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数 334 | * @param {String} [opts.refundReason] 退款的原因说明 335 | * @param {String} [opts.outRequestId] 标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传。 336 | * @param {String} [opts.storeId] 商户的门店编号 337 | * @param {String} [opts.terminalId] 商户的终端编号 338 | */ 339 | props.refund = function (opts) { 340 | 341 | var biz_content = { 342 | out_trade_no: opts.outTradeId, 343 | trade_no: opts.tradeId, 344 | operator_id: opts.operatorId, 345 | refund_amount: opts.refundAmount, 346 | refund_reason: opts.refundReason, 347 | out_request_no: opts.outRequestId, 348 | store_id: opts.storeId, 349 | terminal_id: opts.terminalId 350 | }; 351 | 352 | var params = this.makeParams('alipay.trade.refund', biz_content); 353 | if(this.appAuthToken) { 354 | params.app_auth_token = this.appAuthToken; 355 | } 356 | 357 | var body = utl.processParams(params, this.rsaPrivate, this.signType); 358 | 359 | return utl.request({ 360 | method: 'GET', 361 | url: (this.sandbox? alipay_gate_way_sandbox : alipay_gate_way) + '?' + body 362 | }); 363 | }; 364 | 365 | 366 | /** 367 | * 统一收单交易退款查询 https://doc.open.alipay.com/doc2/apiDetail.htm?docType=4&apiId=1049 368 | * @param {Object} opts 369 | * @param {String} [opts.outTradeId] 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 tradeId,outTradeId如果同时存在优先取tradeId 370 | * @param {String} [opts.tradeId] 支付宝交易号,和商户订单号不能同时为空 371 | * @param {String} [opts.outRequestId] 请求退款接口时,传入的退款请求号,如果在退款请求时未传入,则该值为创建交易时的外部交易号 372 | * @param {String} [opts.appAuthToken] https://doc.open.alipay.com/doc2/detail.htm?treeId=216&articleId=105193&docType=1 373 | */ 374 | props.refundQuery = function (opts) { 375 | 376 | var biz_content = { 377 | out_trade_no: opts.outTradeId, 378 | trade_no: opts.tradeId, 379 | out_request_no: opts.outRequestId || opts.outTradeId 380 | }; 381 | 382 | var params = this.makeParams('alipay.trade.fastpay.refund.query', biz_content); 383 | if(this.appAuthToken) { 384 | params.app_auth_token = this.appAuthToken; 385 | } 386 | 387 | var body = utl.processParams(params, this.rsaPrivate, this.signType); 388 | 389 | return utl.request({ 390 | method: 'GET', 391 | url: (this.sandbox? alipay_gate_way_sandbox : alipay_gate_way) + '?' + body 392 | }); 393 | }; 394 | 395 | 396 | /** 397 | * 查询对账单下载地址 https://doc.open.alipay.com/doc2/apiDetail.htm?spm=a219a.7629065.0.0.iX5mPA&apiId=1054&docType=4 398 | * @param {Object} opts 399 | * @param {String} [opts.billType] 账单类型,商户通过接口或商户经开放平台授权后其所属服务商通过接口可以获取以下账单类型: 400 | * trade、signcustomer;trade指商户基于支付宝交易收单的业务账单;signcustomer是指基于商户支付宝余额收入及支出等资金变动的帐务账单; 401 | * @param {String} [opts.billDate] 账单时间:日账单格式为yyyy-MM-dd,月账单格式为yyyy-MM。 402 | * @param {String} [opts.appAuthToken] https://doc.open.alipay.com/doc2/detail.htm?treeId=216&articleId=105193&docType=1 403 | */ 404 | props.billDownloadUrlQuery = function (opts) { 405 | 406 | var biz_content = { 407 | bill_type: opts.billType, 408 | bill_date: opts.billDate 409 | }; 410 | 411 | var params = this.makeParams('alipay.data.dataservice.bill.downloadurl.query', biz_content); 412 | if(this.appAuthToken) { 413 | params.app_auth_token = this.appAuthToken; 414 | } 415 | 416 | var body = utl.processParams(params, this.rsaPrivate, this.signType); 417 | 418 | return utl.request({ 419 | method: 'GET', 420 | url: (this.sandbox? alipay_gate_way_sandbox : alipay_gate_way) + '?' + body 421 | }); 422 | }; 423 | 424 | //1.0.3版本接口兼容 425 | props.pay = props.appPay; 426 | props.webPay = props.wapPay; 427 | 428 | module.exports = Alipay; 429 | -------------------------------------------------------------------------------- /lib/utl.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by ference on 2017/4/8. 3 | */ 4 | 5 | var crypto = require('crypto'); 6 | var request = require('request'); 7 | 8 | var utl = module.exports = {}; 9 | 10 | Date.prototype.format = function (fmt) { 11 | var o = { 12 | "M+": this.getMonth() + 1, //月份 13 | "d+": this.getDate(), //日 14 | "h+": this.getHours(), //小时 15 | "m+": this.getMinutes(), //分 16 | "s+": this.getSeconds(), //秒 17 | "q+": Math.floor((this.getMonth() + 3) / 3), //季度 18 | "S": this.getMilliseconds() //毫秒 19 | }; 20 | if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 21 | for (var k in o) 22 | if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 23 | return fmt; 24 | } 25 | 26 | /** 27 | * 浅拷贝 28 | * @param obj 29 | * @returns {{}} 30 | */ 31 | utl.copy = function (obj) { 32 | var ret = {}; 33 | for(var k in obj) { 34 | ret[k] = obj[k]; 35 | } 36 | return ret; 37 | } 38 | 39 | /** 40 | * 对请求参数进行组装、编码、签名,返回已组装好签名的参数字符串 41 | * @param {{Object} params 请求参数 42 | * @param {String} privateKey 商户应用私钥 43 | * @param {String} [signType] 签名类型 'RSA2' or 'RSA' 44 | * @returns {String} 45 | */ 46 | utl.processParams = function (params, privateKey, signType) { 47 | var ret = utl.encodeParams(params); 48 | var sign = utl.sign(ret.unencode, privateKey, signType); 49 | return ret.encode + '&sign=' + encodeURIComponent(sign); 50 | }; 51 | 52 | /** 53 | * 对请求参数进行组装、编码 54 | * @param {Object} params 请求参数 55 | * @returns {Object} 56 | */ 57 | utl.encodeParams = function (params) { 58 | var keys = []; 59 | for(var k in params) { 60 | var v = params[k]; 61 | if (params[k] !== undefined && params[k] !== "") keys.push(k); 62 | } 63 | keys.sort(); 64 | 65 | var unencodeStr = ""; 66 | var encodeStr = ""; 67 | var len = keys.length; 68 | for(var i = 0; i < len; ++i) { 69 | var k = keys[i]; 70 | if(i !== 0) { 71 | unencodeStr += '&'; 72 | encodeStr += '&'; 73 | } 74 | unencodeStr += k + '=' + params[k]; 75 | encodeStr += k + '=' + encodeURIComponent(params[k]); 76 | } 77 | return {unencode:unencodeStr, encode:encodeStr}; 78 | }; 79 | 80 | /** 81 | * 对字符串进行签名验证 82 | * @param {String} str 要验证的参数字符串 83 | * @param {String} sign 要验证的签名 84 | * @param {String} publicKey 支付宝公钥 85 | * @param {String} [signType] 签名类型 86 | * @returns {Boolean} 87 | */ 88 | utl.signVerify = function (str, sign, publicKey, signType) { 89 | var verify; 90 | if(signType === 'RSA2') { 91 | verify = crypto.createVerify('RSA-SHA256'); 92 | } else { 93 | verify = crypto.createVerify('RSA-SHA1'); 94 | } 95 | verify.update(str, 'utf8'); 96 | var result = verify.verify(publicKey, sign, 'base64'); 97 | return result; 98 | }; 99 | 100 | /** 101 | * 对字符串进行签名 102 | * @param {String} str 要签名的字符串 103 | * @param {String} privateKey 商户应用私钥 104 | * @param {String} [signType] 签名类型 105 | * @returns {String} 106 | */ 107 | utl.sign = function (str, privateKey, signType) { 108 | var sha; 109 | if(signType === 'RSA2') { 110 | sha = crypto.createSign('RSA-SHA256'); 111 | } else { 112 | sha = crypto.createSign('RSA-SHA1'); 113 | } 114 | sha.update(str, 'utf8'); 115 | return sha.sign(privateKey, 'base64'); 116 | } 117 | 118 | 119 | /** 120 | * 发送请求 https://github.com/request/request 121 | * @param {Object} opts 请求参数 122 | * @param {String} opts.url 请求地址 123 | * @param {String} opts.method GET|POST|PUT... 124 | * @param {String} [opts.type] text/xml | application/json | application/x-www-form-urlencoded ... 125 | * @param {Object} [opts.headers] {} 126 | * @param {Object} [opts.qs] query参数 127 | * @param {Buffer|String|ReadStream} [opts.body] 请求体 128 | * @param {Object} [opts.form] form表单 129 | * @returns {Promise.} resolve({response, body}) 130 | */ 131 | utl.request = function(opts){ 132 | return new Promise(function(resolve, reject){ 133 | request(opts, function(err, res, body){ 134 | if(err){ 135 | reject(err); 136 | return; 137 | } 138 | var ret = {response:res, body:body}; 139 | ret.ok = function() { 140 | return res.statusCode === 200; 141 | }; 142 | ret.json = function () { 143 | if(res.body) return JSON.parse(res.body); 144 | return null; 145 | }; 146 | resolve(ret); 147 | }); 148 | }); 149 | }; 150 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alipay-node-sdk", 3 | "version": "1.1.9", 4 | "description": "支付宝App支付nodejs SDK", 5 | "private": false, 6 | "homepage": "https://github.com/fym201/alipay-node-sdk#readme", 7 | 8 | "scripts": { 9 | "test": "grunt" 10 | }, 11 | 12 | "bugs": { 13 | "url": "https://github.com/fym201/alipay-node-sdk/issues" 14 | }, 15 | 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/fym201/alipay-node-sdk.git" 19 | }, 20 | 21 | "licenses": [ 22 | { 23 | "type": "MIT", 24 | "url": "https://github.com/fym201/alipay-node-sdk#license" 25 | } 26 | ], 27 | 28 | "keywords": [ 29 | "alipay", 30 | "sdk", 31 | "server" 32 | ], 33 | 34 | "dependencies": { 35 | "request": "^2.79.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by ference on 2017/4/8. 3 | */ 4 | 5 | var path = require('path'); 6 | var Alipay = require('../lib/alipay'); 7 | 8 | var outTradeId = Date.now().toString(); 9 | 10 | 11 | var ali = new Alipay({ 12 | appId: '2016080300159077', 13 | notifyUrl: 'http://www.iobox.me/callback/alipay', 14 | rsaPrivate: path.resolve('./pem/sandbox_iobox_private.pem'), 15 | rsaPublic: path.resolve('./pem/sandbox_ali_public.pem'), 16 | sandbox: true, 17 | signType: 'RSA' 18 | }); 19 | 20 | ali.query({ 21 | outTradeId: outTradeId 22 | }).then(function (ret) { 23 | console.log("***** ret.body=" + ret.body); 24 | }); 25 | 26 | ali.close({ 27 | outTradeId: outTradeId 28 | }).then(function (ret) { 29 | console.log("***** ret.body=" + ret.body); 30 | }); 31 | 32 | 33 | ali.refund({ 34 | outTradeId: outTradeId, 35 | operatorId: 'XX001', 36 | refundAmount: '2.01', 37 | refundReason: '退款' 38 | }).then(function (ret) { 39 | console.log("***** ret.body=" + ret.body); 40 | }); 41 | 42 | 43 | ali.billDownloadUrlQuery({ 44 | billType: 'trade', 45 | billDate: '2017-03' 46 | }).then(function (ret) { 47 | console.log("***** ret.body=" + ret.body); 48 | }); 49 | -------------------------------------------------------------------------------- /test/pem/sandbox_ali_public.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIgHnOn7LLILlKETd6BFRJ0Gqg 3 | S2Y3mn1wMQmyh9zEyWlz5p1zrahRahbXAfCfSqshSNfqOmAQzSHRVjCqjsAw1jyq 4 | rXaPdKBmr90DIpIxmIyKXv4GGAkPyJ/6FTFY99uhpiq0qadD/uSzQsefWo0aTvP/ 5 | 65zi3eof7TcZ32oWpwIDAQAB 6 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /test/pem/sandbox_iobox_private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXgIBAAKBgQCbc/e1JYkfcJ54+9d+l/cIuv5X3j71qREf/06WGIhewt4liu38 3 | MzSTLJWc4HOotfeHraPpwDJ5YipYwGIfaiDDqZRfZuy+rEyQT8LInnU6OTzVkUvK 4 | +2NMIlyOitC5sb3p61ceRyAsRM1sF7x3DszVY253aokjr82u0yXgOttu8QIDAQAB 5 | AoGAbv11tth99vypqSfmzHQj5Q/d2U7NFQkJORdIPNJ3S3FGuvdew9qrhwkmKUP4 6 | UFTbzvujNJoNb60vHv79EADuMqeZxnP4fHRRPoWFtYSCXf2rLQKUJaPlZLx6oiSh 7 | 5spL3wOT/hfh9qNlzz/+HRT4P8chXn0OkO4hQRCWoPmSw4ECQQDWkgCJkYAq0gIb 8 | m1VTiwvfHiJLT1VV01gksOOXpW8i8DUeZDGWMslUsqoefu8HenytKzOvvTOYQEer 9 | 2238c9fFAkEAuXfa30m8DOSXGGz7OXOv3KFVZyf2wzh1AltywW0kw0+PKbiSjR/n 10 | LQybKcsuX+EXodEWIcFmlysaovs3oxhBPQJBAJtPcP4iiD/2ZLow1DE1azFjsXUL 11 | hnwqDxn3w7VHdMs4TWqjIVVTi3E4JXUPcdra6RW7OJ1S+N6SYI5ftRvPifUCQQCY 12 | hYc6DwIVvDrBfIYRFiEumIKKJaRZoOkguiGiDeaos5mxHrduVSkgs/g6I3wMnyh3 13 | C2Je+hQrBuiN1XhIqJ6lAkEAmYu2ap+vqHgsjDksnDy5zwMCzywbUBvGIa53zfyi 14 | KYoEmSaDc3AMqaxbxGHwMvPupGTvwiYPyQ+E0Qf5PXa5Kw== 15 | -----END RSA PRIVATE KEY----- --------------------------------------------------------------------------------