├── .editorconfig
├── .eslintrc.json
├── .gitignore
├── CHANGELOG.md
├── README.md
├── alipay_in_weixin
└── pay.htm
├── demo
├── img
│ ├── bgpic.jpg
│ ├── logo.png
│ └── logo
│ │ └── logo-l.svg
├── styles
│ └── pinus.css
└── views
│ └── wap.html
├── dist
└── pingpp.js
├── gulpfile.js
├── mods.js.tmpl
├── package.json
├── src
├── agreement.js
├── callbacks.js
├── channels
│ ├── abc_pay.js
│ ├── abc_pub.js
│ ├── alipay.js
│ ├── alipay_lite.js
│ ├── alipay_pc_direct.js
│ ├── alipay_qr.js
│ ├── alipay_qr_lakala.js
│ ├── alipay_wap.js
│ ├── alipay_wap_lakala.js
│ ├── bfb_wap.js
│ ├── cb_alipay_pc_direct.js
│ ├── cb_alipay_wap.js
│ ├── cb_wx_pub.js
│ ├── ccb_qr.js
│ ├── ccb_wap.js
│ ├── chinaums_alipay_pub.js
│ ├── chinaums_alipay_wap.js
│ ├── chinaums_upacp_wap.js
│ ├── chinaums_wx_pub.js
│ ├── chinaums_wx_wap.js
│ ├── cmb_pc_qr.js
│ ├── cmb_wallet.js
│ ├── commons
│ │ └── redirect_base.js
│ ├── cp_b2b.js
│ ├── extras
│ │ ├── ap.js
│ │ └── wx_jssdk.js
│ ├── isv_lite.js
│ ├── isv_wap.js
│ ├── jdpay_wap.js
│ ├── nucc_b2b_lakala.js
│ ├── nucc_b2c_lakala.js
│ ├── pab_pc.js
│ ├── paypal.js
│ ├── qpay_pub.js
│ ├── upacp_b2b.js
│ ├── upacp_pc.js
│ ├── upacp_wap.js
│ ├── wx_lite.js
│ ├── wx_lite_pab.js
│ ├── wx_pub.js
│ ├── wx_pub_pab.js
│ ├── wx_wap.js
│ ├── yeepay_wap.js
│ ├── yeepay_wx_lite.js
│ ├── yeepay_wx_lite_ofl.js
│ ├── yeepay_wx_pub.js
│ └── yeepay_wx_pub_ofl.js
├── errors.js
├── init.js
├── libs
│ └── md5.js
├── main.js
├── mods.js
├── payment_elements.js
├── stash.js
├── testmode.js
├── transfer_channels
│ └── wx_pub.js
├── transfer_elements.js
├── utils.js
└── version.js
└── test
└── test.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | indent_style = space
6 | indent_size = 2
7 | charset = utf-8
8 |
9 | [*.js]
10 | indent_size = 2
11 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "commonjs": true,
5 | "es6": true
6 | },
7 | "extends": "eslint:recommended",
8 | "rules": {
9 | "indent": [
10 | "error",
11 | 2,
12 | {
13 | "SwitchCase": 1
14 | }
15 | ],
16 | "linebreak-style": [
17 | "error",
18 | "unix"
19 | ],
20 | "quotes": [
21 | "error",
22 | "single"
23 | ],
24 | "semi": [
25 | "error",
26 | "always"
27 | ],
28 | "no-console": 0,
29 | "max-len": [
30 | "error",
31 | 80,
32 | 4,
33 | {
34 | "ignoreComments": true,
35 | "ignoreUrls": true
36 | }
37 | ]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | package-lock.json
3 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # ChangeLog
2 |
3 | ## 2.3.1
4 |
5 | - 更新纯签约支付宝地址为 `https`
6 | - 更新 minimist 到 1.2.6 版本(CVE-2021-44906)
7 |
8 | ---
9 |
10 | ## 2.3.0
11 | - 新增: 支持易宝-微信公众号支付和易宝-微信小程序支付
12 | - 更新: 移除库分期支持
13 | - 更新: 移除杭州银行-微信公众号支付支持
14 |
15 | ## 2.2.27
16 |
17 | - 新增农行 app H5 支付和微信公众号唤起 农行app支付
18 |
19 | ---
20 |
21 | ## 2.2.26
22 |
23 | - 修复支付宝 PC 电脑网站签约跳转问题
24 |
25 | ---
26 |
27 | ## 2.2.25
28 |
29 | - mock 模拟支付地址修改为 `https`
30 |
31 | ---
32 |
33 | ## 2.2.24
34 |
35 | - 新增chinaums_alipay_wap, chinaums_upacp_wap, chinaums_wx_wap, chinaums_alipay_pub, chinaums_wx_pub
36 |
37 | ## 2.2.23
38 |
39 | - 新增 nucc_b2b_lakala,nucc_b2c_lakala
40 |
41 | ### 2.2.22
42 |
43 | - 修正:在部分“浏览器”无法正常打开的异常
44 |
45 | ### 2.2.21
46 |
47 | - 新增: 支持 ccb_wap
48 |
49 | ### 2.2.20
50 |
51 | - 新增:支持 wx_lite_pab
52 |
53 | ### 2.2.19
54 |
55 | - 新增:支持 alipay_wap_lakala, alipay_qr_lakala
56 |
57 | ### 2.2.18
58 |
59 | - 修改:支持 alipay 渠道在支付宝小程序或者支付宝内部网页使用
60 |
61 | ### 2.2.17
62 |
63 | - 新增:pab_pc, wx_pub_pab 渠道
64 |
65 | ### 2.2.16
66 |
67 | - 新增:小程序内使用 alipay 调起支付
68 |
69 | ### 2.2.15
70 |
71 | - 修正:支付宝小程序内报错修正
72 | - 新增:0 元订单直接返回 success
73 |
74 | ### 2.2.14
75 |
76 | - 新增:渠道 `isv_lite`
77 |
78 | ### 2.2.13
79 |
80 | - 新增:渠道 `coolcredit`
81 | - 修正:JSON 解析失败时的报错修正
82 |
83 | ### 2.2.12
84 |
85 | - 新增:渠道 `wx_pub_hzbank`
86 | - 更新:`gulp` 更新至 `4.0.0`
87 | - 更新:移除 `pingpp_ui`
88 |
89 | ### 2.2.11
90 |
91 | - 新增:签约接口 `pingpp.signAgreement(agr, callback)`
92 |
93 | ### 2.2.10
94 |
95 | - 修正:`cb_walipay_wap`、`cb_alipay_pc_direct` 的跳转地址
96 |
97 | ### 2.2.9 (2018-11-29)
98 |
99 | - 更新:新增 `alipay_lite` 渠道
100 |
101 | ### 2.2.7 (2018-11-05)
102 |
103 | - 更新:新增 `ccb_qr` 渠道
104 |
105 | ### 2.2.6 (2018-08-06)
106 | - 更新:判断是否在小程序内支付
107 |
108 | ### 2.2.5 (2018-07-26)
109 | - 新增:添加支付渠道 [ `cmb_pc_qr`]
110 |
111 | ### 2.2.4 (2018-06-22)
112 | - 新增:添加支付渠道 [ `upacp_b2b`]
113 | - 修复:修复 README.md 文档链接
114 | - 更新:更新微信小程序 [`wx_lite`]
115 |
116 | ### 2.2.3 (2018-04-13)
117 | - 新增:添加支付渠道 [ `cb_alipay_pc_direct` , `cb_alipay_wap` , `paypal`]
118 |
119 | ### 2.2.2 (2018-01-22)
120 | - 新增:wx_pub 跨境支付
121 | - 修改:支持小程序模拟支付
122 |
123 | ### 2.2.1 (2018-01-18)
124 | - 新增:`pingpp_ui`
125 |
126 | ### 2.1.16 (2017-12-11)
127 | - 新增: `pingpp.setUrlReturnCallback` 方法,支持获取支付页面地址而不是直接跳转
128 |
129 | ### 2.1.15 (2017-10-18)
130 | - 新增: 支付宝口碑渠道 (alipay_qr)
131 | - 修复:DOM security error
132 |
133 | ### 2.1.14 (2017-09-28)
134 | - 修复:账户系统 1.4 中多 charge 取值问题
135 |
136 | ### 2.1.13 (2017-08-28)
137 | - 更新:兼容账户系统 1.4
138 |
139 | ### 2.1.12 (2017-08-09)
140 | - 修复:测试模式下 wx_pub 中 notify url 报错问题
141 |
142 | ### 2.1.11 (2017-07-14)
143 | - 修复:修复alipay_pc_direct兼容性
144 |
145 | ### 2.1.10 (2017-07-11)
146 | - 新增:添加 招行一网通(cmb_wallet)
147 |
148 | ### 2.1.9 (2017-06-21)
149 | - 新增:添加 线下扫码渠道(isv_wap)
150 | - 更改:更新QQ钱包公众号
151 | - 更改: 兼容 alipay_pc_direct 2.0
152 | - 修复:localStorage为null报错
153 |
154 | ### 2.1.8 (2017-03-09)
155 | - 更改:兼容 IE10 浏览器
156 |
157 | ### 2.1.7 (2017-01-12)
158 | - 新增:添加 微信小程序
159 | - 更改:支付宝(alipay_wap)支持 openapi
160 |
161 | ### 2.1.6 (2017-01-04)
162 | - 修复:test 模式支付 order 成功 order 状态未更正问题
163 | - 新增:QQ 钱包公众号(qpay_pub)
164 |
165 | ### 2.1.5
166 | - 修复:Safari 无痕模式报错
167 |
168 | ### 2.1.4
169 | - require 源码,而不是构建完的 js
170 |
171 | ### 2.1.3
172 | - 新增:支持京东支付2.0
173 | - 修复:微信支付测试模式
174 | - 修复:Android WebView localStorage 兼容问题
175 |
176 | ### 2.1.2
177 | - 新增:支持 wx_wap
178 |
179 | ### 2.1.1
180 | - 更改:修复在 head 导入报错问题
181 |
182 | ### 2.1.0
183 | - 更改:支持模块化构建
184 |
185 | ### 2.0.8
186 | - 新增:添加企业网银支付(cp_b2b)
187 |
188 | ### 2.0.7
189 | - 更改:重命名文件名为 pingpp.js
190 | - 更改:删除无用配置
191 | - 新增:增加 PC 端接口,pingpp-pc.js,调用方式为 `pingppPc.createPayment(charge, callback)`
192 |
193 | ### 2.0.6
194 | - 新增:添加京东钱包 WAP 支付
195 |
196 | ### 2.0.5
197 | - 新增:添加易宝 WAP 支付
198 |
199 | ### 2.0.4
200 | - 更改:改进数组元素类型的判断
201 |
202 | ### 2.0.3
203 | - 新增:支持微信公众号 JS-SDK 调起支付
204 | - 新增:添加在微信中使用支付宝手机网页支付的处理
205 |
206 | ### 2.0.2
207 | - 更改:修正微信公众号 JSAPI 未加载完成时调用的问题
208 |
209 | ### 2.0.1
210 | - 更改:新的测试模式
211 | - 更改:合并 HTML5 和 微信公众号 SDK
212 |
213 | ### 2.0.0
214 | - 更改:添加新渠道:百付宝WAP
215 | - 更改:调用方法添加 callback,未跳转渠道前,出错时可返回错误信息
216 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pingpp HTML5 SDK
2 |
3 | ## 目录
4 |
5 | * [1. 使用 Ping++ SDK 标准版](#1)
6 | * [1.1 支持的渠道](#1.1)
7 | * [1.2 如何构建](#1.2)
8 | * [1.3 使用说明](#1.3)
9 | * [1.4 接入注意事项](#1.4)
10 |
11 | * [2. 常见问题](#2)
12 |
13 | ##
使用 Ping++ SDK 标准版
14 |
15 | ### 支持的渠道
16 |
17 | - 手机网页支付
18 | 1. 支付宝手机网页支付(alipay_wap)
19 | 2. 百度钱包手机网页支付(bfb_wap)
20 | 3. 银联全渠道手机网页支付(upacp_wap)
21 | 4. 微信WAP支付(wx_wap)
22 | 5. 微信小程序支付(wx_lite)
23 | 6. 易宝手机网页支付(yeepay_wap)
24 | 7. 京东手机网页支付(jdpay_wap)
25 | 8. 招行一网通支付(cmb_wallet)
26 |
27 | - PC 网页支付
28 | 1. 支付宝电脑网站支付 (alipay_pc_direct)
29 | 2. 银联网关支付 (upacp_pc)
30 | 3. 银联企业网银支付 (cp_b2b)
31 | 4. 拉卡拉网联B2C/B2B支付
32 |
33 | - 微信公众账号支付(wx_pub)
34 | - QQ 公众号支付 (qpay_pub)
35 | - 支付宝口碑 (alipay_qr)
36 | - 线下扫码支付(isv_wap)
37 | - 线下小程序支付(isv_lite)
38 |
39 | ### 如何构建
40 |
41 | [dist](/dist) 目录下提供了已经构建好的 SDK,使用的命令是 `gulp build --alipay_in_weixin --agreement`。
42 |
43 | #### 全局安装 gulp
44 |
45 | ``` bash
46 | npm install -g gulp
47 | ```
48 |
49 | #### 默认构建
50 |
51 | 默认会包含所有渠道
52 |
53 | ``` bash
54 | npm run build
55 | ```
56 |
57 | #### 自定义构建
58 |
59 | 安装依赖
60 |
61 | ``` bash
62 | npm install
63 | ```
64 |
65 | ##### --channels
66 |
67 | 选择渠道,渠道字段用空格或者英文逗号分割,例:
68 |
69 | ``` bash
70 | gulp build --channels="alipay_wap wx_pub upacp_wap"
71 | ```
72 |
73 | 可选的渠道模块请查看 [src/channels](/src/channels) 目录下的文件名
74 |
75 | ###### wx_lite
76 |
77 | 因为微信小程序中 不能使用其他支付渠道,构建时请添加该参数
78 |
79 | ``` bash
80 | gulp build --channels=wx_lite
81 | ```
82 |
83 | ##### --name
84 |
85 | 设置对象变量名
86 |
87 | ``` bash
88 | gulp build --name="pingppPc" --channels="alipay_pc_direct upacp_pc"
89 | ```
90 |
91 | ##### --alipay_in_weixin
92 |
93 | 如果要在微信内使用支付宝手机网页支付,请添加该参数
94 |
95 | ``` bash
96 | gulp build --alipay_in_weixin
97 | ```
98 |
99 | 同时,将 [`alipay_in_weixin`](/alipay_in_weixin) 目录下的 [pay.htm](/alipay_in_weixin/pay.htm) 放于你服务器可访问的路径下,如下两种方法:
100 |
101 | - 默认情况下,访问该文件的 URL 需要与你的支付页面时同级的。例:
102 | 支付页面 URL:http://localhost/project/payment?a=b&c=d
103 | 该文件 URL:http://localhost/project/pay.htm
104 |
105 | - 你也可以调用 `setAPURL` 方法来自定义该文件 URL。
106 |
107 | ``` js
108 | pingpp.setAPURL('http://localhost/your/custom/url');
109 | ```
110 |
111 | 该文件([pay.htm](/alipay_in_weixin/pay.htm))内的 `CURRENT_PAGE_URL` 变量也设置为相同的值。
112 |
113 | ##### --wx_jssdk
114 |
115 | 如果想使用微信的 JS-SDK 来调起支付,请添加该参数
116 |
117 | ``` bash
118 | gulp build --wx_jssdk
119 | ```
120 |
121 | ##### --agreement
122 |
123 | 如果需要使用签约接口,请添加该参数
124 |
125 | ``` bash
126 | gulp build --agreement
127 | ```
128 |
129 | ### 使用说明
130 |
131 | #### 引入 JS 文件
132 |
133 | - Browserify 打包方式
134 |
135 | 首先使用 `npm` 下载
136 |
137 | ``` bash
138 | npm install pingpp-js
139 | ```
140 |
141 | 使用
142 |
143 | ``` javascript
144 | var pingpp = require('pingpp-js');
145 | ```
146 |
147 | - script 标签方式
148 |
149 | ``` html
150 |
151 | ```
152 |
153 | #### 使用服务端创建的 [charge](https://www.pingxx.com/docs/overview) 调用接口
154 |
155 | ``` javascript
156 | // 参数一:支付参数 charge/order/recharge
157 | // 参数二:支付结果回调
158 | pingpp.createPayment(data, function(result, err) {
159 | if (result == "success") {
160 | // 只有微信公众账号 (wx_pub)、微信小程序 (wx_lite)、QQ 公众号 (qpay_pub)、支付宝口碑 (alipay_qr)
161 | // 支付成功的结果会在这里返回,其他的支付结果都会跳转到 extra 中对应的 URL。
162 | } else if (result == "fail") {
163 | // data 不正确或者微信公众账号/微信小程序/QQ 公众号/支付宝口碑支付失败时会在此处返回
164 | } else if (result == "cancel") {
165 | // 微信公众账号、微信小程序、QQ 公众号、支付宝口碑支付取消支付
166 | }
167 | });
168 | ```
169 |
170 | 如果 `charge` 正确的话,会跳转到相应的支付页面,要求用户进行付款。
171 |
172 | 用户支付成功后,会跳转到创建 `charge` 时定义的 `result_url` 或者 `success_url`。如果用户取消支付,则会跳转到 `result_url` 或者 `cancel_url`(具体情况根据渠道不同会有所变化)。
173 |
174 | #### 如果不想直接跳转到支付页面,而是获取支付页面地址
175 |
176 | 在调用 `pingpp.createPayment` 之前,调用
177 |
178 | ```javascript
179 | pingpp.setUrlReturnCallback(callback, channels);
180 | ```
181 |
182 | ##### 参数 callback
183 |
184 | 回调函数
185 |
186 | - 第一个参数接受错误信息,没有错误时为 null。
187 | - 第二个参数为支付界面地址的值。
188 |
189 | ##### 参数 channels
190 |
191 | 需要启用该功能的渠道列表,类型为 `array`。默认值为 `['alipay_pc_direct']`。
192 |
193 | ##### 示例
194 |
195 | ```javascript
196 | pingpp.setUrlReturnCallback(function (err, url) {
197 | // 自行处理跳转或者另外打开支付页面地址(url)
198 | // window.location.href = url;
199 | }, ['alipay_pc_direct', 'alipay_wap']);
200 | ```
201 |
202 | #### 调用签约接口
203 |
204 | 从服务端获取 `agreement` 对象之后,调用
205 |
206 | ```js
207 | pingpp.signAgreement(agreement, callback);
208 | ```
209 |
210 | 签约接口在对象不正确等情况下,会回调 `callback`。
211 |
212 | 如果对象正确,则会跳转到相应的签约页面,签约结果**不会**在 `callback` 返回,需要商户自己调用服务端接口查询 `agreement` 状态。
213 |
214 | ### 微信公众号接入注意事项
215 |
216 | _以下示例中,Server-SDK 以 `php` 为例,其他语言请参考各语言 SDK 的文档或者示例_
217 |
218 | #### 关于 open_id
219 |
220 | ##### 用 Server-SDK 取得 `open_id`(微信公众号授权用户唯一标识)。
221 |
222 | 先跳转到微信获取`授权 code`,地址由下方代码生成,`$wx_app_id` 是你的`微信公众号应用唯一标识`,`$redirect_url` 是用户确认授权后跳转的地址,用来接收 `code`。
223 |
224 | ```php
225 | 常见问题
327 |
328 | #### 问题一: H5 页面微信公众号支付调用 Ping++ 提示失败 (来源:工单)
329 |
330 | 返回结果: `get_brand_wcpay_request: fail`
331 |
332 | - 报错原因:微信授权目录填写错误。
333 | - 解决方案:详见[帮助中心](https://help.pingxx.com/article/123339)
334 |
335 | #### 问题二:微信内调用支付宝没出现引导界面,只有复制链接到浏览器
336 |
337 | - 报错原因:pay.htm 路径出错
338 | - 解决方案:
339 | 1. 默认情况下,访问该文件的 URL 需要与你的支付页面时同级的。例:
340 | 支付页面 URL:http://localhost/project/payment?a=b&c=d
341 | 该文件 URL:http://localhost/project/pay.htm
342 | 2. 你也可以调用 `setAPURL` 方法来自定义该文件 URL。
343 |
344 | ``` js
345 | pingpp.setAPURL('http://localhost/your/custom/url');
346 | ```
347 |
348 | 该文件([pay.htm](/alipay_in_weixin/pay.htm))内的 `CURRENT_PAGE_URL` 变量也设置为相同的值。
349 |
350 | #### 问题三:调不起支付,返回报错信息 json_decode_fail
351 |
352 | - 报错原因:传入的参数不是正确的 JSON 字符串或者 JSON 对象
353 | - 解决方案:客户端调用 SDK 时,确认服务端输出到客户端时,数据的正确性。
354 |
--------------------------------------------------------------------------------
/alipay_in_weixin/pay.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 支付提示
6 |
7 |
8 |
9 |
10 |
11 |
112 |
113 |
114 |
115 |
116 | 请在菜单中选择在浏览器中打开,
117 | 以完成支付
118 |
119 |
120 |
121 |
122 |
125 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/demo/img/bgpic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PingPlusPlus/pingpp-js/fcbb68b567f4beb4b09c89282ab1d8375b16a4ee/demo/img/bgpic.jpg
--------------------------------------------------------------------------------
/demo/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PingPlusPlus/pingpp-js/fcbb68b567f4beb4b09c89282ab1d8375b16a4ee/demo/img/logo.png
--------------------------------------------------------------------------------
/demo/img/logo/logo-l.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/demo/styles/pinus.css:
--------------------------------------------------------------------------------
1 | * {
2 | -webkit-box-sizing: border-box;
3 | -moz-box-sizing: border-box;
4 | box-sizing: border-box;
5 | -webkit-box-shadow: none;
6 | box-shadow: none;
7 | border: none;
8 | }
9 | html,
10 | body {
11 | border: 0;
12 | font-family: "Helvetica-Neue", "Helvetica", Arial, sans-serif;
13 | line-height: 1.5;
14 | margin: 0;
15 | padding: 0;
16 | width: 100%;
17 | }
18 | div,
19 | span,
20 | object,
21 | iframe,
22 | img,
23 | table,
24 | caption,
25 | thead,
26 | tbody,
27 | tfoot,
28 | tr,
29 | tr,
30 | td,
31 | article,
32 | aside,
33 | canvas,
34 | details,
35 | figure,
36 | hgroup,
37 | menu,
38 | nav,
39 | footer,
40 | header,
41 | section,
42 | summary,
43 | mark,
44 | audio,
45 | video {
46 | border: 0;
47 | margin: 0;
48 | padding: 0;
49 | }
50 | h1,
51 | h2,
52 | h3,
53 | h4,
54 | h5,
55 | h6,
56 | p,
57 | blockquote,
58 | pre,
59 | a,
60 | abbr,
61 | address,
62 | cit,
63 | code,
64 | del,
65 | dfn,
66 | em,
67 | ins,
68 | q,
69 | samp,
70 | small,
71 | strong,
72 | sub,
73 | sup,
74 | b,
75 | i,
76 | hr,
77 | dl,
78 | dt,
79 | dd,
80 | ol,
81 | ul,
82 | li,
83 | fieldset,
84 | legend,
85 | label {
86 | border: 0;
87 | font-size: 100%;
88 | vertical-align: baseline;
89 | margin: 0;
90 | padding: 0;
91 | }
92 | article,
93 | aside,
94 | canvas,
95 | figure,
96 | figure img,
97 | figcaption,
98 | hgroup,
99 | footer,
100 | header,
101 | nav,
102 | section,
103 | audio,
104 | video {
105 | display: block;
106 | }
107 | table {
108 | border-collapse: separate;
109 | border-spacing: 0;
110 | }
111 | table caption,
112 | table th,
113 | table td {
114 | text-align: left;
115 | vertical-align: middle;
116 | }
117 | a img {
118 | border: 0;
119 | }
120 | :focus {
121 | outline: 0;
122 | }
123 | /* color */
124 | /* spacing */
125 | /* fontsize */
126 | /* screen & popup & content */
127 | /* btn */
128 | * {
129 | color: #4d4d4d;
130 | font-size: 14px;
131 | font-weight: 100;
132 | -webkit-font-smoothing: antialiased;
133 | line-height: 2;
134 | font-family: AvenirNext-Regular, 'proxima-nova', 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', 'Open Sans', 'Helvetica Neue', Arial, sans-serif;
135 | }
136 | ::selection {
137 | color: #ffffff;
138 | text-shadow: none;
139 | background: #4d4d4d;
140 | }
141 | p {
142 | font-size: 14px;
143 | line-height: 2;
144 | padding: 7px 0;
145 | }
146 | a {
147 | color: #4d4d4d;
148 | text-decoration: none;
149 | -webkit-transition: all 0.2s ease-out;
150 | -moz-transition: all 0.2s ease-out;
151 | -ms-transition: all 0.2s ease-out;
152 | -o-transition: all 0.2s ease-out;
153 | }
154 | li {
155 | list-fx-position: outside;
156 | text-align: -webkit-match-parent;
157 | }
158 | code {
159 | font-family: monospace, menlo;
160 | }
161 | q {
162 | quotes: "「" "」";
163 | }
164 | b {
165 | font-weight: bold;
166 | }
167 | h1 {
168 | font-size: 36px;
169 | }
170 | h2 {
171 | font-size: 24px;
172 | }
173 | h3 {
174 | font-size: 14px;
175 | font-weight: bold;
176 | }
177 | /* block > content */
178 | .block {
179 | width: 100%;
180 | display: block;
181 | max-width: 1440px;
182 | margin: auto;
183 | padding: 84px 0;
184 | }
185 | @media (min-width: 480px) {
186 | .block {
187 | padding: 84px 0;
188 | }
189 | }
190 | @media (min-width: 768px) {
191 | .block {
192 | padding: 84px 0;
193 | }
194 | }
195 | @media (min-width: 1024px) {
196 | .block {
197 | padding: 84px 0;
198 | }
199 | }
200 | .popup .shadow {
201 | width: 100%;
202 | height: 100%;
203 | display: block;
204 | position: fixed;
205 | top: 0;
206 | background: rgba(0, 0, 0, 0.25);
207 | }
208 | .popup .paper {
209 | background: #ffffff;
210 | display: block;
211 | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
212 | -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
213 | -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
214 | margin: 0 auto;
215 | padding: 28px 0;
216 | width: 100%;
217 | }
218 | @media (min-width: 480px) {
219 | .popup .paper {
220 | margin: 28px auto;
221 | padding: 28px 0;
222 | width: 424px;
223 | }
224 | }
225 | @media (min-width: 768px) {
226 | .popup .paper {
227 | margin: 56px auto;
228 | padding: 56px 0;
229 | width: 656px;
230 | }
231 | }
232 | @media (min-width: 1024px) {
233 | .popup .paper {
234 | margin: 56px auto;
235 | padding: 56px 0;
236 | width: 912px;
237 | }
238 | }
239 | .content {
240 | display: block;
241 | margin-left: auto;
242 | margin-right: auto;
243 | min-width: 768px;
244 | width: 304px;
245 | }
246 | @media (min-width: 480px) {
247 | .content {
248 | width: 368px;
249 | }
250 | }
251 | @media (min-width: 768px) {
252 | .content {
253 | width: 544px;
254 | }
255 | }
256 | @media (min-width: 1024px) {
257 | .content {
258 | width: 100%;
259 | max-width: 1440px;
260 | }
261 | }
262 | .grid-2 {
263 | overflow: hidden;
264 | }
265 | .grid-2 .cell {
266 | width: 100%;
267 | display: inline-block;
268 | float: left;
269 | }
270 | @media (min-width: 480px) {
271 | .grid-2 .cell {
272 | width: 100%;
273 | }
274 | }
275 | @media (min-width: 768px) {
276 | .grid-2 .cell {
277 | width: 244px;
278 | }
279 | .grid-2 .cell:first-child {
280 | margin-right: 56px;
281 | margin-bottom: 28px;
282 | }
283 | }
284 | @media (min-width: 1024px) {
285 | .grid-2 .cell {
286 | width: 372px;
287 | }
288 | .grid-2 .cell:first-child {
289 | margin-right: 56px;
290 | margin-bottom: 28px;
291 | }
292 | }
293 | header {
294 | width: 100%;
295 | background: #ffffff;
296 | position: fixed;
297 | }
298 | header .content {
299 | padding: 0;
300 | padding-top: 28px;
301 | min-width: 768px;
302 | }
303 | header .content a {
304 | line-height: 1;
305 | padding: 14px 0;
306 | }
307 | header .content a:active {
308 | background: #f7f7f7;
309 | }
310 | header .content .logo {
311 | height: 42px;
312 | }
313 | header .content .logo span {
314 | display: block;
315 | background: url(../img/logo/logo-l.svg) no-repeat top center;
316 | -webkit-background-size: cover;
317 | background-size: cover;
318 | width: 52px;
319 | height: 7px;
320 | }
321 | header .content .logo:active {
322 | background: none;
323 | opacity: 0.5;
324 | }
325 | header .space {
326 | display: block;
327 | height: 0;
328 | }
329 | @media (min-width: 768px) {
330 | header .content {
331 | overflow: hidden;
332 | }
333 | header .content .left {
334 | float: left;
335 | }
336 | header .content .right {
337 | float: right;
338 | }
339 | header .content a {
340 | display: inline-block;
341 | padding: 14px 14px;
342 | }
343 | header .content .logo {
344 | padding-left: 0;
345 | padding-right: 0;
346 | }
347 | }
348 | footer {
349 | background: #ffffff;
350 | }
351 | footer .content {
352 | padding: 0 !important;
353 | padding-bottom: 14px !important;
354 | }
355 | footer .content a {
356 | display: block;
357 | line-height: 1;
358 | padding: 14px 0;
359 | }
360 | footer .content a:active {
361 | background: #f7f7f7;
362 | }
363 | footer .content .copyright {
364 | padding: 0;
365 | display: block;
366 | padding-top: 14px;
367 | }
368 | footer .content .endorse {
369 | font-size: 10px;
370 | padding: 0;
371 | padding-bottom: 7px;
372 | line-height: 2;
373 | color: #999999;
374 | }
375 | @media (min-width: 768px) {
376 | footer .content {
377 | overflow: hidden;
378 | }
379 | footer .content a {
380 | display: inline-block;
381 | padding: 14px 14px;
382 | }
383 | footer .content .left {
384 | float: left;
385 | }
386 | footer .content .right {
387 | float: right;
388 | }
389 | }
390 | form label {
391 | display: block;
392 | width: 100%;
393 | }
394 | form .options input[type="radio"] {
395 | display: none;
396 | }
397 | form .options label {
398 | width: auto;
399 | display: inline-block;
400 | margin-right: 14px;
401 | }
402 | form .options label:before {
403 | content: "";
404 | display: inline-block;
405 | position: relative;
406 | top: 2px;
407 | width: 14px;
408 | height: 14px;
409 | margin-right: 7px;
410 | border-radius: 14px;
411 | -webkit-border-radius: 14px;
412 | -moz-border-radius: 14px;
413 | -moz-box-shadow: inset 0px 0px 0px 1px #b3b3b3;
414 | -webkit-box-shadow: inset 0px 0px 0px 1px #b3b3b3;
415 | box-shadow: inset 0px 0px 0px 1px #b3b3b3;
416 | background: rgba(0, 0, 0, 0);
417 | -webkit-transition: all 0.2s ease-out;
418 | -moz-transition: all 0.2s ease-out;
419 | -ms-transition: all 0.2s ease-out;
420 | -o-transition: all 0.2s ease-out;
421 | }
422 | form .options label:hover {
423 | cursor: pointer;
424 | }
425 | form .options label:active:before {
426 | -moz-box-shadow: inset 0px 0px 0px 1px #4d4d4d;
427 | -webkit-box-shadow: inset 0px 0px 0px 1px #4d4d4d;
428 | box-shadow: inset 0px 0px 0px 1px #4d4d4d;
429 | }
430 | form .options input[type="radio"]:checked + label:before {
431 | -moz-box-shadow: inset 0px 0px 0px 1px #4d4d4d;
432 | -webkit-box-shadow: inset 0px 0px 0px 1px #4d4d4d;
433 | box-shadow: inset 0px 0px 0px 1px #4d4d4d;
434 | background: #4d4d4d;
435 | }
436 | form input[type='text'] {
437 | -webkit-transition: all 0.2s ease-out;
438 | -moz-transition: all 0.2s ease-out;
439 | -ms-transition: all 0.2s ease-out;
440 | -o-transition: all 0.2s ease-out;
441 | -moz-box-shadow: inset 0px -1px 0px 0px #b3b3b3;
442 | -webkit-box-shadow: inset 0px -1px 0px 0px #b3b3b3;
443 | box-shadow: inset 0px -1px 0px 0px #b3b3b3;
444 | font-weight: normal;
445 | background: none;
446 | }
447 | form input[type='text']:focus {
448 | -moz-box-shadow: inset 0px -1px 0px 0px #4d4d4d;
449 | -webkit-box-shadow: inset 0px -1px 0px 0px #4d4d4d;
450 | box-shadow: inset 0px -1px 0px 0px #4d4d4d;
451 | }
452 | form textarea {
453 | -webkit-transition: all 0.2s ease-out;
454 | -moz-transition: all 0.2s ease-out;
455 | -ms-transition: all 0.2s ease-out;
456 | -o-transition: all 0.2s ease-out;
457 | -moz-box-shadow: inset 0px -1px 0px 0px #b3b3b3;
458 | -webkit-box-shadow: inset 0px -1px 0px 0px #b3b3b3;
459 | box-shadow: inset 0px -1px 0px 0px #b3b3b3;
460 | display: block;
461 | min-width: 100%;
462 | min-height: 100px;
463 | resize: vertical;
464 | font-weight: normal;
465 | background: none;
466 | }
467 | form textarea:focus {
468 | -moz-box-shadow: inset 0px -1px 0px 0px #4d4d4d;
469 | -webkit-box-shadow: inset 0px -1px 0px 0px #4d4d4d;
470 | box-shadow: inset 0px -1px 0px 0px #4d4d4d;
471 | }
472 | form .btn-bar button {
473 | -webkit-transition: all 0.2s ease-out;
474 | -moz-transition: all 0.2s ease-out;
475 | -ms-transition: all 0.2s ease-out;
476 | -o-transition: all 0.2s ease-out;
477 | background: none;
478 | font-weight: normal;
479 | padding: 7px 14px;
480 | display: inline-block;
481 | margin-bottom: 7px;
482 | width: 100%;
483 | min-width: 120px;
484 | display: block;
485 | }
486 | form .btn-bar button:hover {
487 | cursor: pointer;
488 | }
489 | form .btn-bar button:active {
490 | background: #f7f7f7;
491 | }
492 | @media (min-width: 480px) {
493 | form .btn-bar button {
494 | margin-right: 7px;
495 | width: auto;
496 | display: inline-block;
497 | }
498 | form .btn-bar button:last-child {
499 | margin-right: auto;
500 | }
501 | }
502 | form .btn-bar .btn-main {
503 | -webkit-transition: all 0.2s ease-out;
504 | -moz-transition: all 0.2s ease-out;
505 | -ms-transition: all 0.2s ease-out;
506 | -o-transition: all 0.2s ease-out;
507 | background: none;
508 | font-weight: normal;
509 | padding: 7px 14px;
510 | background: #4d4d4d;
511 | color: #ffffff;
512 | }
513 | form .btn-bar .btn-main:hover {
514 | cursor: pointer;
515 | }
516 | form .btn-bar .btn-main:active {
517 | background: #000000;
518 | }
519 | article h1 {
520 | margin-top: 28px;
521 | }
522 | article h2 {
523 | margin-top: 28px;
524 | }
525 | article h3 {
526 | margin-top: 28px;
527 | margin-bottom: 14px;
528 | }
529 | article code {
530 | background: #f7f7f7;
531 | border-radius: 3px;
532 | -webkit-border-radius: 3px;
533 | -moz-border-radius: 3px;
534 | }
535 | article pre {
536 | min-width: 100%;
537 | padding: 14px;
538 | background: #f7f7f7;
539 | }
540 | article table {
541 | min-width: 100%;
542 | }
543 | article a {
544 | -moz-box-shadow: inset 0px -1px 0px 0px #b3b3b3;
545 | -webkit-box-shadow: inset 0px -1px 0px 0px #b3b3b3;
546 | box-shadow: inset 0px -1px 0px 0px #b3b3b3;
547 | }
548 | article a:active {
549 | -moz-box-shadow: inset 0px -1px 0px 0px #4d4d4d;
550 | -webkit-box-shadow: inset 0px -1px 0px 0px #4d4d4d;
551 | box-shadow: inset 0px -1px 0px 0px #4d4d4d;
552 | }
553 | /*
554 |
555 | app.less
556 |
557 |
558 | */
559 | footer {
560 | position: relative;
561 | background: none;
562 | }
563 | header {
564 | position: relative;
565 | }
566 | header .h_content {
567 | width: 100%;
568 | height: auto;
569 | padding-top: 28px;
570 | }
571 | header .h_content span {
572 | width: 86px;
573 | height: 14px;
574 | margin: auto;
575 | display: block;
576 | background: url(../img/logo.png) no-repeat top center;
577 | margin-bottom: 14px;
578 | }
579 | body {
580 | height: 100%;
581 | overflow-x: hidden;
582 | }
583 | footer {
584 | position: relative;
585 | bottom: 0;
586 | }
587 | footer .content2 {
588 | padding: 0 !important;
589 | padding-bottom: 14px !important;
590 | }
591 | footer .content2 a {
592 | display: block;
593 | line-height: 1;
594 | padding: 14px;
595 | }
596 | footer .content2 a:active {
597 | background: #f7f7f7;
598 | }
599 | footer .content2 .copyright {
600 | padding: 0;
601 | display: block;
602 | padding-left: 14px;
603 | }
604 | footer .content2 .endorse {
605 | font-size: 10px;
606 | padding: 0;
607 | padding-left: 14px;
608 | line-height: 2;
609 | color: #999999;
610 | }
611 | @media (max-width: 640px) {
612 | footer {
613 | position: relative;
614 | }
615 | }
616 | .content2 {
617 | display: block;
618 | margin-left: auto;
619 | margin-right: auto;
620 | width: 100%;
621 | }
622 | .block {
623 | padding: 0;
624 | overflow: hidden;
625 | }
626 | .app {
627 | width: 100%;
628 | margin: auto;
629 | padding: 14px;
630 | height: auto;
631 | overflow: hidden;
632 | }
633 | .iphone {
634 | -webkit-transition: all 0.2s ease-out;
635 | -moz-transition: all 0.2s ease-out;
636 | -ms-transition: all 0.2s ease-out;
637 | -o-transition: all 0.2s ease-out;
638 | width: 100%;
639 | max-width: 960px;
640 | height: auto;
641 | margin: 0 auto;
642 | display: block;
643 | margin-bottom: 28px;
644 | -webkit-background-size: cover;
645 | background-size: cover;
646 | }
647 | @media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min--moz-device-pixel-ratio: 1.5), only screen and (-o-min-device-pixel-ratio: 3/2), only screen and (min-device-pixel-ratio: 1.5) {
648 | background: url(../img/bgpic.jpg) no-repeat center;
649 | }
650 | .text_amount {
651 | display: block;
652 | margin: 56px auto;
653 | width: 300px;
654 | }
655 | .text_amount input[type="text"] {
656 | width: 100%;
657 | -webkit-transition: all 0.2s ease-out;
658 | -moz-transition: all 0.2s ease-out;
659 | -ms-transition: all 0.2s ease-out;
660 | -o-transition: all 0.2s ease-out;
661 | border-bottom: 1px solid #999999;
662 | }
663 | .text_amount input[type="text"]:focus {
664 | -webkit-transition: all 0.2s ease-out;
665 | -moz-transition: all 0.2s ease-out;
666 | -ms-transition: all 0.2s ease-out;
667 | -o-transition: all 0.2s ease-out;
668 | border-bottom: 1px solid #000000;
669 | }
670 | .ch {
671 | width: 50%;
672 | margin: auto;
673 | height: auto;
674 | overflow: hidden;
675 | font-size: 16px;
676 | }
677 | .ch .wx {
678 | width: 20%;
679 | min-width: 69px;
680 | padding: 14px;
681 | margin-right: 20%;
682 | cursor: pointer;
683 | display: block;
684 | float: left;
685 | text-align: center;
686 | font-size: 16px;
687 | display: none;
688 | -webkit-transition: all 0.2s ease-out;
689 | -moz-transition: all 0.2s ease-out;
690 | -ms-transition: all 0.2s ease-out;
691 | -o-transition: all 0.2s ease-out;
692 | }
693 | .ch .wx:hover {
694 | -webkit-transition: all 0.2s ease-out;
695 | -moz-transition: all 0.2s ease-out;
696 | -ms-transition: all 0.2s ease-out;
697 | -o-transition: all 0.2s ease-out;
698 | color: #000000;
699 | }
700 | .ch .wx:active {
701 | -webkit-transition: all 0.2s ease-out;
702 | -moz-transition: all 0.2s ease-out;
703 | -ms-transition: all 0.2s ease-out;
704 | -o-transition: all 0.2s ease-out;
705 | background-color: #f7f7f7;
706 | }
707 | @media (max-width: 960px) {
708 | .ch .wx {
709 | margin-right: 10%;
710 | }
711 | }
712 | .ch .up {
713 | width: 20%;
714 | min-width: 91px;
715 | padding: 14px;
716 | cursor: pointer;
717 | margin-right: 20%;
718 | display: block;
719 | float: left;
720 | text-align: center;
721 | font-size: 16px;
722 | -webkit-transition: all 0.2s ease-out;
723 | -moz-transition: all 0.2s ease-out;
724 | -ms-transition: all 0.2s ease-out;
725 | -o-transition: all 0.2s ease-out;
726 | }
727 | .ch .up:hover {
728 | -webkit-transition: all 0.2s ease-out;
729 | -moz-transition: all 0.2s ease-out;
730 | -ms-transition: all 0.2s ease-out;
731 | -o-transition: all 0.2s ease-out;
732 | color: #000000;
733 | }
734 | .ch .up:active {
735 | -webkit-transition: all 0.2s ease-out;
736 | -moz-transition: all 0.2s ease-out;
737 | -ms-transition: all 0.2s ease-out;
738 | -o-transition: all 0.2s ease-out;
739 | background-color: #f7f7f7;
740 | }
741 | @media (max-width: 960px) {
742 | .ch .up {
743 | margin-right: 10%;
744 | }
745 | }
746 | .ch .ap {
747 | width: 20%;
748 | min-width: 83px;
749 | padding: 14px;
750 | cursor: pointer;
751 | display: block;
752 | float: left;
753 | text-align: center;
754 | font-size: 16px;
755 | -webkit-transition: all 0.2s ease-out;
756 | -moz-transition: all 0.2s ease-out;
757 | -ms-transition: all 0.2s ease-out;
758 | -o-transition: all 0.2s ease-out;
759 | }
760 | .ch .ap:hover {
761 | -webkit-transition: all 0.2s ease-out;
762 | -moz-transition: all 0.2s ease-out;
763 | -ms-transition: all 0.2s ease-out;
764 | -o-transition: all 0.2s ease-out;
765 | color: #000000;
766 | }
767 | .ch .ap:active {
768 | -webkit-transition: all 0.2s ease-out;
769 | -moz-transition: all 0.2s ease-out;
770 | -ms-transition: all 0.2s ease-out;
771 | -o-transition: all 0.2s ease-out;
772 | background-color: #f7f7f7;
773 | }
774 | .tips {
775 | display: inline-block;
776 | width: 100%;
777 | padding: 14px;
778 | background: #4d4d4d;
779 | color: #fff;
780 | text-align: center;
781 | font-size: 16px;
782 | position: fixed;
783 | bottom: 0;
784 | z-index: 1000;
785 | }
786 | @media (max-width: 640px) {
787 | .iphone {
788 | -webkit-transition: all 0.2s ease-out;
789 | -moz-transition: all 0.2s ease-out;
790 | -ms-transition: all 0.2s ease-out;
791 | -o-transition: all 0.2s ease-out;
792 | margin: 0 auto;
793 | }
794 | .text_amount {
795 | display: block;
796 | margin: 28px auto;
797 | width: 100%;
798 | }
799 | .ch {
800 | width: 100%;
801 | }
802 | .ch .up,
803 | .ch .ap {
804 | -webkit-transition: all 0.2s ease-out;
805 | -moz-transition: all 0.2s ease-out;
806 | -ms-transition: all 0.2s ease-out;
807 | -o-transition: all 0.2s ease-out;
808 | float: none;
809 | display: inline-block;
810 | width: 100%;
811 | margin-bottom: 28px;
812 | border: 1px solid #f7f7f7;
813 | padding: 14px;
814 | }
815 | .ch .up:active,
816 | .ch .ap:active {
817 | -webkit-transition: all 0.2s ease-out;
818 | -moz-transition: all 0.2s ease-out;
819 | -ms-transition: all 0.2s ease-out;
820 | -o-transition: all 0.2s ease-out;
821 | border: 1px solid #999999;
822 | background-color: #f7f7f7;
823 | }
824 | }
825 |
--------------------------------------------------------------------------------
/demo/views/wap.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 | MiniCheckout
8 |
9 |
10 |
11 |
16 |
17 |
18 |
19 |

20 |
23 |
24 |
25 | 银联 WAP
26 | 支付宝 WAP
27 | 百度钱包 WAP
28 | 京东支付 WAP
29 | 易宝支付 WAP
30 | 微信浏览器内公众号支付 WAP
31 |
32 |
33 |
34 |
35 |
36 |
37 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/dist/pingpp.js:
--------------------------------------------------------------------------------
1 | !function(e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).pingpp=e()}(function(){return function r(t,l,i){function c(a,e){if(!l[a]){if(!t[a]){var n="function"==typeof require&&require;if(!e&&n)return n(a,!0);if(o)return o(a,!0);throw(e=new Error("Cannot find module '"+a+"'")).code="MODULE_NOT_FOUND",e}n=l[a]={exports:{}},t[a][0].call(n.exports,function(e){return c(t[a][1][e]||e)},n,n.exports,r,t,l,i)}return l[a].exports}for(var o="function"==typeof require&&require,e=0;e>16,n>>8&255,255&n));switch(a){case 1:n=r(e,i)<<18|r(e,i+1)<<12|r(e,i+2)<<6,l.push(String.fromCharCode(n>>16,n>>8&255));break;case 2:n=r(e,i)<<18|r(e,i+1)<<12,l.push(String.fromCharCode(n>>16))}return l.join('')},getbyte:function(e,a){e=e.charCodeAt(a);if(255>18)),i.push(t.charAt(n>>12&63)),i.push(t.charAt(n>>6&63)),i.push(t.charAt(63&n));switch(e.length-c){case 1:n=l(e,a)<<16,i.push(t.charAt(n>>18)+t.charAt(n>>12&63)+r+r);break;case 2:n=l(e,a)<<16|l(e,a+1)<<8,i.push(t.charAt(n>>18)+t.charAt(n>>12&63)+t.charAt(n>>6&63)+r)}return i.join('')}},r={url:'pay.htm',pay:function(e){e=encodeURIComponent(o.encode(e));l.call(t,'APURL')&&(r.url=t.APURL),location.href=r.url+'?goto='+e},decode:function(e){return o.decode(decodeURIComponent(e))}},a.exports=r},{"../../stash":54}],28:[function(e,a,n){e=e('./wx_lite');a.exports=e},{"./wx_lite":39}],29:[function(e,a,n){var r=e('./commons/redirect_base'),t=e('../callbacks'),l=e('../utils'),i={}.hasOwnProperty;a.exports={handleCharge:function(e){var a=e.extra;i.call(a,'pay_channel')?'wx'!==(a=a.pay_channel)||l.inWeixin()?'alipay'!==a||l.inAlipay()?r.handleCharge(e):t.innerCallback('fail',t.error('Not in the Alipay browser')):t.innerCallback('fail',t.error('Not in the WeChat browser')):t.innerCallback('fail',t.error('invalid_charge','charge 格式不正确'))}}},{"../callbacks":2,"../utils":58,"./commons/redirect_base":25}],30:[function(e,a,n){var r=e('../utils'),t={}.hasOwnProperty;a.exports={JDPAY_WAP_URL_OLD:'https://m.jdpay.com/wepay/web/pay',JDPAY_H5_URL:'https://h5pay.jd.com/jdpay/saveOrder',JDPAY_PC_URL:'https://wepay.jd.com/jdpay/saveOrder',handleCharge:function(e){var e=e.credential[e.channel],a=this.JDPAY_H5_URL;t.call(e,'channelUrl')?(a=e.channelUrl,delete e.channelUrl):t.call(e,'merchantRemark')&&(a=this.JDPAY_WAP_URL_OLD),r.formSubmit(a,'post',e)}}},{"../utils":58}],31:[function(e,a,n){var r=e('../utils'),t={}.hasOwnProperty;a.exports={handleCharge:function(e){e=e.credential[e.channel];t.call(e,'bankUrl')&&(request_url=e.bankUrl,delete e.bankUrl),r.formSubmit(request_url,'post',e)}}},{"../utils":58}],32:[function(e,a,n){arguments[4][31][0].apply(n,arguments)},{"../utils":58,dup:31}],33:[function(e,a,n){var r=e('../utils');a.exports={handleCharge:function(e){var e=e.credential[e.channel],a=e.channelUrl;delete e.channelUrl,r.formSubmit(a,'post',e)}}},{"../utils":58}],34:[function(e,a,n){var r=e('../utils');a.exports={handleCharge:function(e){var a=e.credential[e.channel];r.redirectTo(a,e.channel)}}},{"../utils":58}],35:[function(e,a,n){var r=e('../callbacks'),t=e('../utils'),l=e('../stash'),i={}.hasOwnProperty;a.exports={SRC_URL:'https://open.mobile.qq.com/sdk/qqapi.js?_bid=152',ID:'mqq_api',handleCharge:function(e){e=e.credential[e.channel];i.call(e,'token_id')?(l.tokenId=e.token_id,t.loadUrlJs(this.ID,this.SRC_URL,this.callpay)):r.innerCallback('fail',r.error('invalid_credential','missing_token_id'))},callpay:function(){if('undefined'!=typeof mqq){if(0==mqq.QQVersion)return r.innerCallback('fail',r.error('Not in the QQ client')),void delete l.tokenId;mqq.tenpay.pay({tokenId:l.tokenId},function(e){0==e.resultCode?r.innerCallback('success'):r.innerCallback('fail',r.error(e.retmsg))})}else r.innerCallback('fail',r.error('network_err'));delete l.tokenId}}},{"../callbacks":2,"../stash":54,"../utils":58}],36:[function(e,a,n){arguments[4][23][0].apply(n,arguments)},{"../utils":58,dup:23}],37:[function(e,a,n){var r=e('../utils');a.exports={UPACP_PC_URL:'https://gateway.95516.com/gateway/api/frontTransReq.do',handleCharge:function(e){e=e.credential[e.channel];r.formSubmit(this.UPACP_PC_URL,'post',e)}}},{"../utils":58}],38:[function(e,a,n){var r=e('../utils');a.exports={UPACP_WAP_URL:'https://gateway.95516.com/gateway/api/frontTransReq.do',handleCharge:function(e){e=e.credential[e.channel];r.formSubmit(this.UPACP_WAP_URL,'post',e)}}},{"../utils":58}],39:[function(e,a,n){var t=e('../stash'),l=e('../callbacks'),i={}.hasOwnProperty;a.exports={PINGPP_NOTIFY_URL_BASE:'https://notify.pingxx.com/notify',handleCharge:function(e){for(var a=e.credential[e.channel],n=['appId','timeStamp','nonceStr','package','signType','paySign'],r=0;r 0) {
39 | releaseObjectName = cmdOptions.name;
40 | }
41 |
42 | var b = browserify({
43 | entries: entries,
44 | standalone: releaseObjectName,
45 | debug: true
46 | });
47 |
48 | b.bundle()
49 | .pipe(source(destJsFile))
50 | .pipe(buffer())
51 | // .pipe(sourcemaps.init({
52 | // loadMaps: true
53 | // }))
54 | .pipe(uglify({
55 | mangle: {
56 | reserved: ['PingppSDK']
57 | },
58 | output: {
59 | quote_style: 3,
60 | max_line_len: 32000
61 | }
62 | }))
63 | .on('error', gutil.log)
64 | // .pipe(sourcemaps.write('./'))
65 | .pipe(dest(distDir));
66 |
67 | cb();
68 | }
69 |
70 | function modules(cb) {
71 | var channels = makeChannelModulesContent();
72 |
73 | var libs = makeLibModulesContent();
74 | var tmpl = fs.readFileSync(__dirname + '/mods.js.tmpl', 'utf8');
75 |
76 | var modsContents = _.replace(tmpl,
77 | replaceChannelsPattern,
78 | channels.replacement);
79 | modsContents = _.replace(modsContents,
80 | replaceLibsPattern,
81 | libs.replacement);
82 | fs.writeFileSync(modsJsFile, modsContents, 'utf8');
83 | console.log('Enabled channels: ' + channels.enabledChannels);
84 | cb();
85 | }
86 |
87 | function clean(cb) {
88 | var paths = del.sync(distFiles);
89 | console.log('Deleted files and folders:\n' + paths.join('\n'));
90 | cb();
91 | }
92 |
93 | var makeChannelModulesContent = function() {
94 | var channelPool = fs.readdirSync(channelsDirPath, 'utf8');
95 | var allChannels = _.map(channelPool, function(ch) {
96 | if (ch.substr(0, 1) == '.' || ch.substr(-3) != '.js') {
97 | return undefined;
98 | }
99 | return ch.substr(0, ch.length - 3);
100 | });
101 | allChannels = _.remove(allChannels, function(ch) {
102 | return typeof ch != 'undefined';
103 | });
104 | var enabledChannels;
105 | if (hasOwn.call(cmdOptions, 'channels') && cmdOptions.channels.length > 0) {
106 | enabledChannels = _.split(cmdOptions.channels, /[\s,]+/);
107 | _.forEach(enabledChannels, function(ch) {
108 | if (!_.includes(allChannels, ch)) {
109 | console.log('Channel ' + ch +
110 | ' is invalid. The channels you can use: ' + allChannels + '.');
111 | process.exit(0);
112 | }
113 | });
114 | } else {
115 | enabledChannels = _.remove(allChannels, function(ch) {
116 | return !_.includes(deprecatedChannels, ch);
117 | });
118 | }
119 |
120 | var channelsContents = [];
121 | for (var i = 0; i < enabledChannels.length; i++) {
122 | var line = enabledChannels[i] +
123 | ': require(\'' + channelsDir + enabledChannels[i] + '\')';
124 | channelsContents.push(line);
125 | }
126 |
127 | return {
128 | replacement: modnames2text(enabledChannels, channelsDir),
129 | enabledChannels: enabledChannels
130 | };
131 | };
132 |
133 | var makeLibModulesContent = function() {
134 | var extraBaseDir = './channels/extras/';
135 | var extranames = [];
136 | if (hasOwn.call(cmdOptions, 'alipay_in_weixin') &&
137 | cmdOptions.alipay_in_weixin) {
138 | extranames.push('ap');
139 | }
140 | if (hasOwn.call(cmdOptions, 'wx_jssdk') &&
141 | cmdOptions.wx_jssdk) {
142 | extranames.push('wx_jssdk');
143 | }
144 | if (hasOwn.call(cmdOptions, 'agreement')) {
145 | extranames.push(['agreement', './agreement']);
146 | }
147 |
148 | return {
149 | replacement: modnames2text(extranames, extraBaseDir)
150 | };
151 | };
152 |
153 | var modnames2text = function(modnames, baseDir) {
154 | if (modnames.length === 0) {
155 | return '';
156 | }
157 | if (baseDir === undefined || baseDir === null) {
158 | baseDir = '';
159 | }
160 | var modsContents = [];
161 | for (var i = 0; i < modnames.length; i++) {
162 | var modname;
163 | var path;
164 | if (typeof modnames[i] === 'string') {
165 | modname = modnames[i];
166 | path = baseDir + modname;
167 | } else if (Array.isArray(modnames[i])) {
168 | modname = modnames[i][0];
169 | path = modnames[i][1];
170 | }
171 | var line = modname +
172 | ': require(\'' + path + '\')';
173 | modsContents.push(line);
174 | }
175 |
176 | return ' ' + _.join(modsContents, ',\n ');
177 | };
178 |
179 | function watchFiles(cb) {
180 | var watcher = watch(scriptSrcFiles, series(build));
181 | watcher.on('change', function(path) {
182 | console.log('File \'' + path + '\' was changed, running tasks...');
183 | });
184 |
185 | cb();
186 | }
187 |
188 | exports.test = function(cb) {
189 | var test = require('./test/test.js');
190 | test.run();
191 | cb();
192 | };
193 |
194 | exports.build = series(clean, modules, build);
195 | exports.watch = series(clean, build, watchFiles);
196 | exports.default = series(build);
197 |
--------------------------------------------------------------------------------
/mods.js.tmpl:
--------------------------------------------------------------------------------
1 | var hasOwn = {}.hasOwnProperty;
2 | var mods = {};
3 | module.exports = mods;
4 |
5 | mods.channels = {
6 | <>
7 | };
8 |
9 | mods.extras = {
10 | <>
11 | };
12 |
13 | mods.transferChannels = {
14 | wx_pub: require('./transfer_channels/wx_pub'),
15 | }
16 |
17 | mods.getChannelModule = function(channel) {
18 | if (hasOwn.call(mods.channels, channel)) {
19 | return mods.channels[channel];
20 | }
21 | return undefined;
22 | };
23 |
24 | mods.getTransferChannelModule = function(channel) {
25 | if (hasOwn.call(mods.transferChannels, channel)) {
26 | return mods.transferChannels[channel];
27 | }
28 | return undefined;
29 | };
30 |
31 | mods.getExtraModule = function(name) {
32 | if (hasOwn.call(mods.extras, name)) {
33 | return mods.extras[name];
34 | }
35 | return undefined;
36 | };
37 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pingpp-js",
3 | "version": "2.4.0",
4 | "description": "Ping++ HTML5 SDK",
5 | "main": "src/main.js",
6 | "homepage": "https://www.pingxx.com",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/PingPlusPlus/pingpp-js.git"
10 | },
11 | "keywords": [
12 | "javascript",
13 | "payment",
14 | "library",
15 | "browser"
16 | ],
17 | "dependencies": {},
18 | "devDependencies": {
19 | "browserify": "^16.2.3",
20 | "del": "^3.0.0",
21 | "gulp": "^4.0.0",
22 | "gulp-sourcemaps": "^2.6.4",
23 | "gulp-uglify": "^3.0.1",
24 | "gulp-util": "^3.0.8",
25 | "lodash": "^4.17.11",
26 | "minimist": "1.2.6",
27 | "vinyl-buffer": "^1.0.1",
28 | "vinyl-source-stream": "^2.0.0"
29 | },
30 | "scripts": {
31 | "build": "npm install && gulp",
32 | "build:modules": "npm install && gulp build --alipay_in_weixin",
33 | "test": "gulp && gulp test"
34 | },
35 | "author": "Afon",
36 | "license": "MIT"
37 | }
38 |
--------------------------------------------------------------------------------
/src/agreement.js:
--------------------------------------------------------------------------------
1 | var hasOwn = {}.hasOwnProperty;
2 | var callbacks = require('./callbacks');
3 | var utils = require('./utils');
4 |
5 | module.exports = {
6 | signAgreement: function (agreement) {
7 | var agreementObj;
8 | if (typeof agreement === 'string') {
9 | try {
10 | agreementObj = JSON.parse(agreement);
11 | } catch (err) {
12 | callbacks.innerAgreementCallback('fail',
13 | callbacks.error('json_decode_fail', err));
14 | return false;
15 | }
16 | } else {
17 | agreementObj = agreement;
18 | }
19 |
20 | if (typeof agreementObj === 'undefined') {
21 | callbacks.innerAgreementCallback('fail',
22 | callbacks.error('json_decode_fail'));
23 | return false;
24 | }
25 |
26 | if (!hasOwn.call(agreementObj, 'object')
27 | || agreementObj.object !== 'agreement'
28 | || !hasOwn.call(agreementObj, 'channel')
29 | || !hasOwn.call(agreementObj, 'credential')
30 | || typeof agreementObj.credential !== 'object'
31 | ) {
32 | callbacks.innerAgreementCallback('fail',
33 | callbacks.error('invalid_object'));
34 | return false;
35 | }
36 |
37 | if (!hasOwn.call(agreementObj.credential, agreementObj.channel)) {
38 | callbacks.innerAgreementCallback('fail',
39 | callbacks.error('invalid_credential'));
40 | return false;
41 | }
42 |
43 | var credential = agreementObj.credential[agreementObj.channel];
44 | var urlToOpen;
45 | if (typeof credential === 'string') {
46 | urlToOpen = credential;
47 | } else if (hasOwn.call(credential, 'credential')
48 | && typeof credential.credential === 'string'
49 | ) {
50 | urlToOpen = credential.credential;
51 | }
52 |
53 | if (typeof urlToOpen === 'undefined') {
54 | callbacks.innerAgreementCallback('fail',
55 | callbacks.error('invalid_credential'));
56 | return false;
57 | }
58 |
59 | if (agreementObj.channel.substring(0, 6) === 'alipay' && utils.deviceDetectorMobile()) {
60 | var url = new URL(urlToOpen);
61 | urlToOpen = 'https://d.alipay.com/i/index.htm?iframeSrc='
62 | + encodeURIComponent('alipays://platformapi/startapp?appId=60000157'
63 | +'&appClearTop=false&startMultApp=YES&sign_params='
64 | + encodeURIComponent(url.search.substring(1))
65 | );
66 | }
67 |
68 | setTimeout(function() {
69 | utils.redirectTo(urlToOpen);
70 | }, 0);
71 |
72 | return true;
73 | }
74 | };
75 |
--------------------------------------------------------------------------------
/src/callbacks.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | userCallback: undefined,
3 |
4 | urlReturnCallback: undefined,
5 |
6 | urlReturnChannels: [
7 | 'alipay_pc_direct', // 默认只开启 alipay_pc_direct 使用 callback 返回 URL
8 | ],
9 |
10 | userAgreementCallback: undefined,
11 |
12 | userTransferCallback: undefined,
13 |
14 | innerCallback: function (result, err) {
15 | if (typeof this.userCallback === 'function') {
16 | if (typeof err === 'undefined') {
17 | err = this.error();
18 | }
19 | this.userCallback(result, err);
20 | this.userCallback = undefined;
21 | var payment_elements = require('./payment_elements');
22 | payment_elements.clear();
23 | }
24 | },
25 |
26 | error: function (msg, extra) {
27 | msg = typeof msg === 'undefined' ? '' : msg;
28 | extra = typeof extra === 'undefined' ? '' : extra;
29 | return {
30 | msg: msg,
31 | extra: extra,
32 | };
33 | },
34 |
35 | triggerUrlReturnCallback: function (err, url) {
36 | if (typeof this.urlReturnCallback === 'function') {
37 | this.urlReturnCallback(err, url);
38 | }
39 | },
40 |
41 | shouldReturnUrlByCallback: function (channel) {
42 | if (typeof this.urlReturnCallback !== 'function') {
43 | return false;
44 | }
45 | return this.urlReturnChannels.indexOf(channel) !== -1;
46 | },
47 |
48 | innerAgreementCallback: function (result, err) {
49 | if (typeof this.userAgreementCallback === 'function') {
50 | if (typeof err === 'undefined') {
51 | err = this.error();
52 | }
53 | this.userAgreementCallback(result, err);
54 | this.userAgreementCallback = undefined;
55 | }
56 | },
57 |
58 | innerTransferCallback: function (result, err) {
59 | if (typeof this.userTransferCallback === 'function') {
60 | if (typeof err === 'undefined') {
61 | err = this.error();
62 | }
63 | this.userTransferCallback(result, err);
64 | this.userTransferCallback = undefined;
65 | }
66 | },
67 | };
68 |
--------------------------------------------------------------------------------
/src/channels/abc_pay.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var callbacks = require('../callbacks');
3 | module.exports = {
4 | handleCharge: function (charge) {
5 | var credential = charge.credential[charge.channel];
6 | if (typeof credential === 'string') {
7 | utils.redirectTo(credential, charge.channel);
8 | } else {
9 | callbacks.innerCallback('fail',
10 | callbacks.error('invalid_credential', 'credential 格式不正确'));
11 | }
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/src/channels/abc_pub.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var callbacks = require('../callbacks');
3 | module.exports = {
4 | handleCharge: function (charge) {
5 | var credential = charge.credential[charge.channel];
6 | if (typeof credential === 'string') {
7 | utils.redirectTo(credential, charge.channel);
8 | } else {
9 | callbacks.innerCallback('fail',
10 | callbacks.error('invalid_credential', 'credential 格式不正确'));
11 | }
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/src/channels/alipay.js:
--------------------------------------------------------------------------------
1 | var callbacks = require('../callbacks');
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | /*global my,AlipayJSBridge*/
5 | module.exports = {
6 |
7 | PINGPP_NOTIFY_URL_BASE: 'https://notify.pingxx.com/notify',
8 |
9 | handleCharge: function (charge) {
10 | var credential = charge.credential[charge.channel];
11 | if (credential || hasOwn.call(credential, 'orderInfo')) {
12 | this.callpay(credential.orderInfo);
13 | } else {
14 | callbacks.innerCallback('fail',
15 | callbacks.error('invalid_credential', 'missing_alipay'));
16 | }
17 | },
18 |
19 | alipayLiteEnabled: function () {
20 | return typeof my !== 'undefined' && my.tradePay;
21 | },
22 |
23 | // 支付宝小程序支付
24 | callpay: function (orderStr) {
25 | var self = this;
26 | if (this.alipayLiteEnabled()) {
27 | return this.alipayLitePay(orderStr);
28 | }
29 |
30 | if (typeof navigator !== 'undefined'
31 | && /AlipayClient/.test(navigator.userAgent || navigator.swuserAgent)) {
32 | return this.waitAlipayJSBridgde(function () {
33 | self.alipayJsBridgePay(orderStr);
34 | });
35 | }
36 |
37 | var errmsg = '请在支付宝小程序或者支付宝应用内中打开';
38 | console.log(errmsg);
39 | callbacks.innerCallback('fail', callbacks.error(errmsg));
40 | return;
41 | },
42 |
43 | waitAlipayJSBridgde: function (callback) {
44 | if (window.AlipayJSBridge) {
45 | callback && callback();
46 | } else {
47 | document.addEventListener('AlipayJSBridgeReady', callback, false);
48 | }
49 | },
50 |
51 | alipayJsBridgePay: function (orderStr) {
52 | AlipayJSBridge.call('tradePay', {
53 | orderStr: orderStr
54 | }, this.alipayResultHandler);
55 | },
56 |
57 | alipayLitePay: function (orderStr) {
58 | var tradePayParams = {};
59 | tradePayParams.orderStr = orderStr;
60 | tradePayParams.complete = this.alipayResultHandler;
61 | my.tradePay(tradePayParams);
62 | },
63 |
64 | alipayResultHandler: function (res) {
65 | var extra = {
66 | resultCode: res.resultCode
67 | };
68 | if (hasOwn.call(res, 'memo')) {
69 | extra.memo = res.memo;
70 | }
71 | if (hasOwn.call(res, 'result')) {
72 | extra.result = res.result;
73 | }
74 | // 支付成功
75 | if (res.resultCode == '9000') {
76 | callbacks.innerCallback('success', callbacks.error('', extra));
77 | } else if (res.resultCode == '6001') { // 取消支付
78 | callbacks.innerCallback('cancel', callbacks.error('用户取消支付', extra));
79 | } else {
80 | callbacks.innerCallback('fail', callbacks.error('支付失败', extra));
81 | }
82 | },
83 |
84 | runTestMode: function (charge) {
85 | var path = '/charges/' + charge.id;
86 | my.httpRequest({
87 | url: this.PINGPP_NOTIFY_URL_BASE + path + '?livemode=false',
88 | success: function(res) {
89 | if (res.data == 'success') {
90 | callbacks.innerCallback('success');
91 | } else {
92 | callbacks.innerCallback('fail',
93 | callbacks.error('testmode_notify_fail'));
94 | }
95 | },
96 | fail:function() {
97 | callbacks.innerCallback('fail', callbacks.error('network_err'));
98 | }
99 | });
100 | }
101 | };
102 |
--------------------------------------------------------------------------------
/src/channels/alipay_lite.js:
--------------------------------------------------------------------------------
1 | var callbacks = require('../callbacks');
2 |
3 | /*global my*/
4 | module.exports = {
5 |
6 | PINGPP_NOTIFY_URL_BASE: 'https://notify.pingxx.com/notify',
7 |
8 | handleCharge: function (charge) {
9 | var trade_no = charge.credential[charge.channel];
10 | if (trade_no) {
11 | this.callpay(trade_no);
12 | } else {
13 | callbacks.innerCallback('fail',
14 | callbacks.error('invalid_credential', 'missing_alipay_lite'));
15 | }
16 | },
17 |
18 | alipayLiteEnabled: function () {
19 | return typeof my !== 'undefined' && my.tradePay;
20 | },
21 |
22 | //支付宝小程序支付
23 | callpay: function (tradeNO) {
24 | if (!this.alipayLiteEnabled()) {
25 | console.log('请在支付宝小程序中打开');
26 | return;
27 | }
28 | var alipay_lite = {};
29 | alipay_lite.tradeNO = tradeNO;
30 | alipay_lite.complete = function (res) {
31 | //支付成功
32 | if (res.resultCode == 9000) {
33 | callbacks.innerCallback('success');
34 | } else if (res.resultCode == 6001) { //取消支付
35 | callbacks.innerCallback('cancel', callbacks.error('用户取消支付'));
36 | } else {
37 | callbacks.innerCallback('fail', callbacks.error('支付失败'));
38 | }
39 | };
40 | my.tradePay(alipay_lite);
41 | },
42 |
43 | runTestMode: function (charge) {
44 | var path = '/charges/' + charge.id;
45 | my.httpRequest({
46 | url: this.PINGPP_NOTIFY_URL_BASE + path + '?livemode=false',
47 | success: function(res) {
48 | if (res.data == 'success') {
49 | callbacks.innerCallback('success');
50 | } else {
51 | callbacks.innerCallback('fail',
52 | callbacks.error('testmode_notify_fail'));
53 | }
54 | },
55 | fail:function() {
56 | callbacks.innerCallback('fail', callbacks.error('network_err'));
57 | }
58 | });
59 | }
60 | };
61 |
--------------------------------------------------------------------------------
/src/channels/alipay_pc_direct.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | module.exports = {
5 |
6 | ALIPAY_PC_DIRECT_URL: 'https://mapi.alipay.com/gateway.do',
7 |
8 | handleCharge: function(charge) {
9 | var channel = charge.channel;
10 | var credential = charge.credential[channel];
11 | var baseURL = this.ALIPAY_PC_DIRECT_URL;
12 | if (hasOwn.call(credential, 'channel_url')) {
13 | baseURL = credential.channel_url;
14 | }
15 | if (!hasOwn.call(credential, '_input_charset')) {
16 | if(hasOwn.call(credential, 'service')
17 | && credential.service === 'create_direct_pay_by_user') {
18 | credential._input_charset = 'utf-8';
19 | }
20 | }
21 | var query = utils.stringifyData(credential, channel, true);
22 | utils.redirectTo(baseURL + '?' + query, channel);
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/src/channels/alipay_qr.js:
--------------------------------------------------------------------------------
1 | var hasOwn = {}.hasOwnProperty;
2 | var callbacks = require('../callbacks');
3 |
4 | /*global AlipayJSBridge*/
5 | module.exports = {
6 |
7 | handleCharge: function (charge) {
8 | var credential = charge.credential[charge.channel];
9 | if (hasOwn.call(credential, 'transaction_no')) {
10 | this.tradePay(credential.transaction_no);
11 | } else {
12 | callbacks.innerCallback('fail',
13 | callbacks.error('invalid_credential', 'missing_field_transaction_no'));
14 | }
15 | },
16 |
17 | ready: function (callback) {
18 | if (window.AlipayJSBridge) {
19 | callback && callback();
20 | } else {
21 | document.addEventListener('AlipayJSBridgeReady', callback, false);
22 | }
23 | },
24 |
25 | tradePay: function (tradeNO) {
26 | this.ready(function () {
27 | // 通过传入交易号唤起快捷调用方式(注意tradeNO大小写严格)
28 | AlipayJSBridge.call('tradePay', {
29 | tradeNO: tradeNO
30 | }, function (data) {
31 | if ('9000' == data.resultCode) {
32 | callbacks.innerCallback('success');
33 | } else if('6001' == data.resultCode) {
34 | callbacks.innerCallback('cancel', callbacks.error(data.result));
35 | } else {
36 | callbacks.innerCallback('fail',
37 | callbacks.error(data.result));
38 | }
39 | });
40 | });
41 | }
42 | };
43 |
--------------------------------------------------------------------------------
/src/channels/alipay_qr_lakala.js:
--------------------------------------------------------------------------------
1 | var redirectBase = require('./commons/redirect_base');
2 |
3 | module.exports = {
4 |
5 | handleCharge: function(charge) {
6 | redirectBase.handleCharge(charge);
7 | }
8 | };
9 |
--------------------------------------------------------------------------------
/src/channels/alipay_wap.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var mods = require('../mods');
3 | var hasOwn = {}.hasOwnProperty;
4 |
5 | module.exports = {
6 |
7 | ALIPAY_WAP_URL_OLD: 'https://wappaygw.alipay.com/service/rest.htm',
8 | ALIPAY_WAP_URL: 'https://mapi.alipay.com/gateway.do',
9 |
10 | handleCharge: function(charge) {
11 | var channel = charge.channel;
12 | var credential = charge.credential[channel];
13 | var baseURL = this.ALIPAY_WAP_URL;
14 | if (hasOwn.call(credential, 'req_data')) {
15 | baseURL = this.ALIPAY_WAP_URL_OLD;
16 | } else if (hasOwn.call(credential, 'channel_url')) {
17 | baseURL = credential.channel_url;
18 | }
19 | if (!hasOwn.call(credential, '_input_charset')) {
20 | if ((hasOwn.call(credential, 'service')
21 | && credential.service === 'alipay.wap.create.direct.pay.by.user')
22 | || hasOwn.call(credential, 'req_data')
23 | ) {
24 | credential._input_charset = 'utf-8';
25 | }
26 | }
27 | var query = utils.stringifyData(credential, channel, true);
28 | var targetURL = baseURL + '?' + query;
29 | var ap = mods.getExtraModule('ap');
30 | if (utils.inWeixin() && typeof ap !== 'undefined') {
31 | ap.pay(targetURL);
32 | } else {
33 | utils.redirectTo(targetURL, channel);
34 | }
35 | }
36 | };
--------------------------------------------------------------------------------
/src/channels/alipay_wap_lakala.js:
--------------------------------------------------------------------------------
1 | var redirectBase = require('./commons/redirect_base');
2 |
3 | module.exports = {
4 |
5 | handleCharge: function(charge) {
6 | redirectBase.handleCharge(charge);
7 | }
8 | };
9 |
--------------------------------------------------------------------------------
/src/channels/bfb_wap.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var callbacks = require('../callbacks');
3 | var hasOwn = {}.hasOwnProperty;
4 |
5 | module.exports = {
6 |
7 | handleCharge: function(charge) {
8 | var channel = charge.channel;
9 | var credential = charge.credential[channel];
10 |
11 | if (!hasOwn.call(credential, 'url')) {
12 | callbacks.innerCallback('fail',
13 | callbacks.error('invalid_credential', 'missing_field:url'));
14 | return;
15 | }
16 | utils.redirectTo(credential.url + '?' +
17 | utils.stringifyData(credential, channel), channel);
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/src/channels/cb_alipay_pc_direct.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | module.exports = {
5 |
6 | ALIPAY_PC_DIRECT_URL: 'https://intlmapi.alipay.com/gateway.do',
7 |
8 | handleCharge: function(charge) {
9 | var channel = charge.channel;
10 | var credential = charge.credential[channel];
11 | var baseURL = this.ALIPAY_PC_DIRECT_URL;
12 | if (hasOwn.call(credential, 'channel_url')) {
13 | baseURL = credential.channel_url;
14 | }
15 |
16 | if (!hasOwn.call(credential, '_input_charset')) {
17 | if(hasOwn.call(credential, 'service')
18 | && credential.service === 'create_forex_trade') {
19 | credential._input_charset = 'utf-8';
20 | }
21 | }
22 | var query = utils.stringifyData(credential, channel, true);
23 |
24 | utils.redirectTo(baseURL + '?' + query, channel);
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/src/channels/cb_alipay_wap.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var mods = require('../mods');
3 | var hasOwn = {}.hasOwnProperty;
4 |
5 | module.exports = {
6 |
7 | ALIPAY_WAP_URL: 'https://intlmapi.alipay.com/gateway.do',
8 |
9 | handleCharge: function(charge) {
10 | var channel = charge.channel;
11 | var credential = charge.credential[channel];
12 | var baseURL = this.ALIPAY_WAP_URL;
13 | if (hasOwn.call(credential, 'channel_url')) {
14 | baseURL = credential.channel_url;
15 | }
16 | if (!hasOwn.call(credential, '_input_charset')) {
17 | if ((hasOwn.call(credential, 'service')
18 | && credential.service === 'create_forex_trade_wap')
19 | ) {
20 | credential._input_charset = 'utf-8';
21 | }
22 | }
23 |
24 | var query = utils.stringifyData(credential, channel, true);
25 | var targetURL = baseURL + '?' + query;
26 | var ap = mods.getExtraModule('ap');
27 | if (utils.inWeixin() && typeof ap !== 'undefined') {
28 | ap.pay(targetURL);
29 | } else {
30 | utils.redirectTo(targetURL, channel);
31 | }
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/src/channels/cb_wx_pub.js:
--------------------------------------------------------------------------------
1 | var callbacks = require('../callbacks');
2 | var utils = require('../utils');
3 | var stash = require('../stash');
4 | var mods = require('../mods');
5 | var hasOwn = {}.hasOwnProperty;
6 |
7 | /*global WeixinJSBridge*/
8 | module.exports = {
9 |
10 | PINGPP_NOTIFY_URL_BASE: 'https://notify.pingxx.com/notify',
11 |
12 | handleCharge: function(charge) {
13 | var credential = charge.credential[charge.channel];
14 | var fields = [
15 | 'appId', 'timeStamp', 'nonceStr', 'package', 'signType', 'paySign'
16 | ];
17 | for (var k = 0; k < fields.length; k++) {
18 | if (!hasOwn.call(credential, fields[k])) {
19 | callbacks.innerCallback('fail',
20 | callbacks.error('invalid_credential', 'missing_field_' + fields[k]));
21 | return;
22 | }
23 | }
24 | stash.jsApiParameters = credential;
25 | this.callpay();
26 | },
27 |
28 | callpay: function() {
29 | var self = this;
30 | var wx_jssdk = mods.getExtraModule('wx_jssdk');
31 | if (typeof wx_jssdk !== 'undefined' && wx_jssdk.jssdkEnabled()) {
32 | wx_jssdk.callpay();
33 | } else if (typeof WeixinJSBridge == 'undefined') {
34 | var eventCallback = function() {
35 | self.jsApiCall();
36 | };
37 | if (document.addEventListener) {
38 | document.addEventListener('WeixinJSBridgeReady',
39 | eventCallback, false);
40 | } else if (document.attachEvent) {
41 | document.attachEvent('WeixinJSBridgeReady', eventCallback);
42 | document.attachEvent('onWeixinJSBridgeReady', eventCallback);
43 | }
44 | } else {
45 | this.jsApiCall();
46 | }
47 | },
48 |
49 | jsApiCall: function() {
50 | if (hasOwn.call(stash, 'jsApiParameters')) {
51 | WeixinJSBridge.invoke(
52 | 'getBrandWCPayRequest',
53 | stash.jsApiParameters,
54 | function(res) {
55 | delete stash.jsApiParameters;
56 | if (res.err_msg == 'get_brand_wcpay_request:ok') {
57 | callbacks.innerCallback('success');
58 | } else if (res.err_msg == 'get_brand_wcpay_request:cancel') {
59 | callbacks.innerCallback('cancel');
60 | } else {
61 | callbacks.innerCallback('fail',
62 | callbacks.error('wx_result_fail', res.err_msg));
63 | }
64 | }
65 | );
66 | }
67 | },
68 |
69 | runTestMode: function(charge) {
70 | var dopay = confirm('模拟付款?');
71 | if (dopay) {
72 | var path = '/charges/' + charge.id;
73 | utils.request(this.PINGPP_NOTIFY_URL_BASE + path + '?livemode=false',
74 | 'GET', null,
75 | function(data, status) {
76 | if (status >= 200 && status < 400 && data == 'success') {
77 | callbacks.innerCallback('success');
78 | } else {
79 | var extra = 'http_code:' + status + ';response:' + data;
80 | callbacks.innerCallback('fail',
81 | callbacks.error('testmode_notify_fail', extra));
82 | }
83 | },
84 | function() {
85 | callbacks.innerCallback('fail', callbacks.error('network_err'));
86 | });
87 | }
88 | }
89 | };
90 |
--------------------------------------------------------------------------------
/src/channels/ccb_qr.js:
--------------------------------------------------------------------------------
1 | var redirectBase = require('./commons/redirect_base');
2 |
3 | module.exports = {
4 |
5 | handleCharge: function(charge) {
6 | redirectBase.handleCharge(charge);
7 | }
8 | };
9 |
--------------------------------------------------------------------------------
/src/channels/ccb_wap.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var hasOwn = {}.hasOwnProperty;
3 | var callbacks = require('../callbacks');
4 |
5 | module.exports = {
6 |
7 | CCB_WAP_URL_BASE: 'https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?',
8 |
9 | handleCharge: function(charge) {
10 | var channel = charge.channel;
11 | var credential = charge.credential[channel];
12 | if (!hasOwn.call(credential, 'orderinfo')) {
13 | callbacks.innerCallback('fail',
14 | callbacks.error('invalid_credential', 'missing_field:orderinfo'));
15 | return;
16 | }
17 |
18 | var targetURL = this.CCB_WAP_URL_BASE + credential['orderinfo'];
19 | utils.redirectTo(targetURL, channel);
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/src/channels/chinaums_alipay_pub.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var callbacks = require('../callbacks');
3 | var hasOwn = {}.hasOwnProperty;
4 |
5 | module.exports = {
6 | handleCharge: function (charge) {
7 | var credential = charge.credential[charge.channel];
8 | if (typeof credential === 'string') {
9 | utils.redirectTo(credential, charge.channel);
10 | } else {
11 | callbacks.innerCallback('fail',
12 | callbacks.error('invalid_credential', 'credential 格式不正确'));
13 | }
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/src/channels/chinaums_alipay_wap.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var callbacks = require('../callbacks');
3 | var hasOwn = {}.hasOwnProperty;
4 |
5 | module.exports = {
6 | handleCharge: function (charge) {
7 | var credential = charge.credential[charge.channel];
8 | if (typeof credential === 'string') {
9 | utils.redirectTo(credential, charge.channel);
10 | } else {
11 | callbacks.innerCallback('fail',
12 | callbacks.error('invalid_credential', 'credential 格式不正确'));
13 | }
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/src/channels/chinaums_upacp_wap.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var callbacks = require('../callbacks');
3 | var hasOwn = {}.hasOwnProperty;
4 |
5 | module.exports = {
6 | handleCharge: function (charge) {
7 | var credential = charge.credential[charge.channel];
8 | if (typeof credential === 'string') {
9 | utils.redirectTo(credential, charge.channel);
10 | } else {
11 | callbacks.innerCallback('fail',
12 | callbacks.error('invalid_credential', 'credential 格式不正确'));
13 | }
14 | }
15 | };
--------------------------------------------------------------------------------
/src/channels/chinaums_wx_pub.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var callbacks = require('../callbacks');
3 | var hasOwn = {}.hasOwnProperty;
4 |
5 | module.exports = {
6 | handleCharge: function (charge) {
7 | var credential = charge.credential[charge.channel];
8 | if (typeof credential === 'string') {
9 | utils.redirectTo(credential, charge.channel);
10 | } else {
11 | callbacks.innerCallback('fail',
12 | callbacks.error('invalid_credential', 'credential 格式不正确'));
13 | }
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/src/channels/chinaums_wx_wap.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var callbacks = require('../callbacks');
3 | var hasOwn = {}.hasOwnProperty;
4 |
5 | module.exports = {
6 | handleCharge: function (charge) {
7 | var credential = charge.credential[charge.channel];
8 | if (typeof credential === 'string') {
9 | utils.redirectTo(credential, charge.channel);
10 | } else {
11 | callbacks.innerCallback('fail',
12 | callbacks.error('invalid_credential', 'credential 格式不正确'));
13 | }
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/src/channels/cmb_pc_qr.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | module.exports = {
5 |
6 | handleCharge: function(charge) {
7 | var channel = charge.channel;
8 | var credential = charge.credential[channel];
9 | var baseURL;
10 | if (hasOwn.call(credential, 'channel_url')) {
11 | baseURL = credential.channel_url;
12 | delete credential.channel_url;
13 | }
14 |
15 | utils.formSubmit(baseURL, 'post', credential);
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/src/channels/cmb_wallet.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | module.exports = {
5 |
6 | CMB_WALLET_URL:
7 | 'https://netpay.cmbchina.com/netpayment/BaseHttp.dll?MB_EUserPay',
8 |
9 | handleCharge: function(charge) {
10 | var credential = charge.credential[charge.channel];
11 | var request_url = this.CMB_WALLET_URL;
12 | if (hasOwn.call(credential, 'ChannelUrl')) {
13 | request_url = credential.ChannelUrl;
14 | delete credential.ChannelUrl;
15 | }
16 |
17 | if (hasOwn.call(credential, 'channelVersion')) {
18 | delete credential.channelVersion;
19 | }
20 |
21 | utils.formSubmit(request_url, 'post', credential);
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/src/channels/commons/redirect_base.js:
--------------------------------------------------------------------------------
1 | var utils = require('../../utils');
2 | var callbacks = require('../../callbacks');
3 | var hasOwn = {}.hasOwnProperty;
4 |
5 | module.exports = {
6 |
7 | handleCharge: function(charge) {
8 | var credential = charge.credential[charge.channel];
9 | var targetURL;
10 | if (typeof credential === 'string') {
11 | targetURL = credential;
12 | } else if (hasOwn.call(credential, 'url')) {
13 | targetURL = credential.url;
14 | } else {
15 | callbacks.innerCallback('fail', callbacks.error('invalid_credential',
16 | 'credential format is incorrect'));
17 | return;
18 | }
19 | utils.redirectTo(targetURL, charge.channel);
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/src/channels/cp_b2b.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 |
3 | module.exports = {
4 |
5 | CP_B2B_URL: 'https://payment.chinapay.com/CTITS/service/rest/page/nref/000000000017/0/0/0/0/0',
6 |
7 | handleCharge: function(charge) {
8 | var credential = charge.credential[charge.channel];
9 | utils.formSubmit(this.CP_B2B_URL, 'post', credential);
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/src/channels/extras/ap.js:
--------------------------------------------------------------------------------
1 | var stash = require('../../stash');
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | (function() {
5 | var b = {};
6 | var a = {};
7 | a.PADCHAR = '=';
8 | a.ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
9 | a.makeDOMException = function() {
10 | try {
11 | return new DOMException(DOMException.INVALID_CHARACTER_ERR);
12 | } catch (d) {
13 | var c = new Error('DOM Exception 5');
14 | c.code = c.number = 5;
15 | c.name = c.description = 'INVALID_CHARACTER_ERR';
16 | c.toString = function() {
17 | return 'Error: ' + c.name + ': ' + c.message;
18 | };
19 | return c;
20 | }
21 | };
22 | a.getbyte64 = function(e, d) {
23 | var c = a.ALPHA.indexOf(e.charAt(d));
24 | if (c === -1) {
25 | throw a.makeDOMException();
26 | }
27 | return c;
28 | };
29 | a.decode = function(f) {
30 | f = '' + f;
31 | var j = a.getbyte64;
32 | var h, e, g;
33 | var d = f.length;
34 | if (d === 0) {
35 | return f;
36 | }
37 | if (d % 4 !== 0) {
38 | throw a.makeDOMException();
39 | }
40 | h = 0;
41 | if (f.charAt(d - 1) === a.PADCHAR) {
42 | h = 1;
43 | if (f.charAt(d - 2) === a.PADCHAR) {
44 | h = 2;
45 | }
46 | d -= 4;
47 | }
48 | var c = [];
49 | for (e = 0; e < d; e += 4) {
50 | g = (j(f, e) << 18) |
51 | (j(f, e + 1) << 12) |
52 | (j(f, e + 2) << 6) |
53 | j(f, e + 3);
54 | c.push(String.fromCharCode(g >> 16, (g >> 8) & 255, g & 255));
55 | }
56 | switch (h) {
57 | case 1:
58 | g = (j(f, e) << 18) | (j(f, e + 1) << 12) | (j(f, e + 2) << 6);
59 | c.push(String.fromCharCode(g >> 16, (g >> 8) & 255));
60 | break;
61 | case 2:
62 | g = (j(f, e) << 18) | (j(f, e + 1) << 12);
63 | c.push(String.fromCharCode(g >> 16));
64 | break;
65 | }
66 | return c.join('');
67 | };
68 | a.getbyte = function(e, d) {
69 | var c = e.charCodeAt(d);
70 | if (c > 255) {
71 | throw a.makeDOMException();
72 | }
73 | return c;
74 | };
75 | a.encode = function(f) {
76 | if (arguments.length !== 1) {
77 | throw new SyntaxError('Not enough arguments');
78 | }
79 | var g = a.PADCHAR;
80 | var h = a.ALPHA;
81 | var k = a.getbyte;
82 | var e, j;
83 | var c = [];
84 | f = '' + f;
85 | var d = f.length - f.length % 3;
86 | if (f.length === 0) {
87 | return f;
88 | }
89 | for (e = 0; e < d; e += 3) {
90 | j = (k(f, e) << 16) | (k(f, e + 1) << 8) | k(f, e + 2);
91 | c.push(h.charAt(j >> 18));
92 | c.push(h.charAt((j >> 12) & 63));
93 | c.push(h.charAt((j >> 6) & 63));
94 | c.push(h.charAt(j & 63));
95 | }
96 | switch (f.length - d) {
97 | case 1:
98 | j = k(f, e) << 16;
99 | c.push(h.charAt(j >> 18) + h.charAt((j >> 12) & 63) + g + g);
100 | break;
101 | case 2:
102 | j = (k(f, e) << 16) | (k(f, e + 1) << 8);
103 | c.push(h.charAt(j >> 18) +
104 | h.charAt((j >> 12) & 63) +
105 | h.charAt((j >> 6) & 63) + g);
106 | break;
107 | }
108 | return c.join('');
109 | };
110 | b.url = 'pay.htm';
111 | b.pay = function(d) {
112 | var c = encodeURIComponent(a.encode(d));
113 | if (hasOwn.call(stash, 'APURL')) {
114 | b.url = stash.APURL;
115 | }
116 | location.href = b.url + '?goto=' + c;
117 | };
118 | b.decode = function(c) {
119 | return a.decode(decodeURIComponent(c));
120 | };
121 |
122 | module.exports = b;
123 | })();
124 |
--------------------------------------------------------------------------------
/src/channels/extras/wx_jssdk.js:
--------------------------------------------------------------------------------
1 | var stash = require('../../stash');
2 | var callbacks = require('../../callbacks');
3 |
4 | /*global wx*/
5 | module.exports = {
6 |
7 | jssdkEnabled: function() {
8 | return typeof wx !== 'undefined' && typeof stash.signature !== 'undefined';
9 | },
10 |
11 | callpay: function() {
12 | var wxConfigFailed = false;
13 | wx.config({
14 | debug: typeof stash.debug == 'boolean' ? stash.debug : false,
15 | appId: stash.jsApiParameters.appId,
16 | timestamp: stash.jsApiParameters.timeStamp,
17 | nonceStr: stash.jsApiParameters.nonceStr,
18 | signature: stash.signature,
19 | jsApiList: ['chooseWXPay']
20 | });
21 | delete stash.signature;
22 | delete stash.debug;
23 | wx.ready(function() {
24 | if (wxConfigFailed) {
25 | return;
26 | }
27 | wx.chooseWXPay({
28 | timestamp: stash.jsApiParameters.timeStamp,
29 | nonceStr: stash.jsApiParameters.nonceStr,
30 | 'package': stash.jsApiParameters.package,
31 | signType: stash.jsApiParameters.signType,
32 | paySign: stash.jsApiParameters.paySign,
33 | success: function(res) {
34 | delete stash.jsApiParameters;
35 | if (res.errMsg == 'chooseWXPay:ok') {
36 | callbacks.innerCallback('success');
37 | } else {
38 | callbacks.innerCallback('fail',
39 | callbacks.error('wx_result_fail', res.errMsg));
40 | }
41 | },
42 | /* eslint-disable no-unused-vars */
43 | cancel: function(res) {
44 | delete stash.jsApiParameters;
45 | callbacks.innerCallback('cancel');
46 | },
47 | /* eslint-enable no-unused-vars */
48 | fail: function(res) {
49 | delete stash.jsApiParameters;
50 | callbacks.innerCallback('fail',
51 | callbacks.error('wx_result_fail', res.errMsg));
52 | }
53 | });
54 | });
55 | wx.error(function(res) {
56 | wxConfigFailed = true;
57 | delete stash.jsApiParameters;
58 | callbacks.innerCallback('fail',
59 | callbacks.error('wx_config_error', res.errMsg));
60 | });
61 | }
62 | };
63 |
--------------------------------------------------------------------------------
/src/channels/isv_lite.js:
--------------------------------------------------------------------------------
1 | var wxLite = require('./wx_lite');
2 |
3 | module.exports = wxLite;
4 |
--------------------------------------------------------------------------------
/src/channels/isv_wap.js:
--------------------------------------------------------------------------------
1 | var redirectBase = require('./commons/redirect_base');
2 | var callbacks = require('../callbacks');
3 | var utils = require('../utils');
4 | var hasOwn = {}.hasOwnProperty;
5 |
6 | module.exports = {
7 | handleCharge: function (charge) {
8 | var extra = charge.extra;
9 | if (hasOwn.call(extra, 'pay_channel')) {
10 | var pay_channel = extra.pay_channel;
11 | if (pay_channel === 'wx' && !utils.inWeixin()) {
12 | callbacks.innerCallback('fail',
13 | callbacks.error('Not in the WeChat browser'));
14 | return;
15 | } else if (pay_channel === 'alipay' && !utils.inAlipay()) {
16 | callbacks.innerCallback('fail',
17 | callbacks.error('Not in the Alipay browser'));
18 | return;
19 | }
20 | } else {
21 | callbacks.innerCallback('fail',
22 | callbacks.error('invalid_charge', 'charge 格式不正确'));
23 | return;
24 | }
25 | redirectBase.handleCharge(charge);
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/src/channels/jdpay_wap.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | module.exports = {
5 |
6 | JDPAY_WAP_URL_OLD: 'https://m.jdpay.com/wepay/web/pay',
7 | JDPAY_H5_URL: 'https://h5pay.jd.com/jdpay/saveOrder',
8 | JDPAY_PC_URL: 'https://wepay.jd.com/jdpay/saveOrder',
9 |
10 | handleCharge: function(charge) {
11 | var credential = charge.credential[charge.channel];
12 | var request_url = this.JDPAY_H5_URL;
13 | if (hasOwn.call(credential, 'channelUrl')) {
14 | request_url = credential.channelUrl;
15 | delete credential.channelUrl;
16 | } else if (hasOwn.call(credential, 'merchantRemark')) {
17 | request_url = this.JDPAY_WAP_URL_OLD;
18 | }
19 | utils.formSubmit(request_url, 'post', credential);
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/src/channels/nucc_b2b_lakala.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | module.exports = {
5 | handleCharge: function (charge) {
6 | var credential = charge.credential[charge.channel];
7 | if (hasOwn.call(credential, 'bankUrl')) {
8 | request_url = credential.bankUrl;
9 | delete credential.bankUrl;
10 | }
11 |
12 | utils.formSubmit(request_url, 'post', credential);
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/src/channels/nucc_b2c_lakala.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | module.exports = {
5 | handleCharge: function (charge) {
6 | var credential = charge.credential[charge.channel];
7 | if (hasOwn.call(credential, 'bankUrl')) {
8 | request_url = credential.bankUrl;
9 | delete credential.bankUrl;
10 | }
11 |
12 | utils.formSubmit(request_url, 'post', credential);
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/src/channels/pab_pc.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 |
3 | module.exports = {
4 |
5 | handleCharge: function(charge) {
6 | var credential = charge.credential[charge.channel];
7 | var request_url = credential.channelUrl;
8 | delete credential.channelUrl;
9 |
10 | utils.formSubmit(request_url, 'post', credential);
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/src/channels/paypal.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 |
3 | module.exports = {
4 | handleCharge: function(charge) {
5 | var credential = charge.credential[charge.channel];
6 | utils.redirectTo(credential, charge.channel);
7 | }
8 | };
9 |
--------------------------------------------------------------------------------
/src/channels/qpay_pub.js:
--------------------------------------------------------------------------------
1 | var callbacks = require('../callbacks');
2 | var utils = require('../utils');
3 | var stash = require('../stash');
4 | var hasOwn = {}.hasOwnProperty;
5 |
6 | /*global mqq*/
7 | module.exports = {
8 | SRC_URL: 'https://open.mobile.qq.com/sdk/qqapi.js?_bid=152',
9 | ID: 'mqq_api',
10 |
11 | handleCharge: function (charge) {
12 | var credential = charge.credential[charge.channel];
13 |
14 | if (!hasOwn.call(credential, 'token_id')) {
15 | callbacks.innerCallback('fail',
16 | callbacks.error('invalid_credential', 'missing_token_id'));
17 | return;
18 | }
19 | stash.tokenId = credential.token_id;
20 | utils.loadUrlJs(this.ID, this.SRC_URL, this.callpay);
21 | },
22 |
23 | callpay: function () {
24 | if (typeof mqq != 'undefined') {
25 | if (mqq.QQVersion == 0) {
26 | callbacks.innerCallback('fail',
27 | callbacks.error('Not in the QQ client'));
28 | delete stash.tokenId;
29 | return;
30 | }
31 | mqq.tenpay.pay({
32 | tokenId: stash.tokenId
33 | }, function (result) {
34 | if (result.resultCode == 0) {
35 | callbacks.innerCallback('success');
36 | } else {
37 | callbacks.innerCallback('fail',
38 | callbacks.error(result.retmsg));
39 | }
40 | });
41 | } else {
42 | callbacks.innerCallback('fail',
43 | callbacks.error('network_err'));
44 | }
45 | delete stash.tokenId;
46 | }
47 | };
--------------------------------------------------------------------------------
/src/channels/upacp_b2b.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | module.exports = {
5 |
6 | handleCharge: function(charge) {
7 | var channel = charge.channel;
8 | var credential = charge.credential[channel];
9 | var baseURL;
10 | if (hasOwn.call(credential, 'channel_url')) {
11 | baseURL = credential.channel_url;
12 | delete credential.channel_url;
13 | }
14 |
15 | utils.formSubmit(baseURL, 'post', credential);
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/src/channels/upacp_pc.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 |
3 | module.exports = {
4 |
5 | UPACP_PC_URL: 'https://gateway.95516.com/gateway/api/frontTransReq.do',
6 |
7 | handleCharge: function(charge) {
8 | var credential = charge.credential[charge.channel];
9 | utils.formSubmit(this.UPACP_PC_URL, 'post', credential);
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/src/channels/upacp_wap.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 |
3 | module.exports = {
4 |
5 | UPACP_WAP_URL: 'https://gateway.95516.com/gateway/api/frontTransReq.do',
6 |
7 | handleCharge: function(charge) {
8 | var credential = charge.credential[charge.channel];
9 | utils.formSubmit(this.UPACP_WAP_URL, 'post', credential);
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/src/channels/wx_lite.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by yulitao on 2016/12/29.
3 | */
4 | var stash = require('../stash');
5 | var callbacks = require('../callbacks');
6 | var hasOwn = {}.hasOwnProperty;
7 | /*global wx*/
8 | module.exports = {
9 |
10 | PINGPP_NOTIFY_URL_BASE: 'https://notify.pingxx.com/notify',
11 |
12 | handleCharge: function (charge) {
13 | var credential = charge.credential[charge.channel];
14 | var fields = [
15 | 'appId', 'timeStamp', 'nonceStr', 'package', 'signType', 'paySign'
16 | ];
17 | for (var k = 0; k < fields.length; k++) {
18 | if (!hasOwn.call(credential, fields[k])) {
19 | callbacks.innerCallback('fail',
20 | callbacks.error('invalid_credential', 'missing_field_' + fields[k]));
21 | return;
22 | }
23 | }
24 | stash.jsApiParameters = credential;
25 | this.callpay();
26 | },
27 |
28 | wxLiteEnabled: function () {
29 | return typeof wx !== 'undefined' && wx.requestPayment;
30 | },
31 |
32 | //微信小程序支付
33 | callpay: function () {
34 | if (!this.wxLiteEnabled()) {
35 | console.log('请在微信小程序中打开');
36 | return;
37 | }
38 | var wx_lite = stash.jsApiParameters;
39 | delete wx_lite.appId;
40 | wx_lite.complete = function (res) {
41 | //支付成功
42 | if (res.errMsg === 'requestPayment:ok') {
43 | callbacks.innerCallback('success');
44 | }
45 | //取消支付
46 | if (res.errMsg === 'requestPayment:cancel'
47 | || res.errMsg === 'requestPayment:fail cancel') {
48 | callbacks.innerCallback('cancel', callbacks.error('用户取消支付'));
49 | }
50 | //支付验证签名失败
51 | if (res.err_code !== 'undefined' && res.err_desc !== 'undefined') {
52 | callbacks.innerCallback('fail', callbacks.error(res.err_desc, res));
53 | }
54 | };
55 | wx.requestPayment(wx_lite);
56 | },
57 |
58 | runTestMode: function (charge) {
59 | var path = '/charges/' + charge.id;
60 | wx.request({
61 | url: this.PINGPP_NOTIFY_URL_BASE + path + '?livemode=false',
62 | success: function(res) {
63 | if (res.data == 'success') {
64 | callbacks.innerCallback('success');
65 | } else {
66 | callbacks.innerCallback('fail',
67 | callbacks.error('testmode_notify_fail'));
68 | }
69 | },
70 | fail:function() {
71 | callbacks.innerCallback('fail', callbacks.error('network_err'));
72 | }
73 | });
74 | }
75 | };
76 |
--------------------------------------------------------------------------------
/src/channels/wx_lite_pab.js:
--------------------------------------------------------------------------------
1 | var wxLite = require('./wx_lite');
2 |
3 | module.exports = wxLite;
4 |
--------------------------------------------------------------------------------
/src/channels/wx_pub.js:
--------------------------------------------------------------------------------
1 | var callbacks = require('../callbacks');
2 | var utils = require('../utils');
3 | var stash = require('../stash');
4 | var mods = require('../mods');
5 | var hasOwn = {}.hasOwnProperty;
6 |
7 | /*global WeixinJSBridge*/
8 | module.exports = {
9 |
10 | PINGPP_NOTIFY_URL_BASE: 'https://notify.pingxx.com/notify',
11 |
12 | handleCharge: function(charge) {
13 | var credential = charge.credential[charge.channel];
14 | var fields = [
15 | 'appId', 'timeStamp', 'nonceStr', 'package', 'signType', 'paySign'
16 | ];
17 | for (var k = 0; k < fields.length; k++) {
18 | if (!hasOwn.call(credential, fields[k])) {
19 | callbacks.innerCallback('fail',
20 | callbacks.error('invalid_credential', 'missing_field_' + fields[k]));
21 | return;
22 | }
23 | }
24 | stash.jsApiParameters = credential;
25 | this.callpay();
26 | },
27 |
28 | callpay: function() {
29 | var self = this;
30 | var wx_jssdk = mods.getExtraModule('wx_jssdk');
31 | if (typeof wx_jssdk !== 'undefined' && wx_jssdk.jssdkEnabled()) {
32 | wx_jssdk.callpay();
33 | } else if (typeof WeixinJSBridge == 'undefined') {
34 | var eventCallback = function() {
35 | self.jsApiCall();
36 | };
37 | if (document.addEventListener) {
38 | document.addEventListener('WeixinJSBridgeReady',
39 | eventCallback, false);
40 | } else if (document.attachEvent) {
41 | document.attachEvent('WeixinJSBridgeReady', eventCallback);
42 | document.attachEvent('onWeixinJSBridgeReady', eventCallback);
43 | }
44 | } else {
45 | this.jsApiCall();
46 | }
47 | },
48 |
49 | jsApiCall: function() {
50 | if (hasOwn.call(stash, 'jsApiParameters')) {
51 | WeixinJSBridge.invoke(
52 | 'getBrandWCPayRequest',
53 | stash.jsApiParameters,
54 | function(res) {
55 | delete stash.jsApiParameters;
56 | if (res.err_msg == 'get_brand_wcpay_request:ok') {
57 | callbacks.innerCallback('success');
58 | } else if (res.err_msg == 'get_brand_wcpay_request:cancel') {
59 | callbacks.innerCallback('cancel');
60 | } else {
61 | callbacks.innerCallback('fail',
62 | callbacks.error('wx_result_fail', res.err_msg));
63 | }
64 | }
65 | );
66 | }
67 | },
68 |
69 | runTestMode: function(charge) {
70 | var dopay = confirm('模拟付款?');
71 | if (dopay) {
72 | var path = '/charges/' + charge.id;
73 | utils.request(this.PINGPP_NOTIFY_URL_BASE + path + '?livemode=false',
74 | 'GET', null,
75 | function(data, status) {
76 | if (status >= 200 && status < 400 && data == 'success') {
77 | callbacks.innerCallback('success');
78 | } else {
79 | var extra = 'http_code:' + status + ';response:' + data;
80 | callbacks.innerCallback('fail',
81 | callbacks.error('testmode_notify_fail', extra));
82 | }
83 | },
84 | function() {
85 | callbacks.innerCallback('fail', callbacks.error('network_err'));
86 | });
87 | }
88 | }
89 | };
90 |
--------------------------------------------------------------------------------
/src/channels/wx_pub_pab.js:
--------------------------------------------------------------------------------
1 | var wxPub = require('./wx_pub');
2 |
3 | module.exports = wxPub;
4 |
--------------------------------------------------------------------------------
/src/channels/wx_wap.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var callbacks = require('../callbacks');
3 | var hasOwn = {}.hasOwnProperty;
4 |
5 | module.exports = {
6 |
7 | handleCharge: function(charge) {
8 | var credential = charge.credential[charge.channel];
9 | if (typeof credential === 'string') {
10 | utils.redirectTo(credential, charge.channel);
11 | } else if (typeof credential === 'object'
12 | && hasOwn.call(credential, 'url')
13 | ) {
14 | utils.redirectTo(credential.url, charge.channel);
15 | } else {
16 | callbacks.innerCallback('fail',
17 | callbacks.error('invalid_credential', 'credential 格式不正确'));
18 | }
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/src/channels/yeepay_wap.js:
--------------------------------------------------------------------------------
1 | var utils = require('../utils');
2 | var callbacks = require('../callbacks');
3 | var hasOwn = {}.hasOwnProperty;
4 |
5 | module.exports = {
6 |
7 | YEEPAY_WAP_URL: 'https://ok.yeepay.com/paymobile/api/pay/request',
8 | YEEPAY_WAP_TEST_URL: 'https://mobiletest.yeepay.com/paymobile/api/pay/request',
9 |
10 | handleCharge: function(charge) {
11 | var channel = charge.channel;
12 | var credential = charge.credential[channel];
13 | var fields = ['merchantaccount', 'encryptkey', 'data'];
14 | for (var k = 0; k < fields.length; k++) {
15 | if (!hasOwn.call(credential, fields[k])) {
16 | callbacks.innerCallback('fail',
17 | callbacks.error('invalid_credential', 'missing_field_' + fields[k]));
18 | return;
19 | }
20 | }
21 | var baseURL;
22 | if (hasOwn.call(credential, 'mode') && credential.mode == 'test') {
23 | baseURL = this.YEEPAY_WAP_TEST_URL;
24 | } else {
25 | baseURL = this.YEEPAY_WAP_URL;
26 | }
27 | utils.redirectTo(baseURL + '?' +
28 | utils.stringifyData(credential, channel, true), charge.channel);
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/src/channels/yeepay_wx_lite.js:
--------------------------------------------------------------------------------
1 | var wxPub = require('./wx_lite');
2 |
3 | module.exports = wxPub;
4 |
--------------------------------------------------------------------------------
/src/channels/yeepay_wx_lite_ofl.js:
--------------------------------------------------------------------------------
1 | var wxPub = require('./wx_lite');
2 |
3 | module.exports = wxPub;
4 |
--------------------------------------------------------------------------------
/src/channels/yeepay_wx_pub.js:
--------------------------------------------------------------------------------
1 | var wxPub = require('./wx_pub');
2 |
3 | module.exports = wxPub;
4 |
--------------------------------------------------------------------------------
/src/channels/yeepay_wx_pub_ofl.js:
--------------------------------------------------------------------------------
1 | var wxPub = require('./wx_pub');
2 |
3 | module.exports = wxPub;
4 |
--------------------------------------------------------------------------------
/src/errors.js:
--------------------------------------------------------------------------------
1 | var error = function PingppError(message, extra) {
2 | this.message = message;
3 | this.extra = extra;
4 | };
5 |
6 | module.exports = {
7 | Error: error,
8 | };
9 |
--------------------------------------------------------------------------------
/src/init.js:
--------------------------------------------------------------------------------
1 | var stash = require('./stash');
2 | var utils = require('./utils');
3 |
4 | module.exports = {
5 | init: function() {
6 | var self = this;
7 | utils.documentReady(function(){
8 | try {
9 | (!(utils.inWxLite() || utils.inAlipayLite())) && self.initPuid();
10 | } catch (e){/* empty */}
11 | });
12 | },
13 |
14 | initPuid: function() {
15 | if (typeof window === 'undefined' || typeof localStorage === 'undefined'
16 | || localStorage === null) {
17 | return;
18 | }
19 | var puid = localStorage.getItem('pingpp_uid');
20 | if (puid === null) {
21 | puid = utils.randomString();
22 | try {
23 | localStorage.setItem('pingpp_uid', puid);
24 | } catch (e) {
25 | /* empty */
26 | }
27 | }
28 | stash.puid = puid;
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/src/libs/md5.js:
--------------------------------------------------------------------------------
1 | /*
2 | * JavaScript MD5
3 | * https://github.com/blueimp/JavaScript-MD5
4 | *
5 | * Copyright 2011, Sebastian Tschan
6 | * https://blueimp.net
7 | *
8 | * Licensed under the MIT license:
9 | * http://www.opensource.org/licenses/MIT
10 | *
11 | * Based on
12 | * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
13 | * Digest Algorithm, as defined in RFC 1321.
14 | * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
15 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
16 | * Distributed under the BSD License
17 | * See http://pajhome.org.uk/crypt/md5 for more info.
18 | */
19 |
20 | /* global unescape, module */
21 |
22 | (function () {
23 | /*
24 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally
25 | * to work around bugs in some JS interpreters.
26 | */
27 | function safe_add (x, y) {
28 | var lsw = (x & 0xFFFF) + (y & 0xFFFF);
29 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
30 | return (msw << 16) | (lsw & 0xFFFF);
31 | }
32 |
33 | /*
34 | * Bitwise rotate a 32-bit number to the left.
35 | */
36 | function bit_rol (num, cnt) {
37 | return (num << cnt) | (num >>> (32 - cnt));
38 | }
39 |
40 | /*
41 | * These functions implement the four basic operations the algorithm uses.
42 | */
43 | function md5_cmn (q, a, b, x, s, t) {
44 | return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
45 | }
46 | function md5_ff (a, b, c, d, x, s, t) {
47 | return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
48 | }
49 | function md5_gg (a, b, c, d, x, s, t) {
50 | return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
51 | }
52 | function md5_hh (a, b, c, d, x, s, t) {
53 | return md5_cmn(b ^ c ^ d, a, b, x, s, t);
54 | }
55 | function md5_ii (a, b, c, d, x, s, t) {
56 | return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
57 | }
58 |
59 | /*
60 | * Calculate the MD5 of an array of little-endian words, and a bit length.
61 | */
62 | function binl_md5 (x, len) {
63 | /* append padding */
64 | x[len >> 5] |= 0x80 << (len % 32);
65 | x[(((len + 64) >>> 9) << 4) + 14] = len;
66 |
67 | var i;
68 | var olda;
69 | var oldb;
70 | var oldc;
71 | var oldd;
72 | var a = 1732584193;
73 | var b = -271733879;
74 | var c = -1732584194;
75 | var d = 271733878;
76 |
77 | for (i = 0; i < x.length; i += 16) {
78 | olda = a;
79 | oldb = b;
80 | oldc = c;
81 | oldd = d;
82 |
83 | a = md5_ff(a, b, c, d, x[i], 7, -680876936);
84 | d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
85 | c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
86 | b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
87 | a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
88 | d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
89 | c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
90 | b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
91 | a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
92 | d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
93 | c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
94 | b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
95 | a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
96 | d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
97 | c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
98 | b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
99 |
100 | a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
101 | d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
102 | c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
103 | b = md5_gg(b, c, d, a, x[i], 20, -373897302);
104 | a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
105 | d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
106 | c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
107 | b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
108 | a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
109 | d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
110 | c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
111 | b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
112 | a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
113 | d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
114 | c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
115 | b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
116 |
117 | a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
118 | d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
119 | c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
120 | b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
121 | a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
122 | d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
123 | c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
124 | b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
125 | a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
126 | d = md5_hh(d, a, b, c, x[i], 11, -358537222);
127 | c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
128 | b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
129 | a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
130 | d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
131 | c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
132 | b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
133 |
134 | a = md5_ii(a, b, c, d, x[i], 6, -198630844);
135 | d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
136 | c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
137 | b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
138 | a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
139 | d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
140 | c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
141 | b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
142 | a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
143 | d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
144 | c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
145 | b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
146 | a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
147 | d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
148 | c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
149 | b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
150 |
151 | a = safe_add(a, olda);
152 | b = safe_add(b, oldb);
153 | c = safe_add(c, oldc);
154 | d = safe_add(d, oldd);
155 | }
156 | return [a, b, c, d];
157 | }
158 |
159 | /*
160 | * Convert an array of little-endian words to a string
161 | */
162 | function binl2rstr (input) {
163 | var i;
164 | var output = '';
165 | for (i = 0; i < input.length * 32; i += 8) {
166 | output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
167 | }
168 | return output;
169 | }
170 |
171 | /*
172 | * Convert a raw string to an array of little-endian words
173 | * Characters >255 have their high-byte silently ignored.
174 | */
175 | function rstr2binl (input) {
176 | var i;
177 | var output = [];
178 | output[(input.length >> 2) - 1] = undefined;
179 | for (i = 0; i < output.length; i += 1) {
180 | output[i] = 0;
181 | }
182 | for (i = 0; i < input.length * 8; i += 8) {
183 | output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
184 | }
185 | return output;
186 | }
187 |
188 | /*
189 | * Calculate the MD5 of a raw string
190 | */
191 | function rstr_md5 (s) {
192 | return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
193 | }
194 |
195 | /*
196 | * Calculate the HMAC-MD5, of a key and some data (raw strings)
197 | */
198 | function rstr_hmac_md5 (key, data) {
199 | var i;
200 | var bkey = rstr2binl(key);
201 | var ipad = [];
202 | var opad = [];
203 | var hash;
204 | ipad[15] = opad[15] = undefined;
205 | if (bkey.length > 16) {
206 | bkey = binl_md5(bkey, key.length * 8);
207 | }
208 | for (i = 0; i < 16; i += 1) {
209 | ipad[i] = bkey[i] ^ 0x36363636;
210 | opad[i] = bkey[i] ^ 0x5C5C5C5C;
211 | }
212 | hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
213 | return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
214 | }
215 |
216 | /*
217 | * Convert a raw string to a hex string
218 | */
219 | function rstr2hex (input) {
220 | var hex_tab = '0123456789abcdef';
221 | var output = '';
222 | var x;
223 | var i;
224 | for (i = 0; i < input.length; i += 1) {
225 | x = input.charCodeAt(i);
226 | output += hex_tab.charAt((x >>> 4) & 0x0F) +
227 | hex_tab.charAt(x & 0x0F);
228 | }
229 | return output;
230 | }
231 |
232 | /*
233 | * Encode a string as utf-8
234 | */
235 | function str2rstr_utf8 (input) {
236 | return unescape(encodeURIComponent(input));
237 | }
238 |
239 | /*
240 | * Take string arguments and return either raw or hex encoded strings
241 | */
242 | function raw_md5 (s) {
243 | return rstr_md5(str2rstr_utf8(s));
244 | }
245 | function hex_md5 (s) {
246 | return rstr2hex(raw_md5(s));
247 | }
248 | function raw_hmac_md5 (k, d) {
249 | return rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d));
250 | }
251 | function hex_hmac_md5 (k, d) {
252 | return rstr2hex(raw_hmac_md5(k, d));
253 | }
254 |
255 | function md5 (string, key, raw) {
256 | if (!key) {
257 | if (!raw) {
258 | return hex_md5(string);
259 | }
260 | return raw_md5(string);
261 | }
262 | if (!raw) {
263 | return hex_hmac_md5(key, string);
264 | }
265 | return raw_hmac_md5(key, string);
266 | }
267 |
268 | module.exports = md5;
269 | }());
270 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | var version = require('./version').v;
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | var PingppSDK = function () {
5 | require('./init').init();
6 | };
7 |
8 | PingppSDK.prototype.version = version;
9 |
10 | module.exports = new PingppSDK();
11 |
12 | var testmode = require('./testmode');
13 | var callbacks = require('./callbacks');
14 | var PingppError = require('./errors').Error;
15 | var mods = require('./mods');
16 | var stash = require('./stash');
17 | var payment_elements = require('./payment_elements');
18 | var transfer_elements = require('./transfer_elements');
19 |
20 | PingppSDK.prototype.createPayment = function (
21 | chargeJSON, callback, signature, debug
22 | ) {
23 | if (typeof callback === 'function') {
24 | callbacks.userCallback = callback;
25 | }
26 |
27 | try {
28 | payment_elements.init(chargeJSON);
29 | } catch (e) {
30 | if (e instanceof PingppError) {
31 | callbacks.innerCallback('fail',
32 | callbacks.error(e.message, e.extra));
33 | return;
34 | } else {
35 | throw e;
36 | }
37 | }
38 |
39 | if (!hasOwn.call(payment_elements, 'id')) {
40 | callbacks.innerCallback('fail',
41 | callbacks.error('invalid_charge', 'no_charge_id'));
42 | return;
43 | }
44 | if (!hasOwn.call(payment_elements, 'channel')) {
45 | callbacks.innerCallback('fail',
46 | callbacks.error('invalid_charge', 'no_channel'));
47 | return;
48 | }
49 |
50 | if (hasOwn.call(payment_elements, 'app')) {
51 | if (typeof payment_elements.app === 'string') {
52 | stash.app_id = payment_elements.app;
53 | } else if (typeof payment_elements.app === 'object' &&
54 | typeof payment_elements.app.id === 'string') {
55 | stash.app_id = payment_elements.app.id;
56 | }
57 | }
58 | var channel = payment_elements.channel;
59 | if (!hasOwn.call(payment_elements, 'credential')) {
60 | callbacks.innerCallback('fail',
61 | callbacks.error('invalid_charge', 'no_credential'));
62 | return;
63 | }
64 | if (payment_elements.paid && payment_elements.actual_amount === 0) {
65 | callbacks.innerCallback('success');
66 | return;
67 | }
68 |
69 | if (!payment_elements.credential) {
70 | callbacks.innerCallback('fail',
71 | callbacks.error('invalid_credential', 'credential_is_undefined'));
72 | return;
73 | }
74 | if (!hasOwn.call(payment_elements.credential, channel)) {
75 | callbacks.innerCallback('fail',
76 | callbacks.error('invalid_credential', 'credential_is_incorrect'));
77 | return;
78 | }
79 | if (!hasOwn.call(payment_elements, 'livemode')) {
80 | callbacks.innerCallback('fail',
81 | callbacks.error('invalid_charge', 'no_livemode_field'));
82 | return;
83 | }
84 | var channelModule = mods.getChannelModule(channel);
85 | if (typeof channelModule === 'undefined') {
86 | console.error('channel module "' + channel + '" is undefined');
87 | callbacks.innerCallback('fail',
88 | callbacks.error('invalid_channel',
89 | 'channel module "' + channel + '" is undefined')
90 | );
91 | return;
92 | }
93 | if (payment_elements.livemode === false) {
94 | if (hasOwn.call(channelModule, 'runTestMode')) {
95 | channelModule.runTestMode(payment_elements);
96 | } else {
97 | testmode.runTestMode(payment_elements);
98 | }
99 | return;
100 | }
101 |
102 | if (typeof signature != 'undefined') {
103 | stash.signature = signature;
104 | }
105 | if (typeof debug == 'boolean') {
106 | stash.debug = debug;
107 | }
108 | channelModule.handleCharge(payment_elements);
109 | };
110 |
111 | PingppSDK.prototype.setAPURL = function (url) {
112 | stash.APURL = url;
113 | };
114 |
115 | PingppSDK.prototype.setUrlReturnCallback = function (callback, channels) {
116 | if (typeof callback === 'function') {
117 | callbacks.urlReturnCallback = callback;
118 | } else {
119 | throw 'callback need to be a function';
120 | }
121 |
122 | if (typeof channels !== 'undefined') {
123 | if (Array.isArray(channels)) {
124 | callbacks.urlReturnChannels = channels;
125 | } else {
126 | throw 'channels need to be an array';
127 | }
128 | }
129 | };
130 |
131 | PingppSDK.prototype.signAgreement = function (agreement, callback) {
132 | if (typeof callback === 'function') {
133 | callbacks.userAgreementCallback = callback;
134 | }
135 |
136 | var module = mods.getExtraModule('agreement');
137 | if (typeof module === 'undefined') {
138 | console.error('module "agreement" is undefined');
139 | callbacks.innerCallback('fail',
140 | callbacks.error('invalid_module',
141 | 'module "agreement" is undefined')
142 | );
143 | return false;
144 | }
145 |
146 | return module.signAgreement(agreement);
147 | };
148 |
149 | PingppSDK.prototype.createTransfer = function (transfer, callback) {
150 | if (typeof callback === "function") {
151 | callbacks.userTransferCallback = callback;
152 | }
153 |
154 | try {
155 | transfer_elements.init(transfer);
156 | } catch (e) {
157 | if (e instanceof PingppError) {
158 | callbacks.innerTransferCallback(
159 | "fail",
160 | callbacks.error(e.message, e.extra),
161 | );
162 | return;
163 | } else {
164 | throw e;
165 | }
166 | }
167 |
168 | if (!hasOwn.call(transfer_elements, "id")) {
169 | callbacks.innerTransferCallback(
170 | "fail",
171 | callbacks.error("invalid_transfer", "no_transfer_id"),
172 | );
173 | return;
174 | }
175 |
176 | if (!hasOwn.call(transfer_elements, "channel")) {
177 | callbacks.innerTransferCallback(
178 | "fail",
179 | callbacks.error("invalid_transfer", "no_channel"),
180 | );
181 | return;
182 | }
183 |
184 | if (hasOwn.call(transfer_elements, "app")) {
185 | if (typeof transfer_elements.app === "string") {
186 | stash.app_id = transfer_elements.app;
187 | } else if (
188 | typeof transfer_elements.app === "object" &&
189 | typeof transfer_elements.app.id === "string"
190 | ) {
191 | stash.app_id = transfer_elements.app.id;
192 | }
193 | }
194 |
195 | const channel = transfer_elements.channel;
196 | if (!hasOwn.call(transfer_elements, "extra")) {
197 | callbacks.innerTransferCallback(
198 | "fail",
199 | callbacks.error("invalid_transfer", "no_credential"),
200 | );
201 | return;
202 | }
203 | if (transfer_elements.status === "paid") {
204 | callbacks.innerTransferCallback("success");
205 | return;
206 | }
207 |
208 | if (!transfer_elements.extra) {
209 | callbacks.innerTransferCallback(
210 | "fail",
211 | callbacks.error("invalid_credential", "credential_is_undefined"),
212 | );
213 | return;
214 | }
215 |
216 | if (!hasOwn.call(transfer_elements, "livemode")) {
217 | callbacks.innerTransferCallback(
218 | "fail",
219 | callbacks.error("invalid_transfer", "no_livemode_field"),
220 | );
221 | return;
222 | }
223 | const channelModule = mods.getTransferChannelModule(channel);
224 | if (typeof channelModule === "undefined") {
225 | console.error('transfer channel module "' + channel + '" is undefined');
226 | callbacks.innerTransferCallback(
227 | "fail",
228 | callbacks.error(
229 | "invalid_channel",
230 | 'transfer channel module "' + channel + '" is undefined',
231 | ),
232 | );
233 | return;
234 | }
235 | if (transfer_elements.livemode === false) {
236 | callbacks.innerTransferCallback(
237 | "fail",
238 | callbacks.error("invalid_transfer", "testmode_not_supported"),
239 | );
240 | return;
241 | }
242 |
243 | if (typeof signature != "undefined") {
244 | stash.signature = signature;
245 | }
246 | if (typeof debug == "boolean") {
247 | stash.debug = debug;
248 | }
249 | channelModule.handleTransfer(transfer_elements);
250 | };
251 |
--------------------------------------------------------------------------------
/src/mods.js:
--------------------------------------------------------------------------------
1 | var hasOwn = {}.hasOwnProperty;
2 | var mods = {};
3 | module.exports = mods;
4 |
5 | mods.channels = {
6 | abc_pay: require('./channels/abc_pay'),
7 | abc_pub: require('./channels/abc_pub'),
8 | alipay: require('./channels/alipay'),
9 | alipay_lite: require('./channels/alipay_lite'),
10 | alipay_pc_direct: require('./channels/alipay_pc_direct'),
11 | alipay_qr: require('./channels/alipay_qr'),
12 | alipay_qr_lakala: require('./channels/alipay_qr_lakala'),
13 | alipay_wap: require('./channels/alipay_wap'),
14 | alipay_wap_lakala: require('./channels/alipay_wap_lakala'),
15 | bfb_wap: require('./channels/bfb_wap'),
16 | cb_alipay_pc_direct: require('./channels/cb_alipay_pc_direct'),
17 | cb_alipay_wap: require('./channels/cb_alipay_wap'),
18 | cb_wx_pub: require('./channels/cb_wx_pub'),
19 | ccb_qr: require('./channels/ccb_qr'),
20 | ccb_wap: require('./channels/ccb_wap'),
21 | chinaums_alipay_pub: require('./channels/chinaums_alipay_pub'),
22 | chinaums_alipay_wap: require('./channels/chinaums_alipay_wap'),
23 | chinaums_upacp_wap: require('./channels/chinaums_upacp_wap'),
24 | chinaums_wx_pub: require('./channels/chinaums_wx_pub'),
25 | chinaums_wx_wap: require('./channels/chinaums_wx_wap'),
26 | cmb_pc_qr: require('./channels/cmb_pc_qr'),
27 | cmb_wallet: require('./channels/cmb_wallet'),
28 | cp_b2b: require('./channels/cp_b2b'),
29 | isv_lite: require('./channels/isv_lite'),
30 | isv_wap: require('./channels/isv_wap'),
31 | jdpay_wap: require('./channels/jdpay_wap'),
32 | nucc_b2b_lakala: require('./channels/nucc_b2b_lakala'),
33 | nucc_b2c_lakala: require('./channels/nucc_b2c_lakala'),
34 | pab_pc: require('./channels/pab_pc'),
35 | paypal: require('./channels/paypal'),
36 | qpay_pub: require('./channels/qpay_pub'),
37 | upacp_b2b: require('./channels/upacp_b2b'),
38 | upacp_pc: require('./channels/upacp_pc'),
39 | upacp_wap: require('./channels/upacp_wap'),
40 | wx_lite: require('./channels/wx_lite'),
41 | wx_lite_pab: require('./channels/wx_lite_pab'),
42 | wx_pub: require('./channels/wx_pub'),
43 | wx_pub_pab: require('./channels/wx_pub_pab'),
44 | wx_wap: require('./channels/wx_wap'),
45 | yeepay_wap: require('./channels/yeepay_wap'),
46 | yeepay_wx_lite: require('./channels/yeepay_wx_lite'),
47 | yeepay_wx_lite_ofl: require('./channels/yeepay_wx_lite_ofl'),
48 | yeepay_wx_pub: require('./channels/yeepay_wx_pub'),
49 | yeepay_wx_pub_ofl: require('./channels/yeepay_wx_pub_ofl')
50 | };
51 |
52 | mods.extras = {
53 | ap: require('./channels/extras/ap'),
54 | agreement: require('./agreement')
55 | };
56 |
57 | mods.transferChannels = {
58 | wx_pub: require('./transfer_channels/wx_pub'),
59 | }
60 |
61 | mods.getChannelModule = function(channel) {
62 | if (hasOwn.call(mods.channels, channel)) {
63 | return mods.channels[channel];
64 | }
65 | return undefined;
66 | };
67 |
68 | mods.getTransferChannelModule = function(channel) {
69 | if (hasOwn.call(mods.transferChannels, channel)) {
70 | return mods.transferChannels[channel];
71 | }
72 | return undefined;
73 | };
74 |
75 | mods.getExtraModule = function(name) {
76 | if (hasOwn.call(mods.extras, name)) {
77 | return mods.extras[name];
78 | }
79 | return undefined;
80 | };
81 |
--------------------------------------------------------------------------------
/src/payment_elements.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by dong on 2016/12/30.
3 | */
4 |
5 | var PingppError = require('./errors').Error;
6 | var hasOwn = {}.hasOwnProperty;
7 |
8 | module.exports = {
9 | id: null,
10 | or_id: null,
11 | channel: null,
12 | app: null,
13 | credential: {},
14 | extra: null,
15 | livemode: null,
16 | order_no: null,
17 | time_expire: null,
18 | paid: false,
19 | status: null,
20 | actual_amount: null,
21 |
22 | init: function (charge_or_order) {
23 | var charge;
24 | if (typeof charge_or_order === 'string') {
25 | try {
26 | charge = JSON.parse(charge_or_order);
27 | } catch (err) {
28 | throw new PingppError('json_decode_fail', err);
29 | }
30 | } else {
31 | charge = charge_or_order;
32 | }
33 |
34 | if (typeof charge === 'undefined') {
35 | throw new PingppError('json_decode_fail');
36 | }
37 |
38 | if (hasOwn.call(charge, 'object') && charge.object == 'order') {
39 | charge.or_id = charge.id;
40 | charge.order_no = charge.merchant_order_no;
41 | var charge_essentials = charge.charge_essentials;
42 | charge.channel = charge_essentials.channel;
43 | charge.credential = charge_essentials.credential;
44 | charge.extra = charge_essentials.extra;
45 | if(hasOwn.call(charge, 'charge') && charge.charge != null) {
46 | charge.id = charge.charge;
47 | } else if(hasOwn.call(charge_essentials, 'id')
48 | && charge_essentials.id != null) {
49 | charge.id = charge_essentials.id;
50 | } else if(hasOwn.call(charge, 'charges')) {
51 | for(var i = 0; i < charge.charges.data.length; i++){
52 | if(charge.charges.data[i].channel === charge_essentials.channel) {
53 | charge.id = charge.charges.data[i].id;
54 | break;
55 | }
56 | }
57 | }
58 | } else if(hasOwn.call(charge, 'object') && charge.object == 'recharge') {
59 | charge = charge.charge;
60 | }
61 |
62 | for (var key in this) {
63 | if (hasOwn.call(charge, key)) {
64 | this[key] = charge[key];
65 | }
66 | }
67 | return this;
68 | },
69 |
70 | clear: function () {
71 | for (var key in this) {
72 | if (typeof this[key] !== 'function') {
73 | this[key] = null;
74 | }
75 | }
76 | }
77 | };
--------------------------------------------------------------------------------
/src/stash.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | };
3 |
--------------------------------------------------------------------------------
/src/testmode.js:
--------------------------------------------------------------------------------
1 | var utils = require('./utils');
2 | var hasOwn = {}.hasOwnProperty;
3 | module.exports = {
4 | PINGPP_MOCK_URL: 'https://sissi.pingxx.com/mock.php',
5 |
6 | runTestMode: function (charge) {
7 | var params = {
8 | 'ch_id': charge.id,
9 | 'scheme': 'http',
10 | 'channel': charge.channel
11 | };
12 |
13 | if (hasOwn.call(charge, 'order_no')) {
14 | params.order_no = charge.order_no;
15 | } else if (hasOwn.call(charge, 'orderNo')) {
16 | params.order_no = charge.orderNo;
17 | }
18 | if (hasOwn.call(charge, 'time_expire')) {
19 | params.time_expire = charge.time_expire;
20 | } else if (hasOwn.call(charge, 'timeExpire')) {
21 | params.time_expire = charge.timeExpire;
22 | }
23 | if (hasOwn.call(charge, 'extra')) {
24 | params.extra = encodeURIComponent(JSON.stringify(charge.extra));
25 | }
26 | utils.redirectTo(
27 | this.PINGPP_MOCK_URL + '?' + utils.stringifyData(params),
28 | charge.channel
29 | );
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/src/transfer_channels/wx_pub.js:
--------------------------------------------------------------------------------
1 | var callbacks = require('../callbacks');
2 | var stash = require('../stash');
3 | var mods = require('../mods');
4 | var hasOwn = {}.hasOwnProperty;
5 |
6 | module.exports = {
7 | handleTransfer: function(transfer) {
8 | const credential = {};
9 | const fields = [
10 | 'appId', 'mchId', 'package'
11 | ];
12 | for (let k = 0; k < fields.length; k++) {
13 | if (!hasOwn.call(transfer.extra, fields[k])) {
14 | callbacks.innerTransferCallback('fail', callbacks.error('invalid_credential', 'missing_field_' + fields[k]));
15 | console.error(fields[k]);
16 | return;
17 | } else {
18 | credential[fields[k]] = transfer.extra[fields[k]];
19 | }
20 | }
21 | stash.jsApiParameters = credential;
22 | this.callTransfer();
23 | },
24 |
25 | callTransfer: function() {
26 | const self = this;
27 | const wx_jssdk = mods.getExtraModule('wx_jssdk');
28 | if (typeof wx_jssdk !== 'undefined' && wx_jssdk.jssdkEnabled()) {
29 | wx_jssdk.callpay();
30 | } else if (typeof WeixinJSBridge === 'undefined') {
31 | const eventCallback = function () {
32 | self.jsApiCall();
33 | };
34 | if (typeof document === 'undefined') {
35 | callbacks.innerTransferCallback(
36 | "fail",
37 | callbacks.error(
38 | "invalid_environment",
39 | "document_is_undefined",
40 | ),
41 | );
42 | return;
43 | }
44 | if (document.addEventListener) {
45 | document.addEventListener('WeixinJSBridgeReady',
46 | eventCallback, false);
47 | } else if (document.attachEvent) {
48 | document.attachEvent('WeixinJSBridgeReady', eventCallback);
49 | document.attachEvent('onWeixinJSBridgeReady', eventCallback);
50 | }
51 | } else {
52 | this.jsApiCall();
53 | }
54 | },
55 |
56 | jsApiCall: function() {
57 | if (hasOwn.call(stash, 'jsApiParameters')) {
58 | WeixinJSBridge.invoke(
59 | 'requestMerchantTransfer',
60 | stash.jsApiParameters,
61 | function(res) {
62 | delete stash.jsApiParameters;
63 | if (res.err_msg === 'requestMerchantTransfer:ok') {
64 | callbacks.innerTransferCallback("success");
65 | } else if (res.err_msg === 'requestMerchantTransfer:cancel') {
66 | callbacks.innerTransferCallback("cancel");
67 | } else {
68 | callbacks.innerTransferCallback(
69 | "fail",
70 | callbacks.error("wx_result_fail", res.err_msg),
71 | );
72 | }
73 | }
74 | );
75 | }
76 | }
77 | };
78 |
--------------------------------------------------------------------------------
/src/transfer_elements.js:
--------------------------------------------------------------------------------
1 | var PingppError = require('./errors').Error;
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | module.exports = {
5 | id: null,
6 | channel: null,
7 | app: null,
8 | extra: null,
9 | livemode: null,
10 | order_no: null,
11 | time_expire: null,
12 | status: null,
13 |
14 | init: function (params) {
15 | let transfer;
16 | if (typeof params === 'string') {
17 | try {
18 | transfer = JSON.parse(params);
19 | } catch (err) {
20 | throw new PingppError('json_decode_fail', err);
21 | }
22 | } else {
23 | transfer = params;
24 | }
25 |
26 | if (typeof transfer === 'undefined') {
27 | throw new PingppError('json_decode_fail');
28 | }
29 |
30 | for (var key in this) {
31 | if (hasOwn.call(transfer, key)) {
32 | this[key] = transfer[key];
33 | }
34 | }
35 | return this;
36 | },
37 |
38 | clear: function () {
39 | for (var key in this) {
40 | if (typeof this[key] !== 'function') {
41 | this[key] = null;
42 | }
43 | }
44 | }
45 | };
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | var callbacks = require('./callbacks');
2 | var hasOwn = {}.hasOwnProperty;
3 |
4 | var utils = module.exports = {
5 |
6 | /**
7 | * 对象转换成 query string
8 | * @param object data 待转对象
9 | * @param string channel 渠道
10 | * @param boolean urlencode 是否需要 urlencode
11 | *
12 | * @return string query string
13 | */
14 | stringifyData: function (data, channel, urlencode) {
15 | if (typeof urlencode == 'undefined') {
16 | urlencode = false;
17 | }
18 | var output = [];
19 | for (var i in data) {
20 | if (!hasOwn.call(data, i) || typeof data[i] === 'function') {
21 | continue;
22 | }
23 | if (channel == 'bfb_wap' && i == 'url') {
24 | continue;
25 | }
26 | if (channel == 'yeepay_wap' && i == 'mode') {
27 | continue;
28 | }
29 | if (i == 'channel_url') {
30 | continue;
31 | }
32 | output.push(i + '=' +
33 | (urlencode ? encodeURIComponent(data[i]) : data[i]));
34 | }
35 | return output.join('&');
36 | },
37 |
38 | /**
39 | * 网络请求
40 | * @param string url
41 | * @param string method 请求方式, POST, GET ...
42 | * @param object requestData 请求数据
43 | * @param function successCallback 成功回调 (data, statusCode, xhr)
44 | * @param function errorCallback 错误回调 (xhr, statusCode, error)
45 | */
46 | request: function (url, method, requestData,
47 | successCallback, errorCallback, headers) {
48 | if (typeof XMLHttpRequest === 'undefined') {
49 | console.log('Function XMLHttpRequest is undefined.');
50 | return;
51 | }
52 | var xhr = new XMLHttpRequest();
53 | if (typeof xhr.timeout !== 'undefined') {
54 | xhr.timeout = 6000;
55 | }
56 | method = method.toUpperCase();
57 |
58 | if (method === 'GET' && typeof requestData === 'object' && requestData) {
59 | url += '?' + utils.stringifyData(requestData, '', true);
60 | }
61 | xhr.open(method, url, true);
62 | if (typeof headers !== 'undefined') {
63 | for (var k in headers) {
64 | if (hasOwn.call(headers, k)) {
65 | xhr.setRequestHeader(k, headers[k]);
66 | }
67 | }
68 | }
69 | if (method === 'POST') {
70 | xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');
71 | xhr.send(JSON.stringify(requestData));
72 | } else {
73 | xhr.send();
74 | }
75 | if (typeof successCallback == 'undefined') {
76 | successCallback = function () {};
77 | }
78 | if (typeof errorCallback == 'undefined') {
79 | errorCallback = function () {};
80 | }
81 | xhr.onreadystatechange = function () {
82 | if (xhr.readyState == 4) {
83 | successCallback(xhr.responseText, xhr.status, xhr);
84 | }
85 | };
86 | xhr.onerror = function (e) {
87 | errorCallback(xhr, 0, e);
88 | };
89 | },
90 |
91 | /**
92 | * 表单提交
93 | * @param string url
94 | * @param string method 请求方式, POST, GET ...
95 | * @param object params 请求数据
96 | */
97 | formSubmit: function (url, method, params) {
98 | if (typeof window === 'undefined') {
99 | console.log('Not a browser, form submit url: ' + url);
100 | return;
101 | }
102 | var form = document.createElement('form');
103 | form.setAttribute('method', method);
104 | form.setAttribute('action', url);
105 |
106 | for (var key in params) {
107 | if (hasOwn.call(params, key)) {
108 | var hiddenField = document.createElement('input');
109 | hiddenField.setAttribute('type', 'hidden');
110 | hiddenField.setAttribute('name', key);
111 | hiddenField.setAttribute('value', params[key]);
112 | form.appendChild(hiddenField);
113 | }
114 | }
115 |
116 | document.body.appendChild(form);
117 | form.submit();
118 | },
119 |
120 | randomString: function (length) {
121 | if (typeof length == 'undefined') {
122 | length = 32;
123 | }
124 | var chars =
125 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
126 | var maxPos = chars.length;
127 | var str = '';
128 | for (var i = 0; i < length; i++) {
129 | str += chars.charAt(Math.floor(Math.random() * maxPos));
130 | }
131 |
132 | return str;
133 | },
134 |
135 | redirectTo: function (url, channel) {
136 | if (callbacks.shouldReturnUrlByCallback(channel)) {
137 | callbacks.triggerUrlReturnCallback(null, url);
138 | return;
139 | }
140 | if (typeof window === 'undefined') {
141 | console.log('Not a browser, redirect url: ' + url);
142 | return;
143 | }
144 | window.location.href = url;
145 | },
146 |
147 | inWeixin: function () {
148 | if (typeof navigator === 'undefined') {
149 | return false;
150 | }
151 | var ua = navigator.userAgent.toLowerCase();
152 | return ua.indexOf('micromessenger') !== -1;
153 | },
154 |
155 | inAlipay: function () {
156 | if (typeof navigator === 'undefined') {
157 | return false;
158 | }
159 | var ua = navigator.userAgent.toLowerCase();
160 | return ua.indexOf('alipayclient') !== -1;
161 | },
162 |
163 | /*global wx*/
164 | inWxLite: function() {
165 | if(typeof wx === 'undefined') {
166 | return false;
167 | }
168 |
169 | return wx.miniProgram || wx.requestPayment;
170 | },
171 |
172 | /*global my*/
173 | inAlipayLite: function() {
174 | if(typeof my === 'undefined') {
175 | return false;
176 | }
177 |
178 | return my.tradePay;
179 | },
180 |
181 | documentReady: function (fn) {
182 | if (typeof document === 'undefined') {
183 | fn();
184 | return;
185 | }
186 | if (document.readyState != 'loading') {
187 | fn();
188 | } else {
189 | document.addEventListener('DOMContentLoaded', fn);
190 | }
191 | },
192 |
193 | loadUrlJs: function (sid, jsurl, callback) {
194 | var nodeHead = document.getElementsByTagName('head')[0];
195 | var nodeScript = null;
196 | if (document.getElementById(sid) == null) {
197 | nodeScript = document.createElement('script');
198 | nodeScript.setAttribute('type', 'text/javascript');
199 | nodeScript.setAttribute('src', jsurl);
200 | nodeScript.setAttribute('id', sid);
201 | nodeScript.async = true;
202 | if (callback != null) {
203 | nodeScript.onload = nodeScript.onreadystatechange = function () {
204 | if (nodeScript.ready) {
205 | return false;
206 | }
207 |
208 | if (!nodeScript.readyState || nodeScript.readyState == 'loaded'
209 | || nodeScript.readyState == 'complete') {
210 | nodeScript.ready = true;
211 | callback();
212 | }
213 | };
214 | }
215 | nodeHead.appendChild(nodeScript);
216 | } else {
217 | if (callback != null) {
218 | callback();
219 | }
220 | }
221 | },
222 | deviceDetectorMobile: function () {
223 | return /Mobi/.test(window.navigator.userAgent);
224 | },
225 | };
226 |
--------------------------------------------------------------------------------
/src/version.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | v: '2.4.0'
3 | };
4 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | /*eslint quotes: ["off"]*/
2 | /*eslint max-len: ["off"]*/
3 |
4 | module.exports = {
5 | pingpp: undefined,
6 |
7 | run: function() {
8 | const version = require('../package.json').version;
9 | this.pingpp = require('../src/main.js');
10 | if (version !== this.pingpp.version) {
11 | console.error('Version number does not match.');
12 | } else {
13 | console.log(`Version: ${this.pingpp.version}`);
14 | }
15 |
16 | this.testCharge();
17 | this.testChargeCcbWap();
18 | this.testAgreement();
19 | this.testTransfer()
20 | },
21 |
22 | testTransfer: function () {
23 | console.log('running transfer test...');
24 |
25 | const transfer = {
26 | "id": "tr_131250327649096837120006",
27 | "object": "transfer",
28 | "type": "b2c",
29 | "created": 1743068187,
30 | "time_transferred": null,
31 | "livemode": true,
32 | "status": "wait_user_confirm",
33 | "app": "app_1Gqj58ynP0mHeX1q",
34 | "channel": "wx_pub",
35 | "order_no": "912111743068187",
36 | "batch_no": null,
37 | "amount": 10,
38 | "amount_settle": 10,
39 | "currency": "cny",
40 | "recipient": "otdLiw0bx_HJUALDp_dzAAjp7BCA",
41 | "description": "转账测试",
42 | "transaction_no": "1330000139344692503270012303775666",
43 | "failure_msg": null,
44 | "extra": {
45 | "scene_id": "1005",
46 | "product_code": "fund-app",
47 | "scene_report_info": [
48 | {
49 | "info_type": "岗位类型",
50 | "info_content": "测试"
51 | },
52 | {
53 | "info_type": "报酬说明",
54 | "info_content": "测试"
55 | }
56 | ],
57 | "package": "ABBQO+oYAAABAAAAAADBGUx8UBAabcdHHhzlZxAAAADnGabcZahT9IkJjn90+abcRXA0BwkohpO9+F1BLQuBl2pCXphJtQK18bS/ShfGsIUmr1UTByVyMKCC/0/aUmIbP9y7Q8s7qutM1gFiMDRKQbtU2ks=",
58 | "mchId": "1250015000",
59 | "appId": "wx9cfac8008001600"
60 | },
61 | "metadata": {}
62 | }
63 |
64 | const ret = this.pingpp.createTransfer(transfer, (result, error) => {
65 | console.log(result);
66 | console.log(error);
67 | });
68 |
69 | console.log(ret);
70 | },
71 |
72 | testCharge: function () {
73 | console.log('running charge test...');
74 |
75 | this.pingpp.setUrlReturnCallback(function (err, url) {
76 | console.log("UrlReturnCallback: " + url);
77 | });
78 |
79 | var charge = `{
80 | "id": "ch_jD0mL8L88i9Sub9OG0qTiTOS",
81 | "object": "charge",
82 | "created": 1512994590,
83 | "livemode": true,
84 | "paid": false,
85 | "refunded": false,
86 | "reversed": false,
87 | "app": "app_1Gqj58ynP0mHeX1q",
88 | "channel": "alipay_pc_direct",
89 | "order_no": "201700211512994583",
90 | "client_ip": "192.168.23.32",
91 | "amount": 100,
92 | "amount_settle": 99,
93 | "currency": "cny",
94 | "subject": "测试订单",
95 | "body": "订单详情",
96 | "extra": {
97 | "success_url": "https://example.com/success",
98 | "qr_pay_mode": 4,
99 | "qrcode_width": 300
100 | },
101 | "time_paid": null,
102 | "time_expire": 1513080990,
103 | "time_settle": null,
104 | "transaction_no": null,
105 | "refunds": {
106 | "object": "list",
107 | "url": "/v1/charges/ch_jD0mL8L88i9Sub9OG0qTiTOS/refunds",
108 | "has_more": false,
109 | "data": []
110 | },
111 | "amount_refunded": 0,
112 | "failure_code": null,
113 | "failure_msg": null,
114 | "metadata": {},
115 | "credential": {
116 | "object": "credential",
117 | "alipay_pc_direct": {
118 | "app_id": "2016110302520983",
119 | "method": "alipay.trade.page.pay",
120 | "format": "JSON",
121 | "charset": "utf-8",
122 | "sign_type": "RSA2",
123 | "timestamp": "2017-12-11 20:16:30",
124 | "version": "1.0",
125 | "biz_content": "{\\"body\\":\\"订单详情\\",\\"subject\\":\\"测试订单\\",\\"out_trade_no\\":\\"201700211512994583\\",\\"total_amount\\":1,\\"product_code\\":\\"FAST_INSTANT_TRADE_PAY\\",\\"timeout_express\\":\\"1440m\\",\\"qr_pay_mode\\":4,\\"qrcode_width\\":300}",
126 | "notify_url": "https://notify.pingxx.com/notify/charges/ch_jD0mL8L88i9Sub9OG0qTiTOS",
127 | "return_url": "https://example.com/success",
128 | "sign": "qj7mZXBmp7s8aoWlfruqbJWNZc/Qmzrzo1BFhYvbQL6dJskc3NX7oScZuwJIoBhts/mgO77+ziYceI1XANJBhXhFzwJQS0vgEBpwzxAEY008FSbf8Rolfck6C2lyXH+4uhjlk5bzwBAMa2VudR0zcfK1/rUiHVNuG/YHhQIietyyG1SVL/YnMhwo+b7cDLn87pj6/tYRxBNob9cLRMZLQ9JOgHb2JRuRxDpiIpfSlBQMMnoC2TvkUkrLGjhdSsUXd1QqTDbT28+tsMtPMBIjw4Lmgpw6Qr/Y39MtVTOUiSIHdwnG37+8GVML6zfP9v6KNYwH62GNIU0PfpsMzv4p+w==",
129 | "channel_url": "https://openapi.alipay.com/gateway.do"
130 | }
131 | },
132 | "description": null
133 | }`;
134 |
135 | this.pingpp.createPayment(charge, function(result, error){
136 | console.log(result);
137 | console.log(error);
138 | });
139 | },
140 |
141 | testAgreement: function () {
142 | console.log('running agreement test...');
143 |
144 | var agreement = {
145 | "id": "agr_19EFuyiLcdTshr",
146 | "object": "agreement",
147 | "livemode": true,
148 | "app": "app_1Gqj58ynP0mHeX1q",
149 | "created": 1545882366,
150 | "channel": "wx",
151 | "contract_no": "912111545882234",
152 | "contract_id": null,
153 | "credential": {
154 | "object": "credential",
155 | "wx": {
156 | "credential": "https://api.mch.weixin.qq.com/papay/entrustweb?appid=wx87cae2333f5068e1&mch_id=1300233301&plan_id=123611&contract_code=912111545882234&request_serial=912111545882234&contract_display_account=test¬ify_url=https%3A%2F%2Fnotify.pingxx.com%2Fnotify%2Fagreements%2Fagr_19EFuyiLcdTsht&version=1.0×tamp=1545882366&sign=11E5F8C28FE1CE78CF7FEEC1C502EC33"
157 | }
158 | },
159 | "status": "created",
160 | "time_succeeded": null,
161 | "time_canceled": null,
162 | "failure_code": null,
163 | "failure_msg": null,
164 | "extra": {
165 | "plan_id": "123611",
166 | "request_serial": "912111545882234",
167 | "display_account": "test"
168 | },
169 | "metadata": {},
170 | "source": null
171 | };
172 |
173 | var ret = this.pingpp.signAgreement(agreement, function (result, error) {
174 | console.log(result);
175 | console.log(error);
176 | });
177 |
178 | console.log(ret);
179 | },
180 |
181 | testChargeCcbWap: function () {
182 | console.log('running charge ccb_wap test...');
183 |
184 | this.pingpp.setUrlReturnCallback(function (err, url) {
185 | console.log("UrlReturnCallback: " + url);
186 | }, ['ccb_wap']);
187 |
188 | var charge = `{
189 | "id": "ch_101200415434992752640001",
190 | "object": "charge",
191 | "created": 1586922479,
192 | "livemode": true,
193 | "paid": false,
194 | "refunded": false,
195 | "reversed": false,
196 | "app": "app_1Gqj58ynP0mHeX1q",
197 | "channel": "ccb_wap",
198 | "order_no": "202002060026",
199 | "client_ip": "127.0.0.1",
200 | "amount": 1,
201 | "amount_settle": 1,
202 | "currency": "cny",
203 | "subject": "测试订单",
204 | "body": "订单详情",
205 | "extra": {
206 | "pos_id": "044507853"
207 | },
208 | "time_paid": null,
209 | "time_expire": 1587008879,
210 | "time_settle": null,
211 | "transaction_no": null,
212 | "refunds": {
213 | "object": "list",
214 | "url": "/v1/charges/ch_101200415434992752640001/refunds",
215 | "has_more": false,
216 | "data": []
217 | },
218 | "amount_refunded": 0,
219 | "failure_code": null,
220 | "failure_msg": null,
221 | "metadata": {},
222 | "credential": {
223 | "object": "credential",
224 | "ccb_wap": {
225 | "orderinfo": "MERCHANTID=105000056222895&POSID=044507853&BRANCHID=340000000&ORDERID=202002060026&PAYMENT=0.01&CURCODE=01&TXCODE=520100&REMARK1=ch_101200415434992752640001&TIMEOUT=20200416114759&TYPE=1&GATEWAY=UnionPay&THIRDAPPINFO=comccbpay000000000000000ccb&MAC=a4b3dbf79a7b5ca60da2997103ab6ce9"
226 | }
227 | },
228 | "description": null
229 | }`;
230 |
231 | this.pingpp.createPayment(charge, function(result, error){
232 | console.log(result);
233 | console.log(error);
234 | });
235 | },
236 | };
237 |
--------------------------------------------------------------------------------