From e227cbf3d0dcc3df78a455035507950e13deec24 Mon Sep 17 00:00:00 2001 From: dengdonglin Date: Tue, 12 Mar 2013 17:02:35 +0800 Subject: [PATCH] alipay api --- index.js | 1 + lib/alipay.js | 477 ++++++++++++++++++ lib/alipay_core.function.js | 207 ++++++++ lib/alipay_md5.function.js | 52 ++ lib/alipay_notify.class.js | 146 ++++++ lib/alipay_submit.class.js | 171 +++++++ package.json | 36 ++ alipay_config.js => test/alipay_config.js | 18 +- app.js => test/app.js | 7 +- test/package.json | 12 + test/public/images/alipay.gif | Bin 0 -> 1511 bytes test/public/images/new-btn-fixed.png | Bin 0 -> 5902 bytes test/public/stylesheets/style.css | 8 + test/routes/alipaydemo.js | 127 +++++ test/views/create_direct_bankpay_by_user.ejs | 235 +++++++++ test/views/create_direct_pay_by_user.ejs | 219 ++++++++ test/views/create_partner_trade_by_buyer.ejs | 263 ++++++++++ test/views/index.ejs | 12 + test/views/refund_fastpay_by_platform_pwd.ejs | 221 ++++++++ test/views/send_goods_confirm_by_platform.ejs | 220 ++++++++ test/views/trade_create_by_buyer.ejs | 262 ++++++++++ 21 files changed, 2684 insertions(+), 10 deletions(-) create mode 100644 index.js create mode 100644 lib/alipay.js create mode 100644 lib/alipay_core.function.js create mode 100644 lib/alipay_md5.function.js create mode 100644 lib/alipay_notify.class.js create mode 100644 lib/alipay_submit.class.js create mode 100644 package.json rename alipay_config.js => test/alipay_config.js (79%) rename app.js => test/app.js (96%) create mode 100644 test/package.json create mode 100644 test/public/images/alipay.gif create mode 100644 test/public/images/new-btn-fixed.png create mode 100644 test/public/stylesheets/style.css create mode 100644 test/routes/alipaydemo.js create mode 100644 test/views/create_direct_bankpay_by_user.ejs create mode 100644 test/views/create_direct_pay_by_user.ejs create mode 100644 test/views/create_partner_trade_by_buyer.ejs create mode 100644 test/views/index.ejs create mode 100644 test/views/refund_fastpay_by_platform_pwd.ejs create mode 100644 test/views/send_goods_confirm_by_platform.ejs create mode 100644 test/views/trade_create_by_buyer.ejs diff --git a/index.js b/index.js new file mode 100644 index 0000000..8b656af --- /dev/null +++ b/index.js @@ -0,0 +1 @@ +module.exports = require('./lib/alipay'); \ No newline at end of file diff --git a/lib/alipay.js b/lib/alipay.js new file mode 100644 index 0000000..c221cbc --- /dev/null +++ b/lib/alipay.js @@ -0,0 +1,477 @@ +var AlipayNotify = require('./alipay_notify.class').AlipayNotify; +var AlipaySubmit = require('./alipay_submit.class').AlipaySubmit; +var assert = require('assert'); +var url = require('url'); +var inherits = require('util').inherits, + EventEmitter = require('events').EventEmitter; + +var DOMParser = require('xmldom').DOMParser; + +var default_alipay_config = { + partner:'' //合作身份者id,以2088开头的16位纯数字 + ,key:''//安全检验码,以数字和字母组成的32位字符 + ,seller_email:'' //卖家支付宝帐户 必填 + ,host:'http://localhost:3000/' //域名 + ,cacert:'cacert.pem'//ca证书路径地址,用于curl中ssl校验 请保证cacert.pem文件在当前文件夹目录中 + ,transport:'http' //访问模式,根据自己的服务器是否支持ssl访问,若支持请选择https;若不支持请选择http + ,input_charset:'utf-8'//字符编码格式 目前支持 gbk 或 utf-8 + ,sign_type:"MD5"//签名方式 不需修改 + ,create_direct_pay_by_user_return_url : '/alipay/create_direct_pay_by_user/return_url' + ,create_direct_pay_by_user_notify_url: '/alipay/create_direct_pay_by_user/notify_url' + ,refund_fastpay_by_platform_pwd_notify_url : '/alipay/refund_fastpay_by_platform_pwd/notify_url' + ,create_partner_trade_by_buyer_notify_url: '/aplipay/create_partner_trade_by_buyer/notify_url' + ,create_partner_trade_by_buyer_return_url: '/aplipay/create_partner_trade_by_buyer/return_url' + + ,trade_create_by_buyer_return_url : '/alipay/trade_create_by_buyer/return_url' + ,trade_create_by_buyer_notify_url: '/alipay/trade_create_by_buyer/notify_url' +}; + +function Alipay(alipay_config){ + EventEmitter.call(this); + + //default config + this.alipay_config = default_alipay_config; + //config merge + for(var key in alipay_config){ + this.alipay_config[key] = alipay_config[key]; + } +} + +/** + * @ignore + */ +inherits(Alipay, EventEmitter); + +Alipay.prototype.route = function(app){ + var self = this; + app.get(this.alipay_config.create_direct_pay_by_user_return_url, function(req, res){self.create_direct_pay_by_user_return(req, res)}); + app.post(this.alipay_config.create_direct_pay_by_user_notify_url, function(req, res){self.create_direct_pay_by_user_notify(req, res)}); + app.post(this.alipay_config.refund_fastpay_by_platform_pwd_notify_url, function(req, res){self.refund_fastpay_by_platform_pwd_notify(req, res)}); + + app.get(this.alipay_config.create_partner_trade_by_buyer_return_url, function(req, res){self.create_partner_trade_by_buyer_return(req, res)}); + app.post(this.alipay_config.create_partner_trade_by_buyer_notify_url, function(req, res){self.create_partner_trade_by_buyer_notify(req, res)}); + + app.get(this.alipay_config.trade_create_by_buyer_return_url, function(req, res){self.trade_create_by_buyer_return(req, res)}); + app.post(this.alipay_config.trade_create_by_buyer_notify_url, function(req, res){self.trade_create_by_buyer_notify(req, res)}); +} + +//支付宝即时到帐交易接口 +/*data{ + out_trade_no:'' //商户订单号, 商户网站订单系统中唯一订单号,必填 + ,subject:'' //订单名称 必填 + ,total_fee:'' //付款金额,必填 + ,body:'' //订单描述 + ,show_url:'' //商品展示地址 需以http://开头的完整路径,例如:http://www.xxx.com/myorder.html + }*/ + +Alipay.prototype.create_direct_pay_by_user = function(data, res){ + assert.ok(data.out_trade_no && data.subject && data.total_fee); + + //建立请求 + alipaySubmit = new AlipaySubmit(this.alipay_config); + + parameter = { + service:'create_direct_pay_by_user' + ,partner:this.alipay_config.partner + ,payment_type:'1' //支付类型 + ,notify_url: url.resolve(this.alipay_config.host, this.alipay_config.create_direct_pay_by_user_notify_url)//服务器异步通知页面路径,必填,不能修改, 需http://格式的完整路径,不能加?id=123这类自定义参数 + ,return_url: url.resolve(this.alipay_config.host , this.alipay_config.create_direct_pay_by_user_return_url)//页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,不能写成http://localhost/ + ,seller_email:this.alipay_config.seller_email //卖家支付宝帐户 必填 + ,_input_charset:this.alipay_config['input_charset'].toLowerCase().trim() + }; + for(var key in data){ + parameter[key] = data[key]; + } + + html_text = alipaySubmit.buildRequestForm(parameter,"get", "确认"); + res.send(html_text); +} + +//即时到账批量退款有密接口 +/* data{ + refund_date:'',//退款当天日期, 必填,格式:年[4位]-月[2位]-日[2位] 小时[2位 24小时制]:分[2位]:秒[2位],如:2007-10-01 13:13:13 + batch_no: '', //批次号, 必填,格式:当天日期[8位]+序列号[3至24位],如:201008010000001 + batch_num:'', //退款笔数, 必填,参数detail_data的值中,“#”字符出现的数量加1,最大支持1000笔(即“#”字符出现的数量999个) + detail_data: '',//退款详细数据 必填,具体格式请参见接口技术文档 +} */ +Alipay.prototype.refund_fastpay_by_platform_pwd = function(data, res){ + assert.ok(data.refund_date && data.batch_no && data.batch_num && data.detail_data); + //建立请求 + alipaySubmit = new AlipaySubmit(this.alipay_config); + + //构造要请求的参数数组,无需改动 + parameter = { + service : 'refund_fastpay_by_platform_pwd', + partner : this.alipay_config.partner, + notify_url : url.resolve(this.alipay_config.host, this.alipay_config.refund_fastpay_by_platform_pwd_notify_url), + seller_email : this.alipay_config.seller_email, + + refund_date : data.refund_date, + batch_no : data.batch_no, + batch_num : data.batch_num, + detail_data : data.detail_data, + + _input_charset : this.alipay_config['input_charset'].toLowerCase().trim() + }; + + html_text = alipaySubmit.buildRequestForm(parameter,"get", "确认"); + res.send(html_text); +} + +//支付宝纯担保交易接口接口 + +Alipay.prototype.create_partner_trade_by_buyer = function(data, res){ + //建立请求 + alipaySubmit = new AlipaySubmit(this.alipay_config); + + //构造要请求的参数数组,无需改动 + parameter = { + service : 'create_partner_trade_by_buyer', + partner : this.alipay_config.partner, + payment_type: '1', + notify_url : url.resolve(this.alipay_config.host, this.alipay_config.create_partner_trade_by_buyer_notify_url), + return_url : url.resolve(this.alipay_config.host , this.alipay_config.create_partner_trade_by_buyer_return_url), + seller_email : this.alipay_config.seller_email, + + out_trade_no : data.out_trade_no, + subject : data.subject, + price : data.price, + quantity : data.quantity, + logistics_fee : data.logistics_fee, + logistics_type : data.logistics_type, + logistics_payment : data.logistics_payment, + body : data.body, + show_url : data.show_url, + receive_name : data.receive_name, + receive_address : data.receive_address, + receive_zip : data.receive_zip, + receive_phone : data.receive_phone, + receive_mobile : data.receive_mobile, + + _input_charset : this.alipay_config['input_charset'].toLowerCase().trim() + }; + + html_text = alipaySubmit.buildRequestForm(parameter,"get", "确认"); + res.send(html_text); +} + +Alipay.prototype.send_goods_confirm_by_platform = function(data, res){ + //建立请求 + alipaySubmit = new AlipaySubmit(this.alipay_config); + + //构造要请求的参数数组,无需改动 + parameter = { + service : 'send_goods_confirm_by_platform', + partner : this.alipay_config.partner, + + trade_no : data.trade_no, + logistics_name : data.logistics_name, + invoice_no : data.invoice_no, + transport_type : data.transport_type, + + _input_charset : this.alipay_config['input_charset'].toLowerCase().trim() + }; + + alipaySubmit.buildRequestHttp(parameter, function(html_text){ + //解析XML html_text + var doc = new DOMParser().parseFromString(html_text); + var is_success = doc.getElementsByTagName('is_success').item(0).firstChild.nodeValue + if(is_success == 'T'){ + var out_trade_no = doc.getElementsByTagName('out_trade_no').item(0).firstChild.nodeValue; + var trade_no = doc.getElementsByTagName('trade_no').item(0).firstChild.nodeValue; + self.emit('send_goods_confirm_by_platform_success', out_trade_no, trade_no, html_text); + } + else if(is_success == 'F'){ + var error = doc.getElementsByTagName('error').item(0).firstChild.nodeValue; + self.emit('send_goods_confirm_by_platform_fail', error); + } + }); +} + +Alipay.prototype.trade_create_by_buyer = function(data, res){ + //建立请求 + alipaySubmit = new AlipaySubmit(this.alipay_config); + + //构造要请求的参数数组,无需改动 + parameter = { + service : 'trade_create_by_buyer', + partner : this.alipay_config.partner, + payment_type: '1', + notify_url : url.resolve(this.alipay_config.host, this.alipay_config.trade_create_by_buyer_notify_url), + return_url : url.resolve(this.alipay_config.host , this.alipay_config.trade_create_by_buyer_return_url), + seller_email : this.alipay_config.seller_email, + + out_trade_no : data.out_trade_no, + subject : data.subject, + price : data.price, + quantity : data.quantity, + logistics_fee : data.logistics_fee, + logistics_type : data.logistics_type, + logistics_payment : data.logistics_payment, + body : data.body, + show_url : data.show_url, + receive_name : data.receive_name, + receive_address : data.receive_address, + receive_zip : data.receive_zip, + receive_phone : data.receive_phone, + receive_mobile : data.receive_mobile, + + _input_charset : this.alipay_config['input_charset'].toLowerCase().trim() + }; + + html_text = alipaySubmit.buildRequestForm(parameter,"get", "确认"); + res.send(html_text); +} + +Alipay.prototype.trade_create_by_buyer_return = function(req, res){ + var self = this; + + var _GET = req.query; + //计算得出通知验证结果 + alipayNotify = new AlipayNotify(this.alipay_config); + //验证消息是否是支付宝发出的合法消息 + verify_result = alipayNotify.verifyReturn(_GET); + + if(verify_result) {//验证成功 + //商户订单号 + out_trade_no = _GET['out_trade_no']; + //支付宝交易号 + trade_no = _GET['trade_no']; + //交易状态 + trade_status = _GET['trade_status']; + + if(trade_status == 'WAIT_BUYER_PAY'){ + self.emit('trade_create_by_buyer_wait_buyer_pay', out_trade_no, trade_no); + } + else if(trade_status == 'WAIT_SELLER_SEND_GOODS'){ + self.emit('trade_create_by_buyer_wait_seller_send_goods', out_trade_no, trade_no); + } + else if(trade_status == 'WAIT_BUYER_CONFIRM_GOODS'){ + self.emit('trade_create_by_buyer_wait_buyer_confirm_goods', out_trade_no, trade_no); + } + else if(trade_status == 'TRADE_FINISHED'){ + self.emit('trade_create_by_buyer_trade_finished', out_trade_no, trade_no); + } + + res.send("success"); + } + else{ + //验证失败 + self.emit("verify_fail"); + res.send("fail"); + } +} + +Alipay.prototype.trade_create_by_buyer_notify = function(req, res){ + var self = this; + + var _POST = req.body; + //计算得出通知验证结果 + alipayNotify = new AlipayNotify(this.alipay_config); + //验证消息是否是支付宝发出的合法消息 + verify_result = alipayNotify.verifyNotify(_POST); + + if(verify_result) {//验证成功 + //商户订单号 + out_trade_no = _POST['out_trade_no']; + //支付宝交易号 + trade_no = _POST['trade_no']; + //交易状态 + trade_status = _POST['trade_status']; + + if(trade_status == 'WAIT_BUYER_PAY'){ + self.emit('trade_create_by_buyer_wait_buyer_pay', out_trade_no, trade_no); + } + else if(trade_status == 'WAIT_SELLER_SEND_GOODS'){ + self.emit('trade_create_by_buyer_wait_seller_send_goods', out_trade_no, trade_no); + } + else if(trade_status == 'WAIT_BUYER_CONFIRM_GOODS'){ + self.emit('trade_create_by_buyer_wait_buyer_confirm_goods', out_trade_no, trade_no); + } + else if(trade_status == 'TRADE_FINISHED'){ + self.emit('trade_create_by_buyer_trade_finished', out_trade_no, trade_no); + } + + res.send("success"); + } + else{ + //验证失败 + self.emit("verify_fail"); + res.send("fail"); + } +} + +Alipay.prototype.refund_fastpay_by_platform_pwd_notify = function(req, res){ + var self = this; + + var _POST = req.body; + //计算得出通知验证结果 + alipayNotify = new AlipayNotify(this.alipay_config); + //验证消息是否是支付宝发出的合法消息 + verify_result = alipayNotify.verifyNotify(_POST); + + if(verify_result) {//验证成功 + //批次号 + batch_no = _POST['batch_no']; + //批量退款数据中转账成功的笔数 + success_num = _POST['success_num']; + //批量退款数据中的详细信息 + result_details = _POST['result_details']; + + self.emit('refund_fastpay_by_platform_pwd_success', batch_no, success_num, result_details); + + res.send("success"); //请不要修改或删除 + } + else{ + //验证失败 + self.emit("verify_fail"); + res.send("fail"); + } +} + +Alipay.prototype.create_partner_trade_by_buyer_return = function(req, res){ + var self = this; + + var _GET = req.query; + //计算得出通知验证结果 + alipayNotify = new AlipayNotify(this.alipay_config); + //验证消息是否是支付宝发出的合法消息 + verify_result = alipayNotify.verifyReturn(_GET); + + if(verify_result) {//验证成功 + //商户订单号 + out_trade_no = _GET['out_trade_no']; + //支付宝交易号 + trade_no = _GET['trade_no']; + //交易状态 + trade_status = _GET['trade_status']; + + if(trade_status == 'WAIT_BUYER_PAY'){ + self.emit('create_partner_trade_by_buyer_wait_buyer_pay', out_trade_no, trade_no); + } + else if(trade_status == 'WAIT_SELLER_SEND_GOODS'){ + self.emit('create_partner_trade_by_buyer_wait_seller_send_goods', out_trade_no, trade_no); + } + else if(trade_status == 'WAIT_BUYER_CONFIRM_GOODS'){ + self.emit('create_partner_trade_by_buyer_wait_buyer_confirm_goods', out_trade_no, trade_no); + } + else if(trade_status == 'TRADE_FINISHED'){ + self.emit('create_partner_trade_by_buyer_trade_finished', out_trade_no, trade_no); + } + + res.send("success"); + } + else{ + //验证失败 + self.emit("verify_fail"); + res.send("fail"); + } +} + +Alipay.prototype.create_partner_trade_by_buyer_notify = function(req, res){ + var self = this; + + var _POST = req.body; + //计算得出通知验证结果 + alipayNotify = new AlipayNotify(this.alipay_config); + //验证消息是否是支付宝发出的合法消息 + verify_result = alipayNotify.verifyNotify(_POST); + + if(verify_result) {//验证成功 + //商户订单号 + out_trade_no = _POST['out_trade_no']; + //支付宝交易号 + trade_no = _POST['trade_no']; + //交易状态 + trade_status = _POST['trade_status']; + + if(trade_status == 'WAIT_BUYER_PAY'){ + self.emit('create_partner_trade_by_buyer_wait_buyer_pay', out_trade_no, trade_no); + } + else if(trade_status == 'WAIT_SELLER_SEND_GOODS'){ + self.emit('create_partner_trade_by_buyer_wait_seller_send_goods', out_trade_no, trade_no); + } + else if(trade_status == 'WAIT_BUYER_CONFIRM_GOODS'){ + self.emit('create_partner_trade_by_buyer_wait_buyer_confirm_goods', out_trade_no, trade_no); + } + else if(trade_status == 'TRADE_FINISHED'){ + self.emit('create_partner_trade_by_buyer_trade_finished', out_trade_no, trade_no); + } + + res.send("success"); + } + else{ + //验证失败 + self.emit("verify_fail"); + res.send("fail"); + } +} + +Alipay.prototype.create_direct_pay_by_user_notify = function(req, res){ + var self = this; + + var _POST = req.body; + //计算得出通知验证结果 + alipayNotify = new AlipayNotify(this.alipay_config); + //验证消息是否是支付宝发出的合法消息 + verify_result = alipayNotify.verifyNotify(_POST); + + if(verify_result) {//验证成功 + //商户订单号 + out_trade_no = _POST['out_trade_no']; + //支付宝交易号 + trade_no = _POST['trade_no']; + //交易状态 + trade_status = _POST['trade_status']; + + if(trade_status == 'TRADE_FINISHED'){ + self.emit('create_direct_pay_by_user_trade_finished', out_trade_no, trade_no); + } + else if(trade_status == 'TRADE_SUCCESS'){ + self.emit('create_direct_pay_by_user_trade_success', out_trade_no, trade_no); + } + res.send("success"); //请不要修改或删除 + } + else { + //验证失败 + self.emit("verify_fail"); + res.send("fail"); + } +} + +Alipay.prototype.create_direct_pay_by_user_return = function(req, res){ + var self = this; + + var _GET = req.query; + //计算得出通知验证结果 + alipayNotify = new AlipayNotify(this.alipay_config); + verify_result = alipayNotify.verifyReturn(_GET); + if(verify_result) {//验证成功 + //商户订单号 + out_trade_no = _GET['out_trade_no']; + //支付宝交易号 + trade_no = _GET['trade_no']; + //交易状态 + trade_status = _GET['trade_status']; + + if(trade_status == 'TRADE_FINISHED'){ + self.emit('create_direct_pay_by_user_trade_finished', out_trade_no, trade_no); + } + else if(trade_status == 'TRADE_SUCCESS'){ + self.emit('create_direct_pay_by_user_trade_success', out_trade_no, trade_no); + } + + res.send("success"); //请不要修改或删除 + } + else { + //验证失败 + self.emit("verify_fail"); + res.send("fail"); + } +} + +exports.Alipay = Alipay; + + + + diff --git a/lib/alipay_core.function.js b/lib/alipay_core.function.js new file mode 100644 index 0000000..3001cf4 --- /dev/null +++ b/lib/alipay_core.function.js @@ -0,0 +1,207 @@ +/** + * Created with JetBrains WebStorm. + * User: dengdl + * Date: 13-3-7 + * Time: 上午11:26 + * To change this template use File | Settings | File Templates. + */ + +var qs = require('querystring'); +var fs = require('fs'); +var https = require('https'); +//var Iconv = require('iconv').Iconv; + +/* * + * 支付宝接口公用函数 + * 详细:该类是请求、通知返回两个文件所调用的公用函数核心处理文件 + * 版本:3.3 + * 日期:2012-07-19 + * 说明: + * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 + * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。 + */ + +/** + * 把对象所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串 + * @param para 需要拼接的对象 + * return 拼接完成以后的字符串 + */ +exports.createLinkstring = function(para){ + return qs.stringify(para); +} + +/** + * 把对象所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码 + * @param para 需要拼接的对象 + * return 拼接完成以后的字符串 + */ +exports.createLinkstringUrlencode = function(para){ + return qs.stringify(para); +} + +/** + * 除去对象中的空值和签名参数 + * @param para 签名参对象 + * return 去掉空值与签名参数后的新签名参对象 + */ +exports.paraFilter = function(para){ + var para_filter = new Object(); + for (var key in para){ + if(key == 'sign' || key == 'sign_type' || para[key] == ''){ + continue; + } + else{ + para_filter[key] = para[key]; + } + } + + return para_filter; +} + +/** + * 对对象排序 + * @param para 排序前的对象 + * return 排序后的对象 + */ +exports.argSort = function(para){ + var result = new Object(); + var keys = Object.keys(para).sort(); + for (var i = 0; i < keys.length; i++){ + var k = keys[i]; + result[k] = para[k]; + } + return result; +} + +/** + * 写日志,方便测试(看网站需求,也可以改成把记录存入数据库) + * 注意:服务器需要开通fopen配置 + * @param word 要写入日志里的文本内容 默认值:空值 + */ +exports.logResult = function(word){ + word = word || ''; + var str = "执行日期:" + Date().toString() + "\n" + word + "\n"; + fs.appendFile('log.txt', str); +} + +/** + * 远程获取数据,POST模式 + * 注意: + * 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了 + * 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem' + * @param url 指定URL完整路径地址 + * @param cacert_url 指定当前工作目录绝对路径 + * @param para 请求的数据 + * @param input_charset 编码格式。默认值:空值 + * return 远程输出的数据 + */ +exports.getHttpResponsePOST = function(url, cacert_url, para, input_charset, callback){ + input_charset = input_charset || ''; + if(input_charset.trim() != ''){ + url = url + "_input_charset=" + input_charset; + } + + var parsed_url = require('url').parse(url); + + var para_str = qs.stringify(para); + + var options = { + hostname:parsed_url.host, + port:443, + path:parsed_url.path, + method:'POST', + cert:fs.readFileSync(cacert_url), + headers:{ + 'Content-Type':'application/x-www-form-urlencoded', + 'Content-Length':para_str.length + } + }; + + var req = https.request(options, function(res) { + var responseText=''; + res.on('data', function(chunk){ + responseText += chunk; + }); + res.on('end', function(){ + callback && callback(responseText); + }); + }); + + req.write(para_str); + req.end(); +} + +/** + * 远程获取数据,GET模式 + * 注意: + * 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了 + * 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem' + * @param url 指定URL完整路径地址 + * @param cacert_url 指定当前工作目录绝对路径 + * return 远程输出的数据 + */ +exports.getHttpResponseGET = function(url,cacert_url, callback){ + var parsed_url = require('url').parse(url); + + var options = { + hostname:parsed_url.host, + port:443, + path:parsed_url.path, + method:'GET', + cert:fs.readFileSync(cacert_url) + }; + + var req = https.request(options, function(res) { + var responseText=''; + res.on('data', function(chunk){ + responseText += chunk; + }); + res.on('end', function(){ + callback && callback(responseText); + }); + }); + + req.end(); +} + +/** + * 实现多种字符编码方式 + * @param input 需要编码的字符串 + * @param _output_charset 输出的编码格式 + * @param _input_charset 输入的编码格式 + * return 编码后的字符串 + */ +exports.charsetEncode = function(input,_output_charset ,_input_charset) { + output = ""; + _output_charset = _output_charset ||_input_charset; + if(_input_charset == _output_charset || input == null) { + output = input; + } + else { + //var iconv = new Iconv(_input_charset,_output_charset); + //output = iconv.convert(input); + } + + return output; +} + +/** + * 实现多种字符解码方式 + * @param input 需要解码的字符串 + * @param _output_charset 输出的解码格式 + * @param _input_charset 输入的解码格式 + * return 解码后的字符串 + */ +exports.charsetDecode = function(input,_input_charset ,_output_charset){ + output = ""; + _input_charset = _input_charset || _output_charset; + if(_input_charset == _output_charset || input == null) { + output = input; + } + else{ + //var iconv = new Iconv(_input_charset,_output_charset); + //output = iconv.convert(input); + } + + return output; +} diff --git a/lib/alipay_md5.function.js b/lib/alipay_md5.function.js new file mode 100644 index 0000000..2d007d6 --- /dev/null +++ b/lib/alipay_md5.function.js @@ -0,0 +1,52 @@ +/** + * Created with JetBrains WebStorm. + * User: dengdl + * Date: 13-3-7 + * Time: 下午2:33 + * To change this template use File | Settings | File Templates. + */ + +/* * + * MD5 + * 详细:MD5加密 + * 版本:3.3 + * 日期:2012-07-19 + * 说明: + * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 + * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。 + */ + +var crypto = require('crypto'); + +/** + * 签名字符串 + * @param prestr 需要签名的字符串 + * @param key 私钥 + * return 签名结果 + */ + +exports.md5Sign = function(prestr, key){ + prestr = prestr + key; + + return crypto.createHash('md5').update(prestr).digest("hex"); +} + +/** + * 验证签名 + * @param prestr 需要签名的字符串 + * @param sign 签名结果 + * @param key 私钥 + * return 签名结果 + */ + +exports.md5Verify = function(prestr, sign, key){ + prestr = prestr + key; + mysgin = crypto.createHash('md5').update(prestr).digest("hex"); + + if(mysgin == sign) { + return true; + } + else { + return false; + } +} \ No newline at end of file diff --git a/lib/alipay_notify.class.js b/lib/alipay_notify.class.js new file mode 100644 index 0000000..aaadd79 --- /dev/null +++ b/lib/alipay_notify.class.js @@ -0,0 +1,146 @@ +/** + * Created with JetBrains WebStorm. + * User: dengdl + * Date: 13-3-7 + * Time: 下午2:39 + * To change this template use File | Settings | File Templates. + */ + +/* * + * 类名:AlipayNotify + * 功能:支付宝通知处理类 + * 详细:处理支付宝各接口通知返回 + * 版本:3.2 + * 日期:2011-03-25 + * 说明: + * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 + * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考 + + *************************注意************************* + * 调试通知返回时,可查看或改写log日志的写入TXT里的数据,来检查通知返回是否正常 + */ + +var core_funcs = require('./alipay_core.function'); +var md5_f = require('./alipay_md5.function'); + +function AlipayNotify(alipay_config){ + /** + * HTTPS形式消息验证地址 + */ + this.https_verify_url = 'https://mapi.alipay.com/gateway.do?service=notify_verify&'; + /** + * HTTP形式消息验证地址 + */ + this.http_verify_url = 'http://notify.alipay.com/trade/notify_query.do?'; + this.alipay_config = alipay_config; +} + +/** + * 针对notify_url验证消息是否是支付宝发出的合法消息 + * @return 验证结果 + */ +AlipayNotify.prototype.verifyNotify = function(_POST){ + if(Object.keys(_POST).length == 0) {//判断POST来的数组是否为空 + return false; + } + else{ + //生成签名结果 + isSign = this.getSignVeryfy(_POST, _POST["sign"]); + //获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息) + responseTxt = 'true'; + if (null != _POST["notify_id"]) { + responseTxt = this.getResponse(_POST["notify_id"]); + } + + //验证 + //responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关 + //isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关 + if (responseTxt == 'true' && isSign) { //preg_match("/true/i",responseTxt) + return true; + } else { + return false; + } + } +} + +/** + * 针对return_url验证消息是否是支付宝发出的合法消息 + * @return 验证结果 + */ +AlipayNotify.prototype.verifyReturn = function(_GET){ + if(Object.keys(_GET).length == 0) {//判断POST来的数组是否为空 + return false; + } + else{ + //生成签名结果 + isSign = this.getSignVeryfy(_GET, _GET["sign"]); + //获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息) + responseTxt = 'true'; + if (null != _GET["notify_id"]) { + responseTxt = this.getResponse(_GET["notify_id"]); + } + + //验证 + //responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关 + //isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关 + if (responseTxt == 'true' && isSign) { + return true; + } else { + return false; + } + } +} + +/** + * 获取返回时的签名验证结果 + * @param para_temp 通知返回来的参数数组 + * @param sign 返回的签名结果 + * @return 签名验证结果 + */ +AlipayNotify.prototype.getSignVeryfy = function(para_temp, sign){ + //除去待签名参数数组中的空值和签名参数 + para_filter = core_funcs.paraFilter(para_temp); + + //对待签名参数数组排序 + para_sort = core_funcs.argSort(para_filter); + + //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串 + prestr = createLinkstring(para_sort); + + isSgin = false; + + sign_type = this.alipay_config['sign_type'].trim().toUpperCase(); + if(sign_type == "MD5"){ + isSgin = md5_f.md5Verify(prestr, sign, this.alipay_config['key']); + } + else{ + isSgin = false; + } + return isSgin; +} + +/** + * 获取远程服务器ATN结果,验证返回URL + * @param notify_id 通知校验ID + * @return 服务器ATN结果 + * 验证结果集: + * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空 + * true 返回正确信息 + * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟 + */ +AlipayNotify.prototype.getResponse = function(notify_id, callback){ + transport = this.alipay_config['transport'].trim().toLowerCase(); + partner = this.alipay_config['partner'].trim(); + veryfy_url = ''; + if(transport == 'https') { + veryfy_url = this.https_verify_url; + } + else { + veryfy_url = this.http_verify_url; + } + veryfy_url = veryfy_url + "partner=" + partner + "¬ify_id=" + notify_id; + + core_funcs.getHttpResponseGET(veryfy_url, this.alipay_config['cacert'], callback); +} + +exports.AlipayNotify = AlipayNotify; diff --git a/lib/alipay_submit.class.js b/lib/alipay_submit.class.js new file mode 100644 index 0000000..b62d68a --- /dev/null +++ b/lib/alipay_submit.class.js @@ -0,0 +1,171 @@ +/** + * Created with JetBrains WebStorm. + * User: dengdl + * Date: 13-3-7 + * Time: 下午3:43 + * To change this template use File | Settings | File Templates. + */ + +/* * + * 类名:AlipaySubmit + * 功能:支付宝各接口请求提交类 + * 详细:构造支付宝各接口表单HTML文本,获取远程HTTP数据 + * 版本:3.3 + * 日期:2012-07-23 + * 说明: + * 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。 + * 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。 + */ + +var core_funcs = require('./alipay_core.function'); +var md5_f = require('./alipay_md5.function'); +var DOMParser = require('xmldom').DOMParser; + +function AlipaySubmit(alipay_config){ + /** + *支付宝网关地址(新) + */ + this.alipay_gateway_new = 'https://mapi.alipay.com/gateway.do?'; + this.alipay_config = alipay_config; +} + +/** + * 生成签名结果 + * @param para_sort 已排序要签名的数组 + * return 签名结果字符串 + */ +AlipaySubmit.prototype.buildRequestMysign = function(para_sort){ + //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串 + prestr = core_funcs.createLinkstring(para_sort); + + mysign = ""; + + sign_type = this.alipay_config['sign_type'].trim().toUpperCase(); + if(sign_type == "MD5"){ + mysign = md5_f.md5Sign(prestr, this.alipay_config['key']); + } + else{ + mysign = ""; + } + return mysign; +} + +/** + * 生成要请求给支付宝的参数数组 + * @param para_temp 请求前的参数数组 + * @return 要请求的参数数组 + */ +AlipaySubmit.prototype.buildRequestPara = function(para_temp){ + //除去待签名参数数组中的空值和签名参数 + para_filter = core_funcs.paraFilter(para_temp); + + //对待签名参数数组排序 + para_sort = core_funcs.argSort(para_filter); + + //生成签名结果 + mysign = this.buildRequestMysign(para_sort); + + //签名结果与签名方式加入请求提交参数组中 + para_sort['sign'] = mysign; + para_sort['sign_type'] = this.alipay_config['sign_type'].trim().toUpperCase(); + + return para_sort; +} + +/** + * 生成要请求给支付宝的参数数组 + * @param para_temp 请求前的参数数组 + * @return 要请求的参数数组字符串 + */ +AlipaySubmit.prototype.buildRequestParaToString = function(para_temp){ + //待请求参数数组 + para = this.buildRequestPara(para_temp); + + //把参数组中所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码 + request_data = core_funcs.createLinkstringUrlencode(para); + + return request_data; +} + +/** + * 建立请求,以表单HTML形式构造(默认) + * @param para_temp 请求参数数组 + * @param method 提交方式。两个值可选:post、get + * @param button_name 确认按钮显示文字 + * @return 提交表单HTML文本 + */ +AlipaySubmit.prototype.buildRequestForm = function (para_temp, method, button_name) { + //待请求参数数组 + para = this.buildRequestPara(para_temp); + + sHtml = "
"; + + for(var key in para){ + val = para[key]; + sHtml += ""; + } + + //submit按钮控件请不要含有name属性 + sHtml = sHtml+ "
"; + + sHtml = sHtml + ""; + + return sHtml; +} + +/** + * 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果 + * @param para_temp 请求参数数组 + * @return 支付宝处理结果 + */ +AlipaySubmit.prototype.buildRequestHttp = function (para_temp, callback) { + //待请求参数数组字符串 + request_data = this.buildRequestPara(para_temp); + + //远程获取数据 + core_funcs.getHttpResponsePOST(this.alipay_gateway_new, this.alipay_config['cacert'],request_data,this.alipay_config['input_charset'].toLowerCase().trim(), callback); +} + +/** + * 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果,带文件上传功能 + * @param para_temp 请求参数数组 + * @param file_para_name 文件类型的参数名 + * @param file_name 文件完整绝对路径 + * @return 支付宝返回处理结果 + */ +AlipaySubmit.prototype.buildRequestHttpInFile = function (para_temp, file_para_name, file_name, callback) { + //待请求参数数组 + para = this.buildRequestPara(para_temp); + para[file_para_name] = "@" + file_name; + + //远程获取数据 + core_funcs.getHttpResponsePOST(this.alipay_gateway_new, this.alipay_config['cacert'],para,this.alipay_config['input_charset'].toLowerCase().trim(), callback); +} + +/** + * 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数 + * 注意:该功能PHP5环境及以上支持,因此必须服务器、本地电脑中装有支持DOMDocument、SSL的PHP配置环境。建议本地调试时使用PHP开发软件 + * return 时间戳字符串 + */ +AlipaySubmit.prototype.query_timestamp = function (callback) { + url = this.alipay_gateway_new + "service=query_timestamp&partner=" + this.alipay_config['partner'].toLowerCase().trim(); + + http.get(url, function(res) { + var responseText=''; + res.on('data', function(chunk){ + responseText += chunk; + }); + res.on('end', function(){ + var doc = new DOMParser().parseFromString(responseText); + var itemEncrypt_key = doc.getElementsByTagName( "encrypt_key" ); + var encrypt_key = itemEncrypt_key.item(0).nodeValue; + callback && callback(encrypt_key); + }); + }); +} + +exports.AlipaySubmit = AlipaySubmit; \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..3cda8bd --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "async", + "description": "Higher-order functions and common patterns for asynchronous code", + "main": "./lib/async", + "author": "Caolan McMahon", + "version": "0.2.6", + "repository" : { + "type" : "git", + "url" : "http://github.com/caolan/async.git" + }, + "bugs" : { + "url" : "http://github.com/caolan/async/issues" + }, + "licenses" : [ + { + "type" : "MIT", + "url" : "http://github.com/caolan/async/raw/master/LICENSE" + } + ], + "devDependencies": { + "nodeunit": ">0.0.0", + "uglify-js": "1.2.x", + "nodelint": ">0.0.0" + }, + "jam": { + "main": "lib/async.js", + "include": [ + "lib/async.js", + "README.md", + "LICENSE" + ] + }, + "scripts": { + "test": "nodeunit test/test-async.js" + } +} \ No newline at end of file diff --git a/alipay_config.js b/test/alipay_config.js similarity index 79% rename from alipay_config.js rename to test/alipay_config.js index 95ba4f5..41a38c9 100644 --- a/alipay_config.js +++ b/test/alipay_config.js @@ -1,9 +1,9 @@ -var config = { - partner:'' //合作身份者id,以2088开头的16位纯数字 - ,key:''//安全检验码,以数字和字母组成的32位字符 - ,seller_email:'' //卖家支付宝帐户 必填 -}; - -var Alipay = require('alipay').Alipay; - -exports.alipay = new Alipay(config); +var config = { + partner:'' //合作身份者id,以2088开头的16位纯数字 + ,key:''//安全检验码,以数字和字母组成的32位字符 + ,seller_email:'' //卖家支付宝帐户 必填 +}; + +var Alipay = require('alipay').Alipay; + +exports.alipay = new Alipay(config); \ No newline at end of file diff --git a/app.js b/test/app.js similarity index 96% rename from app.js rename to test/app.js index 27bb648..76e6044 100644 --- a/app.js +++ b/test/app.js @@ -1,3 +1,8 @@ + +/** + * Module dependencies. + */ + var express = require('express') , demo = require('./routes/alipaydemo') , http = require('http') @@ -25,7 +30,7 @@ app.configure('development', function(){ require('./alipay_config').alipay.route(app); -app.get('/', function(req, res){ +app.get('/', function(req, res){ res.render("index"); }); diff --git a/test/package.json b/test/package.json new file mode 100644 index 0000000..498e000 --- /dev/null +++ b/test/package.json @@ -0,0 +1,12 @@ +{ + "name": "application-name", + "version": "0.0.1", + "private": true, + "scripts": { + "start": "node app" + }, + "dependencies": { + "express": "3.0.3", + "ejs": "*" + } +} \ No newline at end of file diff --git a/test/public/images/alipay.gif b/test/public/images/alipay.gif new file mode 100644 index 0000000000000000000000000000000000000000..07e46e3966c0a74271d4dfb6ce033366481960e1 GIT binary patch literal 1511 zcmV3jcl-|A89+ha>-s zEdP%)|C2iZmqGoRM*p2m|D{_0sA2!BX8*2h|FCcWvvmKpc>lP4|GkF)zl#6BjsL`x z|HqmC%AfwtrT@>U|Iw@e)w2KFz5m|B|K-pB=+*!2-v966|M&3iZVTIL7Wt-R^3S#Z z;>`c%(*Nt*|M2Ah^61rcFaOJ^|LfhoZ$Qt8S^w6%uw*y8gk}Hz{Mp65o@Y{ySxK&y zl(Mq2W@ctrS63e&AOHXV000000000000000000000000000000A^8LW004IYEC2ui z0EYlA000O7fB}MogoTEOh>41ejE#t|`U8h6@@HqleOt z%i+(^-;*e=7L4VB)Tk#f@FpfA#v&XX7#J1p555}Xh@xSubiow~bpr_*TgZ@M2~7eU zN|boWgR2XT)&-cjFW)^8BILn)al(X!VGt*(WN4@bw^0(TA)Hkxp`;Bc0Tzmg%3LT^ zCLC$B2}uS{RK#==;@K^d3t6sKFkOjig&?AkP9asgRO6x&Kch~iD$44{sFO_adr+YT z*Fj_dA%%GP%k0daHOa2j5cI8}xQ!BU7`3*nAucow4b`jCu3x~6I*7u+;%rqyZlLJc z0VOZZNM7HLWi0Ao02Uiu45~XQ^9>s|baY;gHDhhjq!+3{#5zD`*uZVfwu~3_ZNHOR zp`wt8_3z-oXNSJ_8M&oit~NA}>KZ!m9G#~t5^vp6h+inSSFN$bdvG4an;NfPep2BI zltH8o0(9U=7Dike zTo-HzFbV}QKsx7L0p>ZWcQ-(Ch9FG921lcika2{k!Fds?pr%GCDSf}DxMy^e1YyGs z44g2Dt+)oaLlIRZ2Bl+A9-}IK!){547*jCu#34P{kcO|5sDMBmIJl_85KxriL=Fl((6%Bmj8K>;87y#!8&wSP+TDyd&UgKr0=Ig-j2{91RUsCkikg{RS<#0s z;DBFQRPlrnKqL?T*F602LlH(S0kzZuaz(?KQqbDX>}R+7*-r>tGXfHzwuUeysecfR NpadsK!AS%H06SYL-aY^T literal 0 HcmV?d00001 diff --git a/test/public/images/new-btn-fixed.png b/test/public/images/new-btn-fixed.png new file mode 100644 index 0000000000000000000000000000000000000000..ebdb2802438532e3377b512e464345e7b55934a3 GIT binary patch literal 5902 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 C6Q;oc literal 0 HcmV?d00001 diff --git a/test/public/stylesheets/style.css b/test/public/stylesheets/style.css new file mode 100644 index 0000000..30e047d --- /dev/null +++ b/test/public/stylesheets/style.css @@ -0,0 +1,8 @@ +body { + padding: 50px; + font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; +} + +a { + color: #00B7FF; +} \ No newline at end of file diff --git a/test/routes/alipaydemo.js b/test/routes/alipaydemo.js new file mode 100644 index 0000000..f112d14 --- /dev/null +++ b/test/routes/alipaydemo.js @@ -0,0 +1,127 @@ +var alipay = require('../alipay_config').alipay; +//alipay.on('verify_fail', function(){console.log('emit verify_fail')}); + +exports.create_direct_pay_by_user = function(req, res){ + if(req.route.method == 'get'){ + res.render('create_direct_pay_by_user'); + } + else if(req.route.method == 'post'){ + var data = { + out_trade_no:req.body.WIDout_trade_no + ,subject:req.body.WIDsubject + ,total_fee:req.body.WIDtotal_fee + ,body: req.body.WIDbody + ,show_url:req.body.WIDshow_url + }; + + alipay.create_direct_pay_by_user(data, res) + .on('verify_fail', function(){}) + .on('create_direct_pay_by_user_trade_finished', function(out_trade_no, trade_no){}) + .on('create_direct_pay_by_user_trade_success', function(out_trade_no, trade_no){}); + } +} + +exports.refund_fastpay_by_platform_pwd =function(req, res){ + if(req.route.method == 'get'){ + res.render('refund_fastpay_by_platform_pwd'); + } + else if(req.route.method == 'post'){ + var data = { + refund_date:req.body.WIDrefund_date + ,batch_no:req.body.WIDbatch_no + ,batch_num:req.body.WIDbatch_num + ,detail_data: req.body.WIDdetail_data + }; + + alipay.refund_fastpay_by_platform_pwd(data, res) + .on('verify_fail', function(){}) + .on('refund_fastpay_by_platform_pwd_success', function(batch_no, success_num, result_details){}) + + } +} + +exports.create_partner_trade_by_buyer = function(req, res){ + if(req.route.method == 'get'){ + res.render('create_partner_trade_by_buyer'); + } + else if(req.route.method == 'post'){ + var data = { + refund_date:req.body.WIDrefund_date + ,batch_no:req.body.WIDbatch_no + ,batch_num:req.body.WIDbatch_num + ,detail_data: req.body.WIDdetail_data + }; + + alipay.refund_fastpay_by_platform_pwd(data, res) + .on('verify_fail', function(){}) + .on('create_partner_trade_by_buyer_wait_buyer_pay', function(out_trade_no, trade_no){}) + .on('create_partner_trade_by_buyer_wait_seller_send_goods', function(out_trade_no, trade_no){}) + .on('create_partner_trade_by_buyer_wait_buyer_confirm_goods', function(out_trade_no, trade_no){}) + .on('create_partner_trade_by_buyer_trade_finished', function(out_trade_no, trade_no){}); + + } +} + +exports.send_goods_confirm_by_platform = function(req, res){ + if(req.route.method == 'get'){ + res.render('send_goods_confirm_by_platform'); + } + else if(req.route.method == 'post'){ + var data = { + trade_no:req.body.WIDtrade_no + ,logistics_name:req.body.WIDlogistics_name + ,invoice_no:req.body.WIDinvoice_no + ,transport_type: req.body.WIDtransport_type + }; + + alipay.send_goods_confirm_by_platform(data, res) + .on('send_goods_confirm_by_platform_fail', function(error){res.send(error)}) + .on('send_goods_confirm_by_platform_success', function(out_trade_no, trade_no, xml){}); + } +} + +exports.create_direct_bankpay_by_user = function(req, res){ + if(req.route.method == 'get'){ + res.render('create_direct_bankpay_by_user'); + } + else if(req.route.method == 'post'){ + var data = { + out_trade_no:req.body.WIDout_trade_no + ,subject:req.body.WIDsubject + ,total_fee:req.body.WIDtotal_fee + ,body: req.body.WIDbody + ,show_url:req.body.WIDshow_url + ,paymethod:'bankPay' + ,defaultbank:req.body.WIDdefaultbank + }; + + alipay.create_direct_pay_by_user(data, res) + .on('verify_fail', function(){}) + .on('create_direct_pay_by_user_trade_finished', function(out_trade_no, trade_no){}) + .on('create_direct_pay_by_user_trade_success', function(out_trade_no, trade_no){}); + } +} + +exports.trade_create_by_buyer = function(req, res){ + if(req.route.method == 'get'){ + res.render('trade_create_by_buyer'); + } + else if(req.route.method == 'post'){ + var data = { + out_trade_no:req.body.WIDout_trade_no + ,subject:req.body.WIDsubject + ,total_fee:req.body.WIDtotal_fee + ,body: req.body.WIDbody + ,show_url:req.body.WIDshow_url + ,paymethod:'bankPay' + ,defaultbank:req.body.WIDdefaultbank + }; + + alipay.trade_create_by_buyer(data, res) + .on('verify_fail', function(){}) + .on('trade_create_by_buyer_wait_buyer_pay', function(out_trade_no, trade_no){}) + .on('trade_create_by_buyer_wait_seller_send_goods', function(out_trade_no, trade_no){}) + .on('trade_create_by_buyer_wait_buyer_confirm_goods', function(out_trade_no, trade_no){}) + .on('trade_create_by_buyer_trade_finished', function(out_trade_no, trade_no){}); + } +} \ No newline at end of file diff --git a/test/views/create_direct_bankpay_by_user.ejs b/test/views/create_direct_bankpay_by_user.ejs new file mode 100644 index 0000000..c28aaef --- /dev/null +++ b/test/views/create_direct_bankpay_by_user.ejs @@ -0,0 +1,235 @@ + + + + + 支付宝纯网关接口接口 + + + + +
+ +
+
    +
  1. 1、确认信息 →
  2. +
  3. 2、点击确认 →
  4. +
  5. 3、确认完成
  6. +
+
+
+
+
+
商户订单号:
+
+ * + + 商户网站订单系统中唯一订单号,必填 + +
+
订单名称:
+
+ * + + 必填 + +
+
付款金额:
+
+ * + + 必填 + +
+
订单描述 +:
+
+ * + + +
+
默认网银:
+
+ * + + 必填,银行简码请参考接口技术文档 + +
+
商品展示地址:
+
+ * + + 需以http://开头的完整路径,例如:http://www.xxx.com/myorder.html + +
+
+
+ +
+
+
+
+ +
+ + \ No newline at end of file diff --git a/test/views/create_direct_pay_by_user.ejs b/test/views/create_direct_pay_by_user.ejs new file mode 100644 index 0000000..17a699e --- /dev/null +++ b/test/views/create_direct_pay_by_user.ejs @@ -0,0 +1,219 @@ + + + + 支付宝即时到账交易接口接口 + + + + +
+ +
+
    +
  1. 1、确认信息 →
  2. +
  3. 2、点击确认 →
  4. +
  5. 3、确认完成
  6. +
+
+
+
+
+ +
商户订单号:
+
+ * + + 商户网站订单系统中唯一订单号,必填 + +
+
订单名称:
+
+ * + + 必填 + +
+
付款金额:
+
+ * + + 必填 + +
+
订单描述 +:
+
+ * + + +
+
商品展示地址:
+
+ * + + 需以http://开头的完整路径,例如:http://www.xxx.com/myorder.html + +
+
+
+ +
+
+
+
+ +
+ + \ No newline at end of file diff --git a/test/views/create_partner_trade_by_buyer.ejs b/test/views/create_partner_trade_by_buyer.ejs new file mode 100644 index 0000000..e5023d6 --- /dev/null +++ b/test/views/create_partner_trade_by_buyer.ejs @@ -0,0 +1,263 @@ + + + + + 支付宝纯担保交易接口接口 + + + + +
+ +
+
    +
  1. 1、确认信息 →
  2. +
  3. 2、点击确认 →
  4. +
  5. 3、确认完成
  6. +
+
+
+
+
+ +
商户订单号:
+
+ * + + 商户网站订单系统中唯一订单号,必填 + +
+
订单名称:
+
+ * + + 必填 + +
+
付款金额:
+
+ * + + 必填 + +
+
订单描述 +:
+
+ * + + +
+
商品展示地址:
+
+ * + + 需以http://开头的完整路径,如:http://www.xxx.com/myorder.html + +
+
收货人姓名:
+
+ * + + 如:张三 + +
+
收货人地址:
+
+ * + + 如:XX省XXX市XXX区XXX路XXX小区XXX栋XXX单元XXX号 + +
+
收货人邮编:
+
+ * + + 如:123456 + +
+
收货人电话号码:
+
+ * + + 如:0571-88158090 + +
+
收货人手机号码:
+
+ * + + 如:13312341234 +
+
+
+ +
+
+
+
+ +
+ + \ No newline at end of file diff --git a/test/views/index.ejs b/test/views/index.ejs new file mode 100644 index 0000000..852c950 --- /dev/null +++ b/test/views/index.ejs @@ -0,0 +1,12 @@ +即时到帐收款 +

+网银支付 +

+即时到账批量退款 +

+担保交易收款 +

+支付宝确认发货 +

+双功能收款 +

\ No newline at end of file diff --git a/test/views/refund_fastpay_by_platform_pwd.ejs b/test/views/refund_fastpay_by_platform_pwd.ejs new file mode 100644 index 0000000..7e92130 --- /dev/null +++ b/test/views/refund_fastpay_by_platform_pwd.ejs @@ -0,0 +1,221 @@ + + + + + 支付宝即时到账批量退款有密接口接口 + + + + +
+ +
+
    +
  1. 1、确认信息 →
  2. +
  3. 2、点击确认 →
  4. +
  5. 3、确认完成
  6. +
+
+
+
+
+ +
退款当天日期:
+
+ * + + 必填,格式:年[4位]-月[2位]-日[2位] 小时[2位 24小时制]:分[2位]:秒[2位],如:2007-10-01 13:13:13 + +
+
批次号:
+
+ * + + 必填,格式:当天日期[8位]+序列号[3至24位],如:201008010000001 + +
+
退款笔数:
+
+ * + + 必填,参数detail_data的值中,“#”字符出现的数量加1,最大支持1000笔(即“#”字符出现的数量999个) + +
+
退款详细数据:
+
+ * + + 必填,具体格式请参见接口技术文档 +
+
+
+ +
+
+
+
+ +
+ + \ No newline at end of file diff --git a/test/views/send_goods_confirm_by_platform.ejs b/test/views/send_goods_confirm_by_platform.ejs new file mode 100644 index 0000000..233002d --- /dev/null +++ b/test/views/send_goods_confirm_by_platform.ejs @@ -0,0 +1,220 @@ + + + + + 支付宝确认发货接口接口 + + + + +
+ +
+
    +
  1. 1、确认信息 →
  2. +
  3. 2、点击确认 →
  4. +
  5. 3、确认完成
  6. +
+
+
+
+
+
支付宝交易号:
+
+ * + + 必填 + +
+
物流公司名称:
+
+ * + + 必填 + +
+
物流发货单号 +:
+
+ * + + +
+
物流运输类型:
+
+ * + + 三个值可选:POST(平邮)、EXPRESS(快递)、EMS(EMS) +
+
+
+ +
+
+
+
+ +
+ + \ No newline at end of file diff --git a/test/views/trade_create_by_buyer.ejs b/test/views/trade_create_by_buyer.ejs new file mode 100644 index 0000000..452120b --- /dev/null +++ b/test/views/trade_create_by_buyer.ejs @@ -0,0 +1,262 @@ + + + + + 支付宝标准双接口接口 + + + + +
+ +
+
    +
  1. 1、确认信息 →
  2. +
  3. 2、点击确认 →
  4. +
  5. 3、确认完成
  6. +
+
+
+
+
+
商户订单号:
+
+ * + + 商户网站订单系统中唯一订单号,必填 + +
+
订单名称:
+
+ * + + 必填 + +
+
付款金额:
+
+ * + + 必填 + +
+
订单描述 +:
+
+ * + + +
+
商品展示地址:
+
+ * + + 需以http://开头的完整路径,如:http://www.xxx.com/myorder.html + +
+
收货人姓名:
+
+ * + + 如:张三 + +
+
收货人地址:
+
+ * + + 如:XX省XXX市XXX区XXX路XXX小区XXX栋XXX单元XXX号 + +
+
收货人邮编:
+
+ * + + 如:123456 + +
+
收货人电话号码:
+
+ * + + 如:0571-88158090 + +
+
收货人手机号码:
+
+ * + + 如:13312341234 +
+
+
+ +
+
+
+
+ +
+ + \ No newline at end of file