diff --git a/.gitignore b/.gitignore index f4e3896..c5693ed 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,45 @@ build/ .idea/ bin/ *.iml + +!gradle-wrapper.jar + +# User-specific stuff: +.idea/workspace.xml +.idea/tasks.xml + +# Sensitive or high-churn files: +.idea/dataSources/ +.idea/dataSources.ids +.idea/dataSources.xml +.idea/dataSources.local.xml +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml + +# Gradle: +.idea/gradle.xml +.idea/libraries + +# Mongo Explorer plugin: +.idea/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +gradle.properties +org.eclipse.buildship.core.prefs +org.eclipse.jdt.core.prefs +.project +example/out +.vscode +.classpath +target/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 79a844f..d36bfe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,64 +1,319 @@ +# ChangeLog + +## 2.5.6 + +- 更新: `RequestOptions` 新增`Ping++`验签公钥设置参数 + +## 2.5.5 + +-更新: 退款 refund 新增返回 `app` 参数. + +## 2.5.4 + +- 修正: 修复版本 2.5.3 中存在的 POM 依赖问题。建议用户直接升级到此版本。 + +## 2.5.3 + +- 新增: 签约修改接口 + +## 2.5.2 + +- 修改: 正确 `Map` 以及 `List` 内的元素类型 + +## 2.5.0 + +- 新增: 响应签名验签 +- 新增: 微信扣款预扣费通知实现 +- 更新: `RequestOptions` 新增`Ping++`公钥设置参数 +- 更新: webhook验签方法移动至 `PingppSignature` 类中 +- 更新: `gson` 到`2.10`;`commons-codec` 到 `1.17.0` + +## 2.4.1 + +- 修改: Refund 对象新增`currency` 字段 +- 修改: 更新示例 Main.java 中设置私钥和私钥文件地址写法 +- 修改: build.gradle 镜像仓库使用阿里云源 + +## 2.4.0 + +> 本次更新有较多与旧版本不兼容的地方。 + +- 修改: 支持 JDK 8 及以上; +- 修改: 异常抛出修改,统一声明为 `PingppException`,实际使用可以再做具体判断; +- 废弃: 原接口,支持传 `apiKey` 参数的方法,全部删除,可以用 `RequestOptions` 代替; +- 新增: 每个接口最后一个参数支持 `RequestOptions`; +- 新增: `PingppException` 增加 `type`、`code`、`statusCode`; +- 新增: 对象增加 `getLastResponse()` 方法,可以用于获取当前这次请求的 `response` 对象,包含 `HTTP Status Code`、`Headers`、 + `Response Body` 等; +- 废弃: 取消对 `PKCS1` 格式私钥的支持,请转成 `PKCS8` 再使用; + +--- + +## 2.3.14 + +- 新增:settle_account.recipient extra 字段 +- 新增:Royalty.createData() 方法 + +--- + +## 2.3.13 + +- 新增:结算账户更新接口 + +--- + +## 2.3.12 + +- 新增:证件上传、添加联系人、结算账号更新手机号、结算账号验证打款相关接口 +- 修改:结算账号增加字段 +- 修改:**\*SubApp user 字段类型修改 String -> Object,兼容返回 user 对象而不是 ID 的情况** +- 修改:SubApp 增加 extra 字段 +- 修改:User 增加 identityInfo、extra 等字段 + +--- + +## 2.3.11 + +- 新增:SplitProfit、SplitReceiver、ProfitTransaction、SubBank 相关接口 + +--- + +## 2.3.10 (2019-05-30) + +#### 修改 + +- SettleAccount 添加 `sub_bank_code` 字段 + +## 2.3.9 (2018-08-21) + +#### 修正 + +- 修正 `BalanceSettlement` 错误 + +#### 修改 + +- 移除 `PingppAccount` + +## 2.3.8 (2018-05-22) + +#### 新增 + +- WxLiteOAuth 接口 +- Agreement 接口 + +#### 修改 + +- 合并部分内部类 +- WxpubOAuth 接口错误时增加异常 + +## 2.3.7 (2018-03-16) + +#### 新增 + +- BalanceSettlement 接口 +- CardInfo 接口 + +## 2.3.5 (2018-02-27) + +#### 修正 + +- 部分对象字段从 Integer 改成 Long + +## 2.3.4 (2018-01-10) + +#### 修改 + +- 移除已废弃接口 +- 移除 transfer、batch_transfer 取消接口 +- 更新示例 +- 移除 order user_from 字段 +- settle_account 字段更新 + +## 2.3.3 (2017-12-27) + +#### 修正 + +- 修正 javadoc + +## 2.3.2 (2017-12-21) + +#### 修正 + +- 兼容 JDK 1.7 + +## 2.3.1 (2017-12-08) + +#### 修正 + +- Event 解析修正 + +## 2.3.0 (2017-12-01) + +#### 更改 + +- 合并账户系统相关接口 + +## 2.2.5 (2017-10-10) + +#### 新增 + +- 新增重试机制 + +#### 修改 + +- 优化 SDK + +## 2.2.4 (2017-06-19) + +#### 修改 + +- Charge 增加字段 reversed,表示是否已撤销 +- 针对渠道 isv_scan, isv_qr_isv_wap 增加撤销方法,`Charge.reverse(CHARGE_ID)` +- Refund 增加 extra 字段 + +## 2.2.3 (2017-03-27) + +#### 修改 + +- BatchTransfer 增加字段 + +## 2.2.2 (2017-03-21) + +#### 修正 + +- alipay_pc_direct/alipay_wap 渠道 credential 字段类型的修正 + +## 2.2.1 (2017-01-13) + +#### 新增 + +- 添加 gradle 相关文件 +- 添加部分测试文件 +- batch_transfer 更新/取消接口 + +#### 修改 + +- 更改签名私钥获取方式 +- Charge.list app[id] 参数改为必传 +- 红包去除多余的参数 +- batch_refund charges 字段格式修改 + +#### 修正 + +- Webhooks 解析对象 batch_refund、batch_transfer、customs 对应事件错误 + +## 2.2.0 + +#### 新增 + +- 添加 BatchRefund、BatchTransfer、Customs + +#### 修改 + +- 签名生成规则变更 +- 列表查询接口换成 `list` 方法,代替 `all` 方法 +- 退款接口调用方式变更,直接使用 Refund 对象 +- Refund 对象添加 charge_order_no, transaction_no 属性 + +## 2.1.9 + +#### 修改 + +- 添加 RateLimitException +- 兼容 http 地址,仅为方便测试 + +## 2.1.8 + +#### 新增 + +- Identification 身份证银行卡接口 + ## 2.1.7 -* 修正: -RedEnvelope、Transfer 添加字段 + +#### 修正 + +- RedEnvelope、Transfer 添加字段 ## 2.1.6 -* 修正: -签名内容编码问题 + +#### 修正 + +- 签名内容编码问题 ## 2.1.5 -* 修改: -补充 RedEnvelope、Transfer 缺少字段 + +#### 修改 + +- 补充 RedEnvelope、Transfer 缺少字段 ## 2.1.4 -* 修改: -更改 content-type 为 application/json + +#### 修改 + +- 更改 content-type 为 application/json ## 2.1.3 -* 兼容两种微信公众号接入方式 + +- 兼容两种微信公众号接入方式 ## 2.1.2 -* 补全确实字段 -* 修正 Event 解析 -* 修正部分字符 JSON 序列化问题 -* 添加请求签名 + +- 补全确实字段 +- 修正 Event 解析 +- 修正部分字符 JSON 序列化问题 +- 添加请求签名 ## 2.1.1 -* 修正 extra 类型 -* 兼容 jdk 1.6 + +- 修正 extra 类型 +- 兼容 jdk 1.6 ## 2.1.0 -* 添加应用内快捷支付对应接口 + +- 添加应用内快捷支付对应接口 ## 2.0.10 -* 增加 Refund 对象 status 字段 + +- 增加 Refund 对象 status 字段 ## 2.0.8 -* 增加 ChannelException + +- 增加 ChannelException ## 2.0.6 -* 增加企业转账、修改红包接口 + +- 增加企业转账、修改红包接口 ## 2.0.5 -* 增加 event sdk + +- 增加 event sdk ## 2.0.4 -* 更改 sdk 目录格式,修复wx_pub渠道timeStamp 类型问题。 + +- 更改 sdk 目录格式,修复wx_pub渠道timeStamp 类型问题。 ## 2.0.3 -* 增加 apple pay ,重写 getcredential 方法。 + +- 增加 apple pay ,重写 getcredential 方法。 ## 2.0.2 -* 增加微信红包 + +- 增加微信红包 ## 2.0.1 -* 更改: + +#### 更改 + 修改 wx credential 里的 timeStamp 类型为字符串,防止变成科学计数法 ## 2.0.0 -* 更改: + +#### 更改 + 添加新渠道支持:百付宝、百付宝WAP、微信公众平台 ## 1.0.4 -* 更改: + +#### 更改: + 添加 `Expanding` 机制 diff --git a/README.md b/README.md index 4e1c62f..1a8a82c 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,72 @@ -Ping++ Java SDK -============ +# Ping++ Java SDK + +## 简介 -### 简介 1. [docs](/docs) 目录下为 Ping++ Java SDK 的使用文档。 2. example 目录下面为一个 Eclipse IDE 的示例工程。 3. libs 为 Ping++ Java SDK 的 jar 包和 Ping++ Java SDK 所依赖的Gson 包。 4. src 为 Ping++ Java SDK 的源代码,可以关联到 pingpp-java-x.x.x.jar 文件。或者直接把源代码引入到工程之中。 -### 版本要求 +## 版本要求 + +Java 要求 JDK 8 及以上。 + +## 安装 + +### 手动安装 -Java SDK 要求 JDK 版本 1.7 及以上 +JAR 下载地址: [pingpp-java](https://mvnrepository.com/artifact/com.pingxx/pingpp-java) -### 安装 -##### 手动安装 -将 libs/ 下面的 jar 包导入工程 +请根据版本号下载相应的 JAR 文件并导入至工程。 -##### maven 安装 +#### 依赖库 + +- com.google.code.gson:gson +- commons-codec:commons-codec + +### maven 安装 maven 远程仓库 + ``` xml - - - false - - central - bintray - http://jcenter.bintray.com - +mavenCentral ``` 安装 Ping++ SDK + ``` xml - Pingplusplus + com.pingxx pingpp-java - 2.1.7 + 2.5.6 jar ``` -##### gradle 安装 + +### gradle 安装 gradle 远程仓库 ``` repositories { - maven { - url "http://jcenter.bintray.com" - } + mavenCentral() } ``` 安装 Ping++ SDK + ``` -compile 'Pingplusplus:pingpp-java:2.1.7' +implementation 'com.pingxx:pingpp-java:2.5.6' ``` -### 初始化 +## 初始化 + ``` Pingpp.apiKey = "YOUR_API_KEY"; ``` -### 使用示例 -``` -参考 example/SimpleExample 示例项目工程。改工程提供了付款、退款、微信公共号付款相关的 demo。 -``` +## 使用示例 + +- 参考 [example](/example) 示例项目工程。该工程提供了付款、退款、微信公共号付款相关的 demo。 +- 以及 [test](/src/test/java/com/pingplusplus) 目录下的示例。 +- 原有旧版本的用户请查看[升级文档](/docs/update/)进行相应调整。 diff --git a/VERSION b/VERSION index 04b10b4..1b03fe6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.7 +2.5.6 \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..e7c254d --- /dev/null +++ b/build.gradle @@ -0,0 +1,12 @@ +buildscript { + repositories { + mavenCentral() + } +} + +allprojects { + repositories { + mavenCentral() + } + apply plugin: 'java' +} diff --git "a/docs/ping++_java_sdk_api_\346\226\207\346\241\243.md" b/docs/api-reference.md similarity index 77% rename from "docs/ping++_java_sdk_api_\346\226\207\346\241\243.md" rename to docs/api-reference.md index 59924fa..ddbb18e 100644 --- "a/docs/ping++_java_sdk_api_\346\226\207\346\241\243.md" +++ b/docs/api-reference.md @@ -5,6 +5,8 @@ - Refund - RedEnvelope - Webhooks +- Identification +- 账户系统相关接口请查看 [Ping++ API 文档](https://www.pingxx.com/api) 或参考[测试示例](/src/test/java/com/pingplusplus) #### Charge ##### 创建 Charge @@ -47,9 +49,9 @@ Charge charge = Charge.retrieve(CHARGE_ID); ##### 查询 Charge 列表 ``` java -all(Map params) +list(Map params) ``` -方法名:all +方法名:list 类型:静态方法 参数:Map 返回:ChargeCollection @@ -60,10 +62,23 @@ app.put("id", APP_ID); chargeParams.put("app", app); chargeParams.put("limit", 3); Map app = new HashMap(); -ChargeCollection charges = Charge.all(chargeParams); +ChargeCollection charges = Charge.list(chargeParams); System.out.println(charges); ``` +##### 撤销 Charge +``` java +reverse(String id) +``` +方法名:reverse +类型:静态方法 +参数:String 类型的 Charge ID +返回:Charge +示例: +``` java +Charge charge = Charge.reverse(CHARGE_ID); +``` + #### Refund ##### 创建 Refund ``` java @@ -97,9 +112,9 @@ Refund re = ch.getRefunds().retrieve(REFUND_ID); ##### 查询 Refund 列表 ``` java -all(Map params) +list(Map params) ``` -方法名:all +方法名:list 类型:实例方法 参数:Map 返回:RefundCollection @@ -108,7 +123,7 @@ all(Map params) Charge ch = Charge.retrieve(CHARGE_ID); Map refundParams = new HashMap(); refundParams.put("limit", 3); -Refund re = ch.getRefunds().all(refundParams); +Refund re = ch.getRefunds().list(refundParams); ``` #### RedEnvelope @@ -156,9 +171,9 @@ RedEnvelope redEnvelope = RedEnvelope.retrieve(RED_ID); ##### 查询 RedEnvelope 列表 ``` java -all(Map params) +list(Map params) ``` -方法名:all +方法名:list 类型:静态方法 参数:Map 返回:RedEnvelopeCollection @@ -167,7 +182,7 @@ all(Map params) RedEnvelopeCollection redEnvelopeCollection = null; Map chargeParams = new HashMap(); chargeParams.put("limit", 3); -RedEnvelopeCollection redEnvelopeCollection = RedEnvelope.all(chargeParams); +RedEnvelopeCollection redEnvelopeCollection = RedEnvelope.list(chargeParams); ``` #### Webhooks @@ -205,3 +220,27 @@ eventParse(String eventStr) ``` java Event eventobj = Webhooks.eventParse(eventString); ``` + +#### Identification +##### 身份证银行卡信息认证接口 +``` java +identify(Map params) +``` +方法名:identify +类型:静态方法 +参数:Map +返回:Identification 结果 +示例: +``` java +Map params = new HashMap(); +params.put("app", APP_ID); +params.put("type", "bank_card"); +Map data = new HashMap(); +data.put("id_name", "张三"); +data.put("id_number", "320291198811110000"); +data.put("card_number", "6201111122223333"); +params.put("data", data); +Identification result = Identification.identify(params); +System.out.println(result.getResultCode()); +System.out.println(result.getMessage()); +``` diff --git a/docs/guides.md b/docs/guides.md new file mode 100644 index 0000000..6ad8646 --- /dev/null +++ b/docs/guides.md @@ -0,0 +1,90 @@ +# Ping++ Java SDK 使用文档 + +#### apiKey 和 appId +SDK 需要 Ping++ 提供的 apiKey 和 AppID 作为凭证获取移动端支付所需的 Charge 对象。 +其中,apiKey 可以在 Ping++ 管理平台的【企业设置】->【开发设置】中得到。 +AppID 可以在 Ping++ 管理平台应用卡片下方得到。 + +#### 依赖 +- gons-2.6.2 +- commons-codec-1.10 + +#### 设置 apiKey +``` java +Pingpp.apiKey = "YOUR-KEY"; +``` +在创建 Charge 前,请设置 apiKey。 + +#### 设置请求签名密钥 +密钥需要你自己生成,公钥请填写到 [Ping++ Dashboard](https://dashboard.pingxx.com)。 +建议使用 PKCS\#8 编码的私钥文件。openssl 命令如下: +```shell +openssl pkcs8 -topk8 -inform PEM -in pkcs1.pem -outform PEM -nocrypt -out pkcs8.pem +``` + +设置你的私钥 +```java +Pingpp.privateKey = ""; +``` + +#### 设置 App ID +当你使用账户系统的接口时,需要设置 App ID。比如,充值(recharge)、提现(withdrawal)等。 +```java +Pingpp.appId = ""; +``` + +#### 创建 Charge +```java +Map chargeMap = new HashMap(); +// 某些渠道需要添加extra参数,具体参数详见接口文档 +chargeMap.put("amount", 100); +chargeMap.put("currency", "cny"); +chargeMap.put("subject", "Your Subject"); +chargeMap.put("body", "Your Body"); +chargeMap.put("order_no", "123456789"); +chargeMap.put("channel", "alipay"); +chargeMap.put("client_ip", "127.0.0.1"); +Map app = new HashMap(); +app.put("id", "YOUR_APP_ID"); +chargeMap.put("app", app); +try { + //发起交易请求 + Charge charge = Charge.create(chargeMap); + System.out.println(charge.toString()); +} catch (PingppException e) { + e.printStackTrace(); +} +``` + +##### 备注 + + 获得 Charge 对象,必须的参数有 amount、currency、subject、body、order_no、channel、client_ip、app 这 8 个参数。 + 其中 amount、order_no、channel 三个参数由客户端的 post 请求中获得。 + client_ip 从客户端的 request 请求中解析。 + currency 为交易的货币代码,目前仅支持人民币 cny。 + app 参数为一个包含 appId 的 map 对象。 + subject 和 body 参数用来在用户付款、以及在第三方支付软件的账单显示。 + +#### 返回 Charge +请用 JSON 格式把 Charge 对象返回给客户端。 + +##### servlet 返回 Charge 时注意配置 +```java +response.setContentType("application/json;charset=UTF-8"); +``` + +##### struct2 获得 POST 请求参数,建议使用 struct2-json-pligun.jar。返回的 result 的 type 设置为 json +struct2.xml 配置如下: +```xml + + + + + charge + + + +``` + +#### 补充 +SDK 根目录下面的 example 目录下提供了一个 gradle 工程,里面含有部分操作的示例程序,供开发者参考。 diff --git "a/docs/ping++_java_sdk_\344\275\277\347\224\250\346\226\207\346\241\243.md" "b/docs/ping++_java_sdk_\344\275\277\347\224\250\346\226\207\346\241\243.md" deleted file mode 100644 index 49f55f8..0000000 --- "a/docs/ping++_java_sdk_\344\275\277\347\224\250\346\226\207\346\241\243.md" +++ /dev/null @@ -1,101 +0,0 @@ -### Ping++ Java SDK 使用文档 - -- 接入准备 - -##### apiKey 和 appId - - SDK 需要 Ping++ 提供的 APIKey 和 AppId 作为凭证获取移动端支付所需的 charge 对象。 - 其中,APIKey 可以在 Ping++ 管理平台的【基本信息】中得到。 - AppId 可以在 Ping++ 管理平台【应用名称】->【应用信息】中得得到。 - - -#### 依赖包 - - gons-2.2.4.jar 或更高版本 - pingpp-java-2.0.1.jar 或更高版本 - -#### 设置 apiKey - - Pingpp.apiKey = "YOUR-KEY"; - - 在获得 charge 前,请设置 aipKey。 - -#### 设置请求签名密钥 -密钥需要你自己生成,公钥请填写到 [Ping++ Dashboard](https://dashboard.pingxx.com) - - 设置你的私钥路径 - Pingpp.privateKeyPath = "/path/to/your_rsa_private_key.pem"; - -#### 接受请求 - - 客户端会向服务端发送一个带有 json 对象的 post 请求,用来请求 charge 对象。 - json 对象格式如下: - { - "amount": 10, - "order_no": "1234567890", - "channel": "alipay" - } - -##### 备注 - - amount :int 类型,表示支付的金额,以分为单位。 - order_no :String 类型,表示订单号,由字母和数字组成8-20位。 - channel :String 类型,表示支付渠道。 - - 以上字段详细说明可以参考 Ping++ 【文档】-> 【api文档】-> 【创建charge】。 - -##### 获得 charge - - Map chargeMap = new HashMap(); - //某些渠道需要添加extra参数,具体参数详见接口文档 - chargeMap.put("amount", 100); - chargeMap.put("currency", "cny"); - chargeMap.put("subject", "Your Subject"); - chargeMap.put("body", "Your Body"); - chargeMap.put("order_no", "123456789"); - chargeMap.put("channel", "alipay"); - chargeMap.put("client_ip", "127.0.0.1"); - Map app = new HashMap(); - app.put("id", "YOUR-APP-ID"); - chargeMap.put("app", app); - try { - //发起交易请求 - Charge charge = Charge.create(chargeMap); - System.out.println(charge); - } catch (PingppException e) { - e.printStackTrace(); - } - -##### 备注 - - 获得 charge 对象,必须的参数有 amount、currency、subject、body、order_no、channel、client_ip、app 这 8 个参数。 - 其中 amount、order_no、channel 三个参数由客户端的 post 请求中获得。 - client_ip 从客户端的 request 请求中解析。 - currency 为交易的货币代码,目前仅支持人民币 cny。 - app 参数为一个包含 appId 的 map 对象。 - subject 和 body 参数用来在用户付款、以及在第三方支付软件的账单显示。 - -#### 返回 charge - - 请用 Json 格式把 charge 对象返回给客户端。 - -###### servlet 返回 charge 时注意配置 - - response.setContentType("application/json;charset=UTF-8"); - -##### struct2 获得 post 请求参数,建议使用 struct2-json-pligun.jar 。返回的 result 的 type 设置为 json - - struct2.xml 配置如下: - - - - - charge - - - - -#### 补充 - - SDK 根目录下面的 example 目录下提供了一个 eclipse 工程,里面含有部分操作的示例程序,供开发者参考 - diff --git a/docs/readme.md b/docs/readme.md new file mode 100644 index 0000000..6a89c00 --- /dev/null +++ b/docs/readme.md @@ -0,0 +1,5 @@ +# 文档 + +## 索引 +- [Ping++ Java SDK 使用文档](guides.md) +- [Ping++ Java SDK API 文档](api-reference.md) diff --git a/docs/update/2.3-to-2.4.md b/docs/update/2.3-to-2.4.md new file mode 100644 index 0000000..f8a39b8 --- /dev/null +++ b/docs/update/2.3-to-2.4.md @@ -0,0 +1,208 @@ +# Upgrading to 2.4.* from 2.3.* + +## Guidelines + +### 1. RequestOptions + +每个独立的请求可以使用特定的 API Key、App ID、私钥等配置。 + +#### 使用方法 + +初始化 `RequestOptions` + +```java +RequestOptions options = new RequestOptionsBuilder() + .setApiKey("sk_test_ibbTe5jLGCi5rzfH4OqPW9KC") + .setAppId("app_1Gqj58ynP0mHeX1q") + .setPrivateKey("-----BEGIN PRIVATE KEY-----\n......\n-----END PRIVATE KEY-----") + .setConnectTimeout(5000) + .setReadTimeout(20000) + .setAcceptLanguage("zh-CN") + .setMaxNetworkRetries(2) + .build(); +``` + +使用 `RequestOptions` + +```java +Map params = new HashMap(); +// 填充 params... +Order order = Order.create(params, options); +``` + +```java +User user = User.retrieve("USER_ID", options); +``` + +具体使用示例参考 [RequestOptionsTest.java](/src/test/java/com/pingplusplus/RequestOptionsTest.java) + +### 2. API Key in method + +原有方法中传 `API Key` 的方式都已经废弃,不能使用,请使用 `RequestOptions` 的方式。 + +涉及到以下方法: + +```java +Agreement.create(Map params, String apiKey) +Agreement.retrieve(String id, String apiKey) +Agreement.list(Map params, String apiKey) +Agreement.cancel(String id, String apiKey) + +BatchRefund.create(String apiKey, Mapparams) +BatchRefund.retrieve(String id, String apiKey) +BatchRefund.list(String apiKey, Map params) + +BatchTransfer.create(String apiKey, Mapparams) +BatchTransfer.retrieve(String id, String apiKey) +BatchTransfer.list(String apiKey, Map params) +BatchTransfer.update(String id, String apiKey, Map params) + +CardInfo.query(Map params, String apiKey) + +Charge.create(String apiKey, Map params) +Charge.retrieve(String id, String apiKey) +Charge.retrieve(String id, String apiKey, Map params) +Charge.list(String apiKey, Map params) +Charge.reverse(String id, String apiKey, Map params) +Charge.reverse(String id, String apiKey) + +charge.refunds.list(String apiKey, Map params) +charge.refunds.retrieve(String id, String apiKey) +charge.refunds.create(String apiKey, Map params) + +Contact.create(Map params, String apiKey) + +Customs.create(String apiKey, Map params) +Customs.retrieve(String id, String apiKey) +Customs.list(String apiKey, Map params) + +Event.retrieve(String id, String apiKey) +Event.retrieve(String id, String apiKey, Map params) + +Identification.identify(String apiKey, Map params) + +ProfitTransaction.retrieve(String id, String apiKey) +ProfitTransaction.list(Map params, String apiKey) + +RedEnvelope.create(String apiKey, Map params) +RedEnvelope.retrieve(String id, String apiKey) +RedEnvelope.retrieve(String id, String apiKey, Map params) +RedEnvelope.list(String apiKey, Map params) + +Refund.create(String charge, String apiKey, Map params) +Refund.retrieve(String charge, String id, String apiKey) +Refund.list(String charge, String apiKey, Mapparams) + +Royalty.createData(String orderId, Map params, String apiKey) + +SplitProfit.create(Map params, String apiKey) +SplitProfit.retrieve(String id, String apiKey) +SplitProfit.list(Map params, String apiKey) +SplitReceiver.create(Map params, String apiKey) +SplitReceiver.retrieve(String id, String apiKey) +SplitReceiver.list(Map params, String apiKey) +SplitReceiver.delete(String id, String apiKey) + +SubBank.query(Map params, String apiKey) + +Transfer.create(String apiKey, Map params) +Transfer.retrieve(String id, String apiKey) +Transfer.retrieve(String id, String apiKey, Map params) +Transfer.list(String apiKey, Map params) + +UserPic.upload(Map params, String apiKey) +``` + +#### 替换示例 + +##### 示例 1 + +```java +String apiKey = "YOUR_API_KEY"; +Agreement.create(params, apiKey); + +// 替换成 + +String apiKey = "YOUR_API_KEY"; +RequestOptions options = new RequestOptionsBuilder().setApiKey(apiKey).build(); +Agreement.create(params, options); +``` + +##### 示例 2 + +```java +String apiKey = "YOUR_API_KEY"; +Charge.create(apiKey, params) + +// 替换成 + +String apiKey = "YOUR_API_KEY"; +RequestOptions options = new RequestOptionsBuilder().setApiKey(apiKey).build(); +Charge.create(params, options); +``` + +### 3. Exceptions + +```java +try { + Charge.create(params); +} catch (AuthenticationException e) { +} catch (InvalidRequestException e) { +} catch (APIConnectionException e) { +} catch (APIException e) { +} catch (ChannelException e) { +} catch (RateLimitException e) { +} +``` + +改成 + +```java +try { + Charge.create(params); +} catch (PingppException e) { + // 如果要具体分是哪个 exception + if (e instanceof InvalidRequestException) { + InvalidRequestException ex = (InvalidRequestException) e; + // 获取 error.code 字段(部分报错有) + System.out.println(ex.getCode()); + // 获取请求的 HTTP Status Code + System.out.println(ex.getStatusCode()); + // 获取 error.type 字段 + System.out.println(ex.getType)); + } + // ... +} +``` + +### 4. Accept-Language + +`Pingpp.AcceptLanguage` 改为 `Pingpp.acceptLanguage`。 + +### 5. Private Key + +废弃 `PKCS#1` 编码的私钥支持。 + +请使用 `PKCS#8` 编码的私钥。openssl 转换命令如下: + +```shell +openssl pkcs8 -topk8 -inform PEM -in pkcs1.pem -outform PEM -nocrypt -out pkcs8.pem +``` + +### 6. getLastResponse + +可以获取当前请求的 `response` 对象。 + +```java +Charge charge = Charge.create(params); +PingppResponse response = charge.getLastResponse(); + +// 获取响应的 HTTP Status Code +int statusCode = response.getResponseCode(); + +// 获取响应的 Headers +HttpHeaders headers = response.getResponseHeaders(); + +// 获取响应体 +String responseBody = response.getResponseBody() +``` diff --git a/example/.classpath b/example/.classpath new file mode 100644 index 0000000..0b72ca4 --- /dev/null +++ b/example/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/example/SimpleExample/.classpath b/example/SimpleExample/.classpath deleted file mode 100644 index c576d7e..0000000 --- a/example/SimpleExample/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/example/SimpleExample/.project b/example/SimpleExample/.project deleted file mode 100644 index a18ea41..0000000 --- a/example/SimpleExample/.project +++ /dev/null @@ -1,17 +0,0 @@ - - - SimpleExample - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - diff --git a/example/SimpleExample/.settings/org.eclipse.jdt.core.prefs b/example/SimpleExample/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 7341ab1..0000000 --- a/example/SimpleExample/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,11 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.7 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.7 diff --git a/example/SimpleExample/bin/sign b/example/SimpleExample/bin/sign deleted file mode 100644 index e990ae3..0000000 --- a/example/SimpleExample/bin/sign +++ /dev/null @@ -1 +0,0 @@ -PcU0SMJhbPObiIVinNnalZOjI02koWozxLrxa3WQW3rK/n7I+EuVGuXvhsq2MIfUaNiHZDgRFYybGtKr1uuFzEXjA4PwmnDHfWgwRPdjgseoU0eke6ZqGpklBRVTbF6PUy6/vAqur4xb7h1wpdrteUpCPafzDmVPsQLicdojJ/TF9ACjQW8gTNiS6tE9gL5hxy0RJ3/okRJo6dz2pvJBWkjCrgp/r98z/LQijA1o//atZrH63+DcL/GwEOgaymqbodzusXF+g6WMJ/GTJgjdPRHvpO9UAAUKkOQqvwthJvsXIH/L1xqvy+tFpo2J0Ptwg85bowKoyy1qC5ak3sqWqw== \ No newline at end of file diff --git a/example/SimpleExample/libs/commons-codec-1.10.jar b/example/SimpleExample/libs/commons-codec-1.10.jar deleted file mode 100644 index 1d7417c..0000000 Binary files a/example/SimpleExample/libs/commons-codec-1.10.jar and /dev/null differ diff --git a/example/SimpleExample/libs/gson-2.6.2.jar b/example/SimpleExample/libs/gson-2.6.2.jar deleted file mode 100644 index 9d78626..0000000 Binary files a/example/SimpleExample/libs/gson-2.6.2.jar and /dev/null differ diff --git a/example/SimpleExample/libs/pingpp-java-2.1.7.jar b/example/SimpleExample/libs/pingpp-java-2.1.7.jar deleted file mode 100644 index 1438238..0000000 Binary files a/example/SimpleExample/libs/pingpp-java-2.1.7.jar and /dev/null differ diff --git a/example/SimpleExample/res/pingpp_public_key.pem b/example/SimpleExample/res/pingpp_public_key.pem deleted file mode 100644 index 7cf6d7c..0000000 --- a/example/SimpleExample/res/pingpp_public_key.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzs8SiPoFQT9K0lWa6WSx -0d6UnA391KM2aFwijY0AK7r+MiAe07ivenopzFL3dqIRhQjuP7d30V85kWydN5UZ -cm/tZgm4K+8wttb988hOrzSjtPOMghHK+bnDwE8FIB+ZbHAZCEVhNfE6i9kLGbHH -Q617+mxUTJ3yEZG9CIgke475o2Blxy4UMsRYjo2gl5aanzmOmoZcbiC/R5hXSQUH -XV9/VzA7U//DIm8Xn7rerd1n8+KWCg4hrIIu/A0FKm8zyS4QwAwQO2wdzGB0h15t -uFLhjVz1W5ZPXjmCRLzTUoAvH12C6YFStvS5kjPcA66P1nSKk5o3koSxOumOs0iC -EQIDAQAB ------END PUBLIC KEY----- diff --git a/example/SimpleExample/src/main/java/com/pingxx/example/ChargeExample.java b/example/SimpleExample/src/main/java/com/pingxx/example/ChargeExample.java deleted file mode 100644 index b3a3a85..0000000 --- a/example/SimpleExample/src/main/java/com/pingxx/example/ChargeExample.java +++ /dev/null @@ -1,185 +0,0 @@ -/** - * Ping++ Server SDK - * 说明: - * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。 - * 接入支付流程参考开发者中心:https://www.pingxx.com/docs/server/charge ,文档可筛选后端语言和接入渠道。 - * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。 - */ -package com.pingxx.example; - -import java.util.*; - -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; -import com.pingplusplus.exception.PingppException; -import com.pingplusplus.model.Charge; -import com.pingplusplus.model.ChargeCollection; - -/** - * Charge 对象相关示例 - * - * 该实例程序演示了如何从 Ping++ 服务器获得 charge ,查询 charge。 - * - * 开发者需要填写 apiKey 和 appId , - * - * apiKey 有 TestKey 和 LiveKey 两种。 - * - * TestKey 模式下不会产生真实的交易。 - */ -public class ChargeExample { - - private String appId; - - ChargeExample(String appId) { - this.appId = appId; - } - - public static void runDemos(String appId) { - - ChargeExample chargeExample = new ChargeExample(appId); - System.out.println("------- 创建 charge -------"); - Charge charge = chargeExample.createCharge(); - System.out.println("------- 查询 charge -------"); - chargeExample.retrieve(charge.getId()); - System.out.println("------- 查询 charge 列表 -------"); - chargeExample.all(); - } - - /** - * 创建 Charge - * - * 创建 Charge 用户需要组装一个 map 对象作为参数传递给 Charge.create(); - * map 里面参数的具体说明请参考:https://pingxx.com/document/api#api-c-new - * @return Charge - */ - public Charge createCharge() { - Charge charge = null; - Map chargeMap = new HashMap(); - chargeMap.put("amount", 100);//订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100) - chargeMap.put("currency", "cny"); - chargeMap.put("subject", "Your Subject"); - chargeMap.put("body", "Your Body"); - String orderNo = new Date().getTime() + Main.randomString(7); - chargeMap.put("order_no", orderNo);// 推荐使用 8-20 位,要求数字或字母,不允许其他字符 - chargeMap.put("channel", "alipay");// 支付使用的第三方支付渠道取值,请参考:https://www.pingxx.com/api#api-c-new - chargeMap.put("client_ip", "127.0.0.1"); // 发起支付请求客户端的 IP 地址,格式为 IPV4,如: 127.0.0.1 - Map app = new HashMap(); - app.put("id", appId); - chargeMap.put("app", app); - - Map extra = new HashMap(); -// extra.put("open_id", "USER_OPENID"); - chargeMap.put("extra", extra); - try { - //发起交易请求 - charge = Charge.create(chargeMap); - // 传到客户端请先转成字符串 .toString(), 调该方法,会自动转成正确的 JSON 字符串 - String chargeString = charge.toString(); - System.out.println(chargeString); - } catch (PingppException e) { - e.printStackTrace(); - } - return charge; - } - - /** - * 创建 Charge (微信公众号) - * - * 创建 Charge 用户需要组装一个 map 对象作为参数传递给 Charge.create(); - * map 里面参数的具体说明请参考:https://pingxx.com/document/api#api-c-new - * @return Charge - */ - public Charge createChargeWithOpenid(String openid) { - Charge charge = null; - Map chargeMap = new HashMap(); - chargeMap.put("amount", 100);//订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100) - chargeMap.put("currency", "cny"); - chargeMap.put("subject", "Your Subject"); - chargeMap.put("body", "Your Body"); - String orderNo = new Date().getTime() + Main.randomString(7); - chargeMap.put("order_no", orderNo);// 推荐使用 8-20 位,要求数字或字母,不允许其他字符 - chargeMap.put("channel", "wx_pub");// 支付使用的第三方支付渠道取值,请参考:https://www.pingxx.com/api#api-c-new - chargeMap.put("client_ip", "127.0.0.1"); // 发起支付请求客户端的 IP 地址,格式为 IPV4,如: 127.0.0.1 - Map app = new HashMap(); - app.put("id", appId); - chargeMap.put("app", app); - - Map extra = new HashMap(); - extra.put("open_id", openid);// 用户在商户微信公众号下的唯一标识,获取方式可参考 WxPubOAuthExample.java - chargeMap.put("extra", extra); - try { - //发起交易请求 - charge = Charge.create(chargeMap); - // 传到客户端请先转成字符串 .toString(), 调该方法,会自动转成正确的 JSON 字符串 - String chargeString = charge.toString(); - System.out.println(chargeString); - } catch (PingppException e) { - e.printStackTrace(); - } - return charge; - } - - /** - * 查询 Charge - * - * 该接口根据 charge Id 查询对应的 charge 。 - * 参考文档:https://pingxx.com/document/api#api-c-inquiry - * - * 该接口可以传递一个 expand , 返回的 charge 中的 app 会变成 app 对象。 - * 参考文档: https://pingxx.com/document/api#api-expanding - * @param id - */ - public Charge retrieve(String id) { - Charge charge = null; - try { - Map params = new HashMap(); -// List expand = new ArrayList(); -// expand.add("app"); -// params.put("expand", expand); - charge = Charge.retrieve(id, params); - System.out.println(charge); - } catch (PingppException e) { - e.printStackTrace(); - } - - return charge; - } - - /** - * 分页查询 Charge - * - * 该接口为批量查询接口,默认一次查询10条。 - * 用户可以通过添加 limit 参数自行设置查询数目,最多一次不能超过 100 条。 - * - * 该接口同样可以使用 expand 参数。 - * @return chargeCollection - */ - public ChargeCollection all() { - ChargeCollection chargeCollection = null; - Map params = new HashMap(); - params.put("limit", 3); - Map app = new HashMap(); - app.put("id", appId); - params.put("app", app); - - try { - chargeCollection = Charge.all(params); - System.out.println(chargeCollection); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } - - return chargeCollection; - } -} diff --git a/example/SimpleExample/src/main/java/com/pingxx/example/EventExample.java b/example/SimpleExample/src/main/java/com/pingxx/example/EventExample.java deleted file mode 100644 index b8ece5d..0000000 --- a/example/SimpleExample/src/main/java/com/pingxx/example/EventExample.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.pingxx.example; - -import java.util.HashMap; -import java.util.Map; - -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; -import com.pingplusplus.model.Charge; -import com.pingplusplus.model.Event; -import com.pingplusplus.model.EventCollection; -import com.pingplusplus.model.Refund; -import com.pingplusplus.model.Summary; -import com.pingplusplus.model.Webhooks; - - -/** - * - * Event 事件参考文档:https://pingxx.com/document/api#api-event - * - * 该实例演示如何查询 Event - * - * apiKey 有 TestKey 和 LiveKey 两种。 - * - * TestKey 模式下不会产生真实的交易。 - * - */ -public class EventExample { - - public static void runDemos() { - EventExample eventExample = new EventExample(); - System.out.println("------- 查询 event -------"); - - String eventId = "evt_vTmGHwcHc842hWLRWNS4bwFM"; - eventExample.retrieve(eventId); - System.out.println("------- 查询 event 列表 -------"); - eventExample.all(); - } - - /** - * 根据 ID 查询 Evnet - * - * 传递 Event 的 Id 查询 Event。 - * 参考文档:https://pingxx.com/document/api#api-event-inquiry - * @param id - */ - public void retrieve(String id) { - try { - Event event = Event.retrieve(id); - System.out.println(event); - - // 解析 webhooks 可以采用如下方法 -// Object obj = Webhooks.getObject(event.toString()); -// if (obj instanceof Charge) { -// System.out.println("webhooks 发送了 Charge"); -// } else if (obj instanceof Refund) { -// System.out.println("webhooks 发送了 Refund"); -// } else if (obj instanceof Summary) { -// System.out.println("webhooks 发送了 Summary"); -// } - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } - - } - - /** - * 批量查询 - * - * 该接口为批量查询接口,默认一次查询10条。 - * 用户可以通过添加 limit 参数自行设置查询数目,最多一次不能超过 100 条。 - * - */ - public void all() { - Map params = new HashMap(); - params.put("limit", 3); -// params.put("type", "charge.succeeded"); -// params.put("type", "refund.succeeded"); -// ... - try { - EventCollection eventCollection = Event.all(params); - System.out.println(eventCollection); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } - } - -} diff --git a/example/SimpleExample/src/main/java/com/pingxx/example/Main.java b/example/SimpleExample/src/main/java/com/pingxx/example/Main.java deleted file mode 100644 index ccdd45a..0000000 --- a/example/SimpleExample/src/main/java/com/pingxx/example/Main.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.pingxx.example; - -import com.pingplusplus.Pingpp; - -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; -import java.security.SecureRandom; - -/** - * Created by Afon on 16/4/26. - */ -public class Main { - - /** - * Pingpp 管理平台对应的 API Key,api_key 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击管理平台右上角公司名称->开发信息-> Secret Key - */ - private final static String apiKey = "sk_test_ibbTe5jLGCi5rzfH4OqPW9KC"; - - /** - * Pingpp 管理平台对应的应用 ID,app_id 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击你创建的应用->应用首页->应用 ID(App ID) - */ - private final static String appId = "app_1Gqj58ynP0mHeX1q"; - - /** - * 设置请求签名密钥,密钥对需要你自己用 openssl 工具生成,如何生成可以参考帮助中心:https://help.pingxx.com/article/123161; - * 生成密钥后,需要在代码中设置请求签名的私钥(rsa_private_key.pem); - * 然后登录 [Dashboard](https://dashboard.pingxx.com)->点击右上角公司名称->开发信息->商户公钥(用于商户身份验证) - * 将你的公钥复制粘贴进去并且保存->先启用 Test 模式进行测试->测试通过后启用 Live 模式 - */ - - // 你生成的私钥路径 - private final static String privateKeyFilePath = "res/your_rsa_private_key.pem"; - - public static void main(String[] args) throws Exception { - - // 设置 API Key - Pingpp.apiKey = apiKey; - - // 设置私钥路径,用于请求签名 - Pingpp.privateKeyPath = privateKeyFilePath; - - /** - * 或者直接设置私钥内容 - Pingpp.privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" + - "... 私钥内容字符串 ...\n" + - "-----END RSA PRIVATE KEY-----\n"; - */ - - // Charge 示例 - ChargeExample.runDemos(appId); - - // Refund 示例 - RefundExample.runDemos(); - - // RedEnvelope 示例 - RedEnvelopeExample.runDemos(appId); - - // Transfer 示例 - TransferExample.runDemos(appId); - - // Event 示例 - EventExample.runDemos(); - - // Webhooks 验证示例 - WebhooksVerifyExample.runDemos(); - - // 微信公众号 openid 相关示例 - WxPubOAuthExample.runDemos(appId); - } - - private static SecureRandom random = new SecureRandom(); - - public static String randomString(int length) { - String str = new BigInteger(130, random).toString(32); - return str.substring(0, length); - } -} diff --git a/example/SimpleExample/src/main/java/com/pingxx/example/RedEnvelopeExample.java b/example/SimpleExample/src/main/java/com/pingxx/example/RedEnvelopeExample.java deleted file mode 100644 index 71c86b9..0000000 --- a/example/SimpleExample/src/main/java/com/pingxx/example/RedEnvelopeExample.java +++ /dev/null @@ -1,151 +0,0 @@ -/* * - * Ping++ Server SDK - * 说明: - * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。 - * 接入红包流程参考开发者中心:https://www.pingxx.com/docs/server/red-envelope ,文档可筛选后端语言和接入渠道。 - * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。 -*/ -package com.pingxx.example; - -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; -import com.pingplusplus.model.RedEnvelope; -import com.pingplusplus.model.RedEnvelopeCollection; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -/** - * - * 该实例演示如何操作微信红包 - * - * 开发者需要填写 apiKey 、appId 和 openid , - * - * apiKey 有 TestKey 和 LiveKey 两种。 - * - * TestKey 模式下不会产生真实的交易。 - * - * openid 是发送红包的对象在公共平台下的 openid ,获得 openid 的方法可以参考微信文档:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html - * - */ -public class RedEnvelopeExample { - - private String appId; - /** - * 微信用户在微信公共号的 openid - */ - public static String openid = "USER_OPENID";// 用户在商户微信公众号下的唯一标识,获取方式可参考 WxPubOAuthExample.java - - RedEnvelopeExample(String appId) { - this.appId = appId; - } - - public static void runDemos(String appId) { - - RedEnvelopeExample redEnvelopeExample = new RedEnvelopeExample(appId); - System.out.println("------- 创建 RedEnvelope -------"); - RedEnvelope redEnvelope = redEnvelopeExample.create(); - System.out.println("------- 查询 RedEnvelope -------"); - redEnvelopeExample.retrieve(redEnvelope.getId()); - System.out.println("------- 查询 RedEnvelope 列表 -------"); - redEnvelopeExample.all(); - } - - /** - * 创建红包 - * - * 创建红包需要传递一个 map 到 RedEnvelope.create(redenvelope) - * map 里面的具体参数参考:https://pingxx.com/document/api#api-e-new - * @return - */ - public RedEnvelope create() { - Map redenvelope = new HashMap(); - redenvelope.put("amount", 100);// 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100,金额限制在 100 ~ 20000 之间,即 1 ~ 200 元) - redenvelope.put("currency", "cny"); - redenvelope.put("subject", "Your Subject"); - redenvelope.put("body", "Your Body"); - String orderNo = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date()); - redenvelope.put("order_no", orderNo);// 红包使用的商户订单号。wx(新渠道)、wx_pub 规定为 1 ~ 28 位不能重复的数字 - redenvelope.put("channel", "wx_pub");// 目前支持 wx(新渠道)、 wx_pub - redenvelope.put("recipient", openid);// 接收者 id, 为用户在 wx(新渠道)、wx_pub 下的 open_id - redenvelope.put("description", "Your Description"); - Map app = new HashMap(); - app.put("id", appId); - redenvelope.put("app", app); - Map extra = new HashMap(); - extra.put("send_name", "Send Name");// 商户名称,最多 32 个字节 - redenvelope.put("extra", extra); - RedEnvelope red = null; - try { - red = RedEnvelope.create(redenvelope); - System.out.println(red); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } - return red; - - } - - /** - * 查询红包 - * - * 根据红包的 ID 查询红包。 - * 参考文档:https://pingxx.com/document/api#api-e-inquiry - * @param id - */ - public void retrieve(String id) { - try { - RedEnvelope redEnvelope = RedEnvelope.retrieve(id); - System.out.println(redEnvelope); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } - } - - /** - * 批量查询红包 - * - * 批量查询接口,默认一次查询 10 条。用户可以通过 limit 自定义查询数目,最多不超过 100 条。 - */ - public void all() { - RedEnvelopeCollection redEnvelopeCollection = null; - Map chargeParams = new HashMap(); - chargeParams.put("limit", 3); - try { - redEnvelopeCollection = RedEnvelope.all(chargeParams); - System.out.println(redEnvelopeCollection); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } - - } -} diff --git a/example/SimpleExample/src/main/java/com/pingxx/example/TransferExample.java b/example/SimpleExample/src/main/java/com/pingxx/example/TransferExample.java deleted file mode 100644 index f0bf165..0000000 --- a/example/SimpleExample/src/main/java/com/pingxx/example/TransferExample.java +++ /dev/null @@ -1,151 +0,0 @@ -/* * - * Ping++ Server SDK - * 说明: - * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。 - * 接入企业付款流程参考开发者中心:https://www.pingxx.com/docs/server/transfer ,文档可筛选后端语言和接入渠道。 - * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。 -*/ -package com.pingxx.example; - -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; -import com.pingplusplus.model.Transfer; -import com.pingplusplus.model.TransferCollection; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -/** - * - * 该实例演示如何使用 Ping++ 进行企业转账。 - * - * 开发者需要填写 apiKey ,openid 和 appId , - * - * apiKey 有 TestKey 和 LiveKey 两种。 - * - * TestKey 模式下不会产生真实的交易。 - * - * openid 是发送红包的对象在公共平台下的 openid ,获得 openid 的方法可以参考微信文档:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html - * - */ -public class TransferExample { - - private String appId; - - /** - * 接收者的 openid - */ - public static String openid ="USER_OPENID";// 用户在商户微信公众号下的唯一标识,获取方式可参考 WxPubOAuthExample.java - - public static void runDemos(String appId) { - - TransferExample transferExample = new TransferExample(appId); - System.out.println("------- 创建 Transfer -------"); - Transfer transfer = transferExample.transfer(); - System.out.println("------- 查询 Transfer -------"); - transferExample.retrieve(transfer.getId()); - System.out.println("------- 查询 Transfer 列表 -------"); - transferExample.all(); - - } - - TransferExample(String appId) { - this.appId = appId; - } - - /** - * 创建企业转账 - * - * 创建企业转账需要传递一个 map 给 Transfer.create(); - * map 填写的具体介绍可以参考:https://pingxx.com/document/api#api-t-new - * - * @return - */ - public Transfer transfer() { - Transfer transfer = null; - String orderNo = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date()) + Main.randomString(7); - Map transferMap = new HashMap(); - transferMap.put("channel", "wx_pub");// 目前支持 wx(新渠道)、 wx_pub - transferMap.put("order_no", orderNo);// 企业转账使用的商户内部订单号。wx(新渠道)、wx_pub 规定为 1 ~ 50 位不能重复的数字字母组合 - transferMap.put("amount", "200");// 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100,企业付款最小发送金额为 1 元) - transferMap.put("type", "b2c");// 付款类型,当前仅支持 b2c 企业付款 - transferMap.put("currency", "cny"); - transferMap.put("recipient", openid);// 接收者 id, 为用户在 wx(新渠道)、wx_pub 下的 open_id - transferMap.put("description", "your description"); - Map app = new HashMap(); - app.put("id", appId); - transferMap.put("app", app); - - try { - transfer = Transfer.create(transferMap); - System.out.println(transfer); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } - return transfer; - } - - /** - * 根据 ID 查询 - * - * 根据 ID 查询企业转账记录。 - * 参考文档:https://pingxx.com/document/api#api-t-inquiry - * @param id - */ - public void retrieve(String id) { - Map param = new HashMap(); - try { - Transfer transfer = Transfer.retrieve(id, param); - System.out.println(transfer); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } - - } - - /** - * 批量查询 - * - * 批量查询企业转账记录,默认一次查询 10 条,用户可以使用 limit 自定义查询数目,但是最多不超过 100 条。 - */ - public void all() { - Map parm = new HashMap(); - parm.put("limit", 3); - - try { - TransferCollection transferCollection = Transfer.all(parm); - System.out.println(transferCollection); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } - } -} diff --git a/example/SimpleExample/src/main/java/com/pingxx/example/WebhooksVerifyExample.java b/example/SimpleExample/src/main/java/com/pingxx/example/WebhooksVerifyExample.java deleted file mode 100644 index 0d9294b..0000000 --- a/example/SimpleExample/src/main/java/com/pingxx/example/WebhooksVerifyExample.java +++ /dev/null @@ -1,123 +0,0 @@ -/* * - * Ping++ Server SDK - * 说明: - * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。 - * 接入 webhooks 流程参考开发者中心:https://www.pingxx.com/docs/webhooks/webhooks - * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。 - */ -package com.pingxx.example; - -import java.io.*; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.spec.X509EncodedKeySpec; - -import org.apache.commons.codec.binary.Base64; - -/** - * Created by sunkai on 15/5/19. webhooks 验证签名示例 - * - * 该实例演示如何对 Ping++ webhooks 通知进行验证。 - * 验证是为了让开发者确认该通知来自 Ping++ ,防止恶意伪造通知。用户如果有别的验证机制,可以不进行验证签名。 - * - * 验证签名需要 签名、公钥、验证信息,该实例采用文件存储方式进行演示。 - * 实际项目中,需要用户从异步通知的 HTTP header 中读取签名,从 HTTP body 中读取验证信息。公钥的存储方式也需要用户自行设定。 - * - * 该实例仅供演示如何验证签名,请务必不要直接 copy 到实际项目中使用。 - * - */ -public class WebhooksVerifyExample { - - private static String pubKeyPath = "res/pingpp_public_key.pem"; - private static String eventPath = "res/webhooks_raw_post_data.json"; - private static String signPath = "res/signature.txt"; - - /** - * 验证 webhooks 签名,仅供参考 - * @param args - * @throws Exception - */ - public static void main(String[] args) throws Exception { - runDemos(); - } - - public static void runDemos() throws Exception { - // 该数据请从 request 中获取原始 POST 请求数据, 以下仅作为示例 - String webhooksRawPostData = getStringFromFile(eventPath); - System.out.println("------- POST 原始数据 -------"); - System.out.println(webhooksRawPostData); - // 签名数据请从 request 的 header 中获取, key 为 X-Pingplusplus-Signature (请忽略大小写, 建议自己做格式化) - String signature = getStringFromFile(signPath); - System.out.println("------- 签名 -------"); - System.out.println(signature); - - boolean result = verifyData(webhooksRawPostData, signature, getPubKey()); - System.out.println("验签结果:" + (result ? "通过" : "失败")); - } - - /** - * 读取文件, 部署 web 程序的时候, 签名和验签内容需要从 request 中获得 - * @param filePath - * @return - * @throws Exception - */ - public static String getStringFromFile(String filePath) throws Exception { - FileInputStream in = new FileInputStream(filePath); - InputStreamReader inReader = new InputStreamReader(in, "UTF-8"); - BufferedReader bf = new BufferedReader(inReader); - StringBuilder sb = new StringBuilder(); - String line; - do { - line = bf.readLine(); - if (line != null) { - if (sb.length() != 0) { - sb.append("\n"); - } - sb.append(line); - } - } while (line != null); - - return sb.toString(); - } - - /** - * 获得公钥 - * @return - * @throws Exception - */ - public static PublicKey getPubKey() throws Exception { - String pubKeyString = getStringFromFile(pubKeyPath); - pubKeyString = pubKeyString.replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", ""); - byte[] keyBytes = Base64.decodeBase64(pubKeyString); - - // generate public key - X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PublicKey publicKey = keyFactory.generatePublic(spec); - return publicKey; - } - - /** - * 验证签名 - * @param dataString - * @param signatureString - * @param publicKey - * @return - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException - * @throws SignatureException - */ - public static boolean verifyData(String dataString, String signatureString, PublicKey publicKey) - throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException { - byte[] signatureBytes = Base64.decodeBase64(signatureString); - Signature signature = Signature.getInstance("SHA256withRSA"); - signature.initVerify(publicKey); - signature.update(dataString.getBytes("UTF-8")); - return signature.verify(signatureBytes); - } - -} diff --git a/example/build.gradle b/example/build.gradle new file mode 100644 index 0000000..495f667 --- /dev/null +++ b/example/build.gradle @@ -0,0 +1,13 @@ +apply plugin: 'java' + +dependencies { + implementation 'com.google.code.gson:gson:2.10' + implementation 'commons-codec:commons-codec:1.17.0' + + // 方法 1. 本地文件系统依赖 + // implementation fileTree(dir: 'lib', includes: ['*jar']) + // 方法 2. 仓库依赖 + // implementation 'com.pingxx:pingpp-java:2.5.6' + // 方法 3.模块依赖 + implementation project(':pingpp-sdk') +} diff --git a/example/SimpleExample/bin/charge b/example/res/charge.json similarity index 100% rename from example/SimpleExample/bin/charge rename to example/res/charge.json diff --git a/example/SimpleExample/res/signature.txt b/example/res/signature.txt similarity index 100% rename from example/SimpleExample/res/signature.txt rename to example/res/signature.txt diff --git a/example/SimpleExample/res/webhooks_raw_post_data.json b/example/res/webhooks_raw_post_data.json similarity index 100% rename from example/SimpleExample/res/webhooks_raw_post_data.json rename to example/res/webhooks_raw_post_data.json diff --git a/example/SimpleExample/res/your_rsa_private_key.pem b/example/res/your_rsa_private_key_pkcs1.pem similarity index 100% rename from example/SimpleExample/res/your_rsa_private_key.pem rename to example/res/your_rsa_private_key_pkcs1.pem diff --git a/example/res/your_rsa_private_key_pkcs8.pem b/example/res/your_rsa_private_key_pkcs8.pem new file mode 100644 index 0000000..9da76fb --- /dev/null +++ b/example/res/your_rsa_private_key_pkcs8.pem @@ -0,0 +1 @@ +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDHYyS3FwoESp1hGLYiBhy6k9Ag3lzGCIEvm50IIEkE0Ftc9qq44TWqyl+EHUpTMdcBOcI42JLO5stwFOfCLa3PQStEJ4llIRFEKlsrHh67pvWd5RNaSBrvGlnFY40S+SZmjk2WF/h9dE9Ric79t0YI0alD8dIl9Yu3OaEKo7VonBWFwOYMxjPhtORlq+EUF1XJd//yftQrKWTTd7KaUonWzBCl4VzFop/OyTWYlTuZz3eYJaNpH5VaQ1vDgBAcPIeBvMf7NgBHMKW6LLmFd2LEYQ/6I7hkGTjysSzWEpO8bPWT6OEsJ2R2kFGOrSkr+G2MDcJ7ykXYAmz5+A3plS6ZAgMBAAECggEAVrgwR9GlcahiOtDcpn+yDxQq+aC9CQS561LrQZWJLKbSleRS7IZHKTlLwdJbeUO8F7RfXQoVEBghc2YkRrhHWFUn1ES95VY0hElHzcET7Nn5CeuQNzwVOtljIg7iVNY4dXJ/HEDguu/Tb8tYU9FajItj60FJ/WiGk/JksJPzWsOCVPVniy9fTbTLy1e+dCpCI6OXirtm7hvbodRNDjree0wSEzm7vL0wVzEZFo6kX+ABGUwaoO7pPyH+hgyI5Iuhc65NHsHzTJpf8yNFl9QGhkxvm2Ff2oEtDt1idOTBrHB6tg+ti9Ctb2+2yzBnk14hsSYJnKitR7wM6ZCFPX4eYQKBgQD+JAREeFkodec/SC+GX+4Q4Y68uMPkfUPrMKXM4cyY5wgXk64RBvRVxIxX7x6Y3tIKn9v8tWAprbsyVr15eb4RcAFEVwjuoZixhd9sIPsRhfdNolKn/fSPIsHL4ywcJMSIt7KVKHuQeqBNHy0o0PxQjNej1ozsmrAWqV55cbKHswKBgQDI2JQRTPIEC/2y6LdmBVhGJW9OKWTYdVNjq7rX+Yw4uxOtfd5hBqpvgZEklKEk72aazFdEcERlAm9SqoX09qk6zK/wcq4Xn5Q/qy8ecmjuyf2AK9X+HUdMerMVxhK9RpeevKYP/RO2F/wIN64anlQVYygVkXXgdOvWhBE4YABKgwKBgDRtmbPGYB5ItHwJmERQZfx1i8zDESaB8RED6DBsJJkmkDTM8ovws1c+RPWfDuDalto6QFfR0xTGEmhAHLaCtwNB6AEBM4aHL8jvpTfZVfI3gN0zL3oYmestcG1vYBouO504yE6dG2Ci6479b4OMGYFEjPfvuwLUpp8GMcc7/WihAoGANCp8mtm/ammq5VMof2kX+nAyrrx1ovsmQ5cRGpOIZhvBCqjMn6rZjci7aCLqj+tWXRKCABagzROK0o/T50JBxjHv6KYArcYW/Up7HI9ezdbM7wNzu2LjZ+veo+MkbuDs9J/PCgwTmJI2NfQwVl2VPVDZ0nBLi5cSwk7fIiNdL/0CgYEAtECmC1QDs53Di2MIsa/Fe4sWfJGSDqEWqhcA/aPwf1skM6VJJXBBMV1qFtwgO1AlLnu9dQYra6ylsUoubVYIXM9XK7EMhbqi57+Q75jHFTc0DnzOTyho5Gp4Ddi8dztmZGNWdWTGdeMqh+svqMXkD6VdJeddyGu/Zlgj7Wk6whU= \ No newline at end of file diff --git a/example/SimpleExample/res/your_rsa_public_key.pem b/example/res/your_rsa_public_key.pem similarity index 100% rename from example/SimpleExample/res/your_rsa_public_key.pem rename to example/res/your_rsa_public_key.pem diff --git a/example/src/main/java/com/pingxx/example/AgreementExample.java b/example/src/main/java/com/pingxx/example/AgreementExample.java new file mode 100644 index 0000000..205a51c --- /dev/null +++ b/example/src/main/java/com/pingxx/example/AgreementExample.java @@ -0,0 +1,30 @@ +package com.pingxx.example; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.Agreement; + +import java.util.HashMap; +import java.util.Map; + +public class AgreementExample { + + private String appId; + + public AgreementExample(String appId) { + this.appId = appId; + } + + public static void runDemos(String appId) throws PingppException { + AgreementExample example = new AgreementExample(appId); + Agreement agrModify = example.modify(); + } + + public Agreement modify() throws PingppException { + String agreementId = "agr_123456"; + Map params = new HashMap<>(); + params.put("deduct_time", "2025-07-10"); + params.put("memo", "扣款失败,需延期扣款时间"); + + return Agreement.modify(agreementId, params); + } +} diff --git a/example/src/main/java/com/pingxx/example/AgreementNotifyExample.java b/example/src/main/java/com/pingxx/example/AgreementNotifyExample.java new file mode 100644 index 0000000..54c9fa5 --- /dev/null +++ b/example/src/main/java/com/pingxx/example/AgreementNotifyExample.java @@ -0,0 +1,33 @@ +package com.pingxx.example; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.AgreementNotify; + +import java.util.HashMap; +import java.util.Map; + +public class AgreementNotifyExample { + private String appId; + + AgreementNotifyExample(String appId) { + this.appId = appId; + } + + public static void runDemos(String appId) { + AgreementNotifyExample example = new AgreementNotifyExample(appId); + System.out.println("------- 签约扣款-商户预扣费通知 -------"); + example.create("agr_123456"); + } + + public AgreementNotify create(String id) { + AgreementNotify agreementNotify = null; + Map params = new HashMap(); + params.put("amount", 100); + try { + agreementNotify = AgreementNotify.create(id, params); + } catch (PingppException e) { + e.printStackTrace(); + } + return agreementNotify; + } +} diff --git a/example/src/main/java/com/pingxx/example/BatchTransferExample.java b/example/src/main/java/com/pingxx/example/BatchTransferExample.java new file mode 100644 index 0000000..a556df1 --- /dev/null +++ b/example/src/main/java/com/pingxx/example/BatchTransferExample.java @@ -0,0 +1,274 @@ +/* * + * Ping++ Server SDK + * 说明: + * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。 + * 接入企业付款流程参考开发者中心:https://www.pingxx.com/docs/server/transfer ,文档可筛选后端语言和接入渠道。 + * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。 +*/ +package com.pingxx.example; + +import com.pingplusplus.exception.*; +import com.pingplusplus.model.BatchTransfer; +import com.pingplusplus.model.BatchTransferCollection; +import com.pingplusplus.model.Transfer; +import com.pingplusplus.model.TransferCollection; + +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * + * 该实例演示如何使用 Ping++ 进行批量转账。 + * + * 开发者需要填写 apiKey 和 appId , + * + * apiKey 有 TestKey 和 LiveKey 两种。 + * + * TestKey 模式下不会产生真实的交易。 + ** + */ +public class BatchTransferExample { + + private String appId; + + public static void runDemos(String appId) { + + BatchTransferExample batchTransferExample = new BatchTransferExample(appId); + System.out.println("------- 创建 BatchTransfer -------"); + BatchTransfer batchTransfer = batchTransferExample.create(); + System.out.println("------- 查询 BatchTransfer -------"); + batchTransferExample.retrieve(batchTransfer.getId()); + System.out.println("------- 查询 BatchTransfer 列表 -------"); + batchTransferExample.list(); + + } + + BatchTransferExample(String appId) { + this.appId = appId; + } + + /** + * 创建批量转账 + * + * 创建企业转账需要传递一个 map 给 BatchTransfer.create(); + * map 填写的具体介绍可以参考:https://www.pingxx.com/api + * + * @return + */ + public BatchTransfer create() { + String channel = "alipay"; + + BatchTransfer obj = null; + String batchNo = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date()) + Main.randomString(7); + Map params = new HashMap(); + params.put("app", appId); + params.put("channel", channel); // 目前支持 alipay、 unionpay、wx_pub、allinpay、jdpay + params.put("batch_no", batchNo); // 企业转账使用的商户内部订单号。 + params.put("amount", 5000); // 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100) + params.put("type", "b2c"); // 付款类型,wx_pub 仅支持 b2c,alipay、 unionpay、allinpay、jdpay 支持 b2b + params.put("currency", "cny"); + params.put("description", "your description"); + List> recipients = new ArrayList>(); + + recipients.add(channelRecipient(channel)); + // recipients.add(channelRecipient(channel)); + // recipients.add(channelRecipient(channel)); + + params.put("recipients", recipients); + + + try { + obj = BatchTransfer.create(params); + System.out.println(obj); + } catch (PingppException e) { + e.printStackTrace(); + } + return obj; + } + + /** + * 根据 ID 查询 + * + * 根据 ID 查询批量转账记录。 + * 参考文档:https://www.pingxx.com/api + * @param id + */ + public void retrieve(String id) { + try { + BatchTransfer obj = BatchTransfer.retrieve(id); + System.out.println(obj); + } catch (PingppException e) { + e.printStackTrace(); + } + } + + /** + * 查询列表 + * + * 查询批量转账记录列表,默认一次查询 10 条,用户可以使用 per_page 自定义查询数目,但是最多不超过 20 条。 + */ + public void list() { + Map param = new HashMap(); + param.put("per_page", 3); + param.put("app", appId); + + try { + BatchTransferCollection objs = BatchTransfer.list(param); + System.out.println(objs); + } catch (PingppException e) { + e.printStackTrace(); + } + } + + private Map channelRecipient(String channel) { + Map recipient = new HashMap(); + + switch (channel) { + case "alipay": + recipient = alipayRecipient(); + break; + case "wx_pub": + recipient = wxPubRecipient(); + break; + case "unionpay": + recipient = unionpayRecipient(); + break; + case "allinpay": + recipient = allinpayRecipient(); + break; + case "jdpay": + recipient = jdpayRecipient(); + break; + } + + return recipient; + } + + private Map alipayRecipient() { + Map extra = new HashMap<>(); + + // 必须,金额,单位为分。 + extra.put("amount", 5000); + + // 必须,接收者支付宝账号。 + extra.put("account", "alipayaccount@gmail.com"); + + // 必须,收款人姓名,1~50位。 + extra.put("name", "张三"); + + // 可选,收款方账户类型。可取值:1、 ALIPAY_USERID :支付宝账号对应的支付宝唯一用户号。以2088开头的16位纯数字组成。 2、 ALIPAY_LOGONID (默认值):支付宝登录号,支持邮箱和手机号格式。 + // extra.put("account_type", "ALIPAY_LOGONID"); + + // 可选,批量企业付款描述,最多 200 字节。 + // extra.put("description", "描述"); + + // 可选,订单号,1 ~ 64 位不能重复的数字字母组合。 + // extra.put("order_no", "1234567890123456"); + + return extra; + } + + private Map wxPubRecipient() { + Map extra = new HashMap<>(); + // 必须,金额,单位为分。 + extra.put("amount", 5000); + + // 必须,接收者 id,为用户在 wx_pub 下的 open_id。 + extra.put("open_id", "o7xEMsySBFG3MVHI-9VsAJX-j50W"); + + // 可选,收款人姓名。当该参数为空,则不校验收款人姓名。 + // extra.put("name", "张三"); + + // 可选,是否强制校验收款人姓名。仅当 user_name 参数不为空时该参数生效。 + // extra.put("force_check", true); + + // 可选,批量企业付款描述,最多 99 个英文和数字的组合或最多 33 个中文字符,不可以包含特殊字符。不填默认使用外层参数中的 description。 + // extra.put("description", "描述"); + + // 可选,订单号,1 ~ 32 位不能重复的数字字母组合。 + // extra.put("order_no", "1234567890123456"); + + return extra; + } + + private Map unionpayRecipient() { + Map extra = new HashMap<>(); + // 必须,金额,单位为分。 + extra.put("amount", 5000); + + // 必须,1~32位,收款人银行卡号或者存折号。 + extra.put("account", "6228480402564890011"); + + // 必须,1~100位,收款人姓名。 + extra.put("name", "张三"); + + /** + * open_bank_code 和 open_bank 两个参数必传一个,建议使用 open_bank_code ,若都传参则优先使用 open_bank_code 读取规则;prov 和 city 均为可选参数,如果不传参,则使用默认值 "上海" 给渠道接口。 + */ + // 条件可选,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:https://www.pingxx.com/api#%E9%93%B6%E8%A1%8C%E7%BC%96%E5%8F%B7%E8%AF%B4%E6%98%8E。 + extra.put("open_bank_code", "0103"); + + // 条件可选,1~50位,开户银行,详情请参考 企业付款(银行卡)银行编号说明:https://www.pingxx.com/api#%E9%93%B6%E8%A1%8C%E7%BC%96%E5%8F%B7%E8%AF%B4%E6%98%8E。 + extra.put("open_bank", "农业银行"); + + // 可选,订单号,1 ~ 16 位数字。 + // extra.put("order_no", "1234567890123456"); + + // 可选,批量企业付款描述,最多 200 字节。 + // extra.put("description", "描述"); + + return extra; + } + + private Map allinpayRecipient() { + Map extra = new HashMap<>(); + // 必须,金额,单位为分。 + extra.put("amount", 5000); + + // 必须,接收者银行卡账号。 + extra.put("account", "6228480402564890011"); + + // 必须,收款人姓名。 + extra.put("name", "张三"); + + // 必须,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:https://www.pingxx.com/api#%E9%93%B6%E8%A1%8C%E7%BC%96%E5%8F%B7%E8%AF%B4%E6%98%8E。 + extra.put("open_bank_code", "0103"); + + // 可选,5位,业务代码,根据通联业务人员提供,不填使用通联提供默认值09900。 + // extra.put("business_code", "09900"); + + // 可选,1位,银行卡号类型,0:银行卡、1:存折,不填默认使用银行卡。 + // extra.put("card_type", 0); + + // 可选,批量付款描述,最多 30 个 Unicode 字符。 + // extra.put("description", "描述"); + + // 可选,订单号, 20 ~ 40 位不能重复的数字字母组合(必须以通联的商户号开头,建议组合格式:通联商户号 + 时间戳 + 固定位数顺序流水号,不包含+号),这里不传的话程序会调用商户的通联商户号加上随机数自动生成 order_no。 + // extra.put("order_no", "331301234554321098765432112"); + + return extra; + } + + private Map jdpayRecipient() { + Map extra = new HashMap<>(); + // 必须,金额,单位为分。 + extra.put("amount", 5000); + + // 必须,1~32位,收款人银行卡号或者存折号。 + extra.put("account", "6228480402564890011"); + + // 必须,1~100位,收款人姓名。 + extra.put("name", "张三"); + + // 必须,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:https://www.pingxx.com/api#%E9%93%B6%E8%A1%8C%E7%BC%96%E5%8F%B7%E8%AF%B4%E6%98%8E。 + extra.put("open_bank_code", "0103"); + + // 可选,批量付款描述,最多 100 个 Unicode 字符。 + // extra.put("description", "描述"); + + // 可选,订单号,jdpay 限长 1~64 位不能重复的数字字母组合。 + // extra.put("order_no", "1234567890123456"); + + return extra; + } +} diff --git a/example/src/main/java/com/pingxx/example/ChargeExample.java b/example/src/main/java/com/pingxx/example/ChargeExample.java new file mode 100644 index 0000000..88421e1 --- /dev/null +++ b/example/src/main/java/com/pingxx/example/ChargeExample.java @@ -0,0 +1,689 @@ +/** + * Ping++ Server SDK + * 说明: + * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。 + * 接入支付流程参考开发者中心:https://www.pingxx.com/docs/server/charge ,文档可筛选后端语言和接入渠道。 + * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。 + */ +package com.pingxx.example; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.Charge; +import com.pingplusplus.model.ChargeCollection; + +import java.util.*; + +/** + * Charge 对象相关示例 + * + * 该实例程序演示了如何从 Ping++ 服务器获得 charge ,查询 charge。 + * + * 开发者需要填写 apiKey 和 appId , + * + * apiKey 有 TestKey 和 LiveKey 两种。 + * + * TestKey 模式下不会产生真实的交易。 + */ +public class ChargeExample { + + private String appId; + + ChargeExample(String appId) { + this.appId = appId; + } + + public static void runDemos(String appId) { + + ChargeExample chargeExample = new ChargeExample(appId); + System.out.println("------- 创建 charge -------"); + Charge charge = chargeExample.createCharge(); + System.out.println("------- 查询 charge -------"); + chargeExample.retrieve(charge.getId()); + System.out.println("------- 查询 charge 列表 -------"); + chargeExample.list(); + System.out.println("------- 撤销 charge(仅支持线下渠道) -------"); + chargeExample.reverse(charge.getId()); + } + + /** + * 创建 Charge + * + * 创建 Charge 用户需要组装一个 map 对象作为参数传递给 Charge.create(); + * map 里面参数的具体说明请参考:https://www.pingxx.com/api#api-c-new + * @return Charge + */ + public Charge createCharge() { + Charge charge = null; + String channel = "wx_pub"; + + Map chargeMap = new HashMap(); + chargeMap.put("amount", 100);//订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100) + chargeMap.put("currency", "cny"); + chargeMap.put("subject", "Your Subject"); + chargeMap.put("body", "Your Body"); + String orderNo = new Date().getTime() + Main.randomString(7); + chargeMap.put("order_no", orderNo);// 推荐使用 8-20 位,要求数字或字母,不允许其他字符 + chargeMap.put("channel", channel);// 支付使用的第三方支付渠道取值,请参考:https://www.pingxx.com/api#api-c-new + chargeMap.put("client_ip", "127.0.0.1"); // 发起支付请求客户端的 IP 地址,格式为 IPV4,如: 127.0.0.1 + Map app = new HashMap(); + app.put("id", appId); + chargeMap.put("app", app); + + // extra 取值请查看相应方法说明 + chargeMap.put("extra", channelExtra(channel)); + + try { + //发起交易请求 + charge = Charge.create(chargeMap); + // 传到客户端请先转成字符串 .toString(), 调该方法,会自动转成正确的 JSON 字符串 + String chargeString = charge.toString(); + System.out.println(chargeString); + } catch (PingppException e) { + e.printStackTrace(); + } + + return charge; + } + + /** + * 查询 Charge + * + * 该接口根据 charge Id 查询对应的 charge 。 + * 参考文档:https://www.pingxx.com/api#api-c-inquiry + * + * 参考文档: https://www.pingxx.com/api#api-expanding + * @param id + */ + public Charge retrieve(String id) { + Charge charge = null; + try { + Map params = new HashMap(); + charge = Charge.retrieve(id, params); + System.out.println(charge); + } catch (PingppException e) { + e.printStackTrace(); + } + + return charge; + } + + /** + * 撤销 Charge + * + * @param id + */ + public Charge reverse(String id) { + Charge charge = null; + try { + charge = Charge.reverse(id); + System.out.println(charge); + } catch (PingppException e) { + e.printStackTrace(); + } + + return charge; + } + + /** + * 分页查询 Charge + * + * 该接口为批量查询接口,默认一次查询10条。 + * 用户可以通过添加 limit 参数自行设置查询数目,最多一次不能超过 100 条。 + * + * 该接口同样可以使用 expand 参数。 + * @return chargeCollection + */ + public ChargeCollection list() { + ChargeCollection chargeCollection = null; + Map params = new HashMap(); + params.put("limit", 3); + Map app = new HashMap(); + app.put("id", appId); + params.put("app", app); // app 参数为必填参数。 + + try { + chargeCollection = Charge.list(params); + System.out.println(chargeCollection); + } catch (PingppException e) { + e.printStackTrace(); + } + + return chargeCollection; + } + + private Map channelExtra(String channel) { + Map extra = new HashMap<>(); + + switch (channel) { + case "alipay": + extra = alipayExtra(); + break; + case "alipay_wap": + extra = alipayWapExtra(); + break; + case "alipay_pc_direct": + extra = alipayPcDirectExtra(); + break; + case "alipay_qr": + extra = alipayQrExtra(); + break; + case "wx": + extra = wxExtra(); + break; + case "wx_pub": + extra = wxPubExtra(); + break; + case "wx_pub_qr": + extra = wxPubQrDirectExtra(); + break; + case "wx_lite": + extra = wxLiteExtra(); + break; + case "wx_wap": + extra = wxWapExtra(); + break; + case "bfb": + extra = bfbExtra(); + break; + case "bfb_wap": + extra = bfbWapExtra(); + break; + case "upacp": + extra = upacpExtra(); + break; + case "upacp_wap": + extra = upacpWapExtra(); + break; + case "upacp_pc": + extra = upacpPcExtra(); + break; + case "jdpay_wap": + extra = jdpayWapExtra(); + break; + case "yeepay_wap": + extra = yeepayWapExtra(); + break; + case "applepay_upacp": + extra = applepayUpacpExtra(); + break; + case "qpay": + extra = qpayExtra(); + break; + case "cmb_wallet": + extra = cmbWalletExtra(); + break; + case "cp_b2b": + extra = cpB2bExtra(); + break; + case "isv_scan": + extra = isvScanExtra(); + break; + case "isv_qr": + extra = isvQrExtra(); + break; + case "isv_wap": + extra = isvWapExtra(); + break; + case "alipay_scan": + extra = alipayScanExtra(); + break; + case "wx_pub_scan": + extra = wxPubScanExtra(); + break; + case "cb_alipay": + extra = cbAlipayExtra(); + break; + case "cb_wx": + extra = cbWxExtra(); + break; + case "cb_wx_pub": + extra = cbWxPubExtra(); + break; + case "cb_wx_pub_qr": + extra = cbWxPubQrExtra(); + break; + case "cb_wx_pub_scan": + extra = cbWxPubScanExtra(); + break; + } + + return extra; + } + + // extra 根据渠道会有不同的参数 + + private Map alipayExtra() { + Map extra = new HashMap<>(); + + // 可选,开放平台返回的包含账户信息的 token(授权令牌,商户在一定时间内对支付宝某些服务的访问权限)。通过授权登录后获取的 alipay_open_id ,作为该参数的 value ,登录授权账户即会为支付账户,32 位字符串。 + // extra.put("extern_token", "TOKEN"); + + // 可选,是否发起实名校验,T 代表发起实名校验;F 代表不发起实名校验。 + extra.put("rn_check", "T"); + + return extra; + } + + private Map alipayWapExtra() { + Map extra = new HashMap<>(); + + // 必须,支付成功的回调地址,在本地测试不要写 localhost。URL 后面带参数的情况,可能会被渠道拒绝,建议把参数放到“路径”里,比如:`https://example.com/result/user/12345/order_no/6789`。 + extra.put("success_url", "https://example.com/success"); + // 可选,支付取消的回调地址, app_pay 为true时,该字段无效,在本地测试不要写 localhost。URL 后面带参数的情况,可能会被渠道拒绝,建议把参数放到“路径”里,比如:`https://example.com/result/user/12345/order_no/6789`。 + extra.put("cancel_url", "https://example.com/cancel"); + + // 可选,2016 年 6 月 16 日之前登录 Ping++ 管理平台填写支付宝手机网站的渠道参数的旧接口商户,需要更新接口时设置此参数值为true,6月16号后接入的新接口商户不需要设置该参数。 + // extra.put("new_version", true); + + // 可选,是否使用支付宝客户端支付,该参数为true时,调用客户端支付。 + // extra.put("app_pay", true); + + return extra; + } + + private Map alipayPcDirectExtra() { + Map extra = new HashMap<>(); + // 必须,支付成功的回调地址,在本地测试不要写 localhost。URL 后面带参数的情况,可能会被渠道拒绝,建议把参数放到“路径”里,比如:`https://example.com/result/user/12345/order_no/6789`。 + extra.put("success_url", "https://example.com/success"); + + // 可选,是否开启防钓鱼网站的验证参数(如果已申请开通防钓鱼时间戳验证,则此字段必填)。 + // extra.put("enable_anti_phishing_key", false); + + // 可选,客户端 IP ,用户在创建交易时,该用户当前所使用机器的IP(如果商户申请后台开通防钓鱼IP地址检查选项,此字段必填,校验用)。 + // extra.put("exter_invoke_ip", "192.168.100.8"); + + return extra; + } + + private Map alipayQrExtra() { + Map extra = new HashMap<>(); + + return extra; + } + + private Map wxExtra() { + Map extra = new HashMap<>(); + // 可选,指定支付方式,指定不能使用信用卡支付可设置为 no_credit 。 + extra.put("limit_pay", "no_credit"); + + // 可选,商品标记,代金券或立减优惠功能的参数。 + // extra.put("goods_tag", "YOUR_GOODS_TAG"); + + return extra; + } + + private Map wxPubExtra() { + Map extra = new HashMap<>(); + // 可选,指定支付方式,指定不能使用信用卡支付可设置为 no_credit 。 + extra.put("limit_pay", "no_credit"); + + // 可选,商品标记,代金券或立减优惠功能的参数。 + // extra.put("goods_tag", "YOUR_GOODS_TAG"); + + // 必须,用户在商户 appid 下的唯一标识。 + extra.put("open_id", "o7xEMsySBFG3MVHI-9VsAJX-j50W"); + + return extra; + } + + private Map wxPubQrDirectExtra() { + Map extra = new HashMap<>(); + // 可选,指定支付方式,指定不能使用信用卡支付可设置为 no_credit 。 + extra.put("limit_pay", "no_credit"); + + // 可选,商品标记,代金券或立减优惠功能的参数。 + // extra.put("goods_tag", "YOUR_GOODS_TAG"); + + // 必须,商品 ID,1-32 位字符串。此 id 为二维码中包含的商品 ID,商户可自定义。 + extra.put("product_id", "YOUR_PRODUCT_ID"); + + return extra; + } + + private Map wxLiteExtra() { + Map extra = new HashMap<>(); + // 可选,指定支付方式,指定不能使用信用卡支付可设置为 no_credit 。 + extra.put("limit_pay", "no_credit"); + + // 可选,商品标记,代金券或立减优惠功能的参数。 + // extra.put("goods_tag", "YOUR_GOODS_TAG"); + + // 必须,用户在商户 appid 下的唯一标识。 + extra.put("open_id", "o7xEMsySBFG3MVHI-9VsAJX-j50W"); + + return extra; + } + + private Map wxWapExtra() { + Map extra = new HashMap<>(); + // 可选,支付完成的回调地址。 + extra.put("result_url", "https://example.com/success"); + + // 可选,商品标记,代金券或立减优惠功能的参数。 + // extra.put("goods_tag", "YOUR_GOODS_TAG"); + + return extra; + } + + private Map bfbExtra() { + Map extra = new HashMap<>(); + + return extra; + } + + private Map bfbWapExtra() { + Map extra = new HashMap<>(); + // 必须,支付完成的回调地址,在本地测试不要写 localhost。URL 后面带参数的情况,可能会被渠道拒绝,建议把参数放到“路径”里,比如:`https://example.com/result/user/12345/order_no/6789`。 + extra.put("result_url", "https://example.com/success"); + + // 必须,是否需要登录百度钱包来进行支付。 + extra.put("bfb_login", true); + + return extra; + } + + private Map upacpExtra() { + Map extra = new HashMap<>(); + + return extra; + } + + private Map upacpWapExtra() { + Map extra = new HashMap<>(); + // 必须,支付完成的回调地址,在本地测试不要写 localhost。URL 后面带参数的情况,可能会被渠道拒绝,建议把参数放到“路径”里,比如:`https://example.com/result/user/12345/order_no/6789`。 + extra.put("result_url", "https://example.com/success"); + + return extra; + } + + private Map upacpPcExtra() { + Map extra = new HashMap<>(); + // 必须,支付完成的回调地址,在本地测试不要写 localhost。URL 后面带参数的情况,可能会被渠道拒绝,建议把参数放到“路径”里,比如:`https://example.com/result/user/12345/order_no/6789`。 + extra.put("result_url", "https://example.com/success"); + + return extra; + } + + private Map jdpayWapExtra() { + Map extra = new HashMap<>(); + // 必须,支付完成的回调地址。 + extra.put("success_url", "https://example.com/success"); + + // 必须,支付失败页面跳转路径。 + extra.put("fail_url", "https://example.com/fail"); + + // 可选,用户交易令牌,用于识别用户信息,支付成功后会调用 success_url 返回给商户。商户可以记录这个 token 值,当用户再次支付的时候传入该 token ,用户无需再次输入银行卡信息,直接输入短信验证码进行支付。32 位字符串。 + // extra.put("token", "TOKEN"); + + // 可选,订单类型,值为0表示实物商品订单,值为 1 代表虚拟商品订单,该参数默认值为 0 。 + // extra.put("order_type", 0); + + // 可选,设置是否通过手机端发起支付,值为 true 时调用手机 h5 支付页面,值为 false 时调用 PC 端支付页面,该参数默认值为 true 。 + extra.put("is_mobile", true); + + // 可选,用户账号类型,取值只能为:BIZ。传参存在问题请参考 帮助中心:https://help.pingxx.com/article/1012535/。 + // extra.put("user_type", "BIZ"); + + // 可选,商户的用户账号。传参存在问题请参考 帮助中心:https://help.pingxx.com/article/1012535/。 + // extra.put("user_id", "YOUR_USER_ID"); + + return extra; + } + + private Map yeepayWapExtra() { + Map extra = new HashMap<>(); + // 必须,商品类别码,商品类别码参考链接 :https://www.pingxx.com/api#%E6%98%93%E5%AE%9D%E6%94%AF%E4%BB%98%E5%95%86%E5%93%81%E7%B1%BB%E5%9E%8B%E7%A0%81 。 + extra.put("product_category", "1"); + + // 必须,用户标识,商户生成的用户账号唯一标识,最长 50 位字符串。 + extra.put("identity_id", "IDENTITY_ID"); + + // 必须,用户标识类型,用户标识类型参考链接:https://www.pingxx.com/api#%E6%98%93%E5%AE%9D%E6%94%AF%E4%BB%98%E7%94%A8%E6%88%B7%E6%A0%87%E8%AF%86%E7%B1%BB%E5%9E%8B%E7%A0%81 。 + extra.put("identity_type", 2); + + // 必须,终端类型,对应取值 0:IMEI, 1:MAC, 2:UUID, 3:other。 + extra.put("terminal_type", 2); + + // 必须,终端 ID。 + extra.put("terminal_id", "TERMINAL_ID"); + + // 必须,用户使用的移动终端的 UserAgent 信息。 + extra.put("user_ua", "USER_UA"); + + // 必须,前台通知地址。 + extra.put("result_url", "https://example.com/result"); + + return extra; + } + + private Map applepayUpacpExtra() { + Map extra = new HashMap<>(); + + return extra; + } + + private Map qpayExtra() { + Map extra = new HashMap<>(); + // 必须,客户端设备类型,取值范围: "ios" ,"android"。 + extra.put("device", "ios"); + + return extra; + } + + private Map cmbWalletExtra() { + Map extra = new HashMap<>(); + // 必须,交易完成跳转的地址。 + extra.put("result_url", "https://example.com/result"); + + /** + * 对于 p_no, seq , m_uid , mobile 这几个参数: + * 1. 这几个参数是用户自定义的。 + * 2. 对于同一个终端用户每次请求 charge 务必使用同一套参数(确保每个参数都不变), + * 任意参数变更都会导致用户重新签约,同一个用户和招行重新签约的次数有限制,超限制就会无法签约 ,导致用户无法使用。 + */ + + // 必须,客户协议号,不超过 30 位的纯数字字符串。 + extra.put("p_no", "201700100001"); + + // 必须,协议开通请求流水号,不超过 20 位的纯数字字符串,请保证系统内唯一。 + extra.put("seq", "201700200001"); + + // 必须,协议用户 ID,不超过 20 位的纯数字字符串。 + extra.put("m_uid", "201700300001"); + + // 必须,协议手机号,11 位数字。 + extra.put("mobile", "13523456789"); + + return extra; + } + + private Map cpB2bExtra() { + Map extra = new HashMap<>(); + + return extra; + } + + private Map isvScanExtra() { + Map extra = new HashMap<>(); + // 必须,终端号,1~8 位英文或数字,要求不同终端此号码不一样,会显示在对账单中。 + extra.put("terminal_id", "A0000007"); + + // 必须,客户端软件中展示的条码值,扫码设备扫描获取。1~32 位字符串。 + extra.put("scan_code", "280614577834623988"); + + // 可选,商品列表,上送格式参照下面示例。序列化后总字符串长度不超过 8000。 + List goodsList = goodsListForIsv(); + extra.put("goods_list", goodsList); + + return extra; + } + + private Map isvQrExtra() { + Map extra = new HashMap<>(); + // 必须,终端号,1~8 位英文或数字,要求不同终端此号码不一样,会显示在对账单中。 + extra.put("terminal_id", "A0000007"); + + // 必须,具体支付渠道,目前支持:alipay、wx、bfb。 + extra.put("pay_channel", "alipay"); + + // 可选,商品列表,上送格式参照下面示例。序列化后总字符串长度不超过 8000。 + List goodsList = goodsListForIsv(); + extra.put("goods_list", goodsList); + + return extra; + } + + private Map isvWapExtra() { + Map extra = new HashMap<>(); + // 必须,终端号,1~8 位英文或数字,要求不同终端此号码不一样,会显示在对账单中。 + extra.put("terminal_id", "A0000007"); + + // 必须,具体支付渠道,目前支持:alipay、wx、bfb。 + extra.put("pay_channel", "wx"); + + // 必须,前台通知地址,支付成功或失败后,跳转到的 URL。 + extra.put("result_url", "https://www.example.com/payment-result"); + + // 可选,商品列表,上送格式参照下面示例。 + List goodsList = goodsListForIsv(); + extra.put("goods_list", goodsList); + + return extra; + } + + private Map alipayScanExtra() { + Map extra = new HashMap<>(); + // 必填,客户端软件中展示的条码值,扫码设备扫描获取。 + extra.put("scan_code", "286801346868493272"); + // 必填,终端号,要求不同终端此号码不一样,会显示在对账单中,如A01、SH008等。 + extra.put("terminal_id", "SH008"); + // 可选,商户操作员编号(可包含字母、数字、下划线、中划线) + extra.put("operator_id", "yx_001"); + // 可选,商户门店编号(可包含字母、数字、下划线、中划线) + extra.put("store_id", "SH_001"); + // 可选,系统商编号 + extra.put("sys_service_provider_id", "2088511833207846"); + + // 可选,商品列表,上送格式参照下面示例。 + List goodsList = goodsListForAlipayScan(); + extra.put("goods_list", goodsList); + return extra; + } + + private Map wxPubScanExtra() { + Map extra = new HashMap<>(); + // 必填,客户端软件中展示的条码值,扫码设备扫描获取。 + extra.put("scan_code", "286801346868493272"); + // 可选,终端号,要求不同终端此号码不一样,会显示在对账单中,如A01、SH008等。 + extra.put("terminal_id", "SH008"); + // 可选,指定支付方式,指定不能使用信用卡支付可设置为 no_credit 。 + extra.put("limit_pay", "no_credit"); + // 可选,商品标记,代金券或立减优惠功能的参数。 + // extra.put("goods_tag", "your goods_tag"); + return extra; + } + + private Map cbAlipayExtra() { + Map extra = new HashMap<>(); + // 可选,支付类型。默认值为:1(商品购买)。 + extra.put("payment_type", 1); + + // 可选,分账列表。 + List list = new ArrayList<>(); + Map map = new HashMap<>(); + map.put("account", "2088866088886666"); // 接受分账资金的支付宝账户ID。 + map.put("amount", 1); // 分账的金额。 + map.put("desc", "split_desc desc"); // 分账描述信息。 + extra.put("split_fund_info", list); + return extra; + } + + private Map cbWxExtra() { + Map extra = new HashMap<>(); + // 可选,指定支付方式,指定不能使用信用卡支付可设置为 no_credit 。 + extra.put("limit_pay", "no_credit"); + + // 必填,商品列表 + List goodsList = goodsListForCbWx(); + extra.put("goods_list", goodsList); + return extra; + } + + private Map cbWxPubExtra() { + Map extra = new HashMap<>(); + // 可选,指定支付方式,指定不能使用信用卡支付可设置为 no_credit 。 + extra.put("limit_pay", "no_credit"); + // // 必填,用户在商户 appid 下的唯一标识。 + extra.put("open_id", "openidxxxxxxxxxxxx"); + // 必填,商品列表 + List goodsList = goodsListForCbWx(); + extra.put("goods_list", goodsList); + return extra; + } + + private Map cbWxPubQrExtra() { + Map extra = new HashMap<>(); + // 可选,指定支付方式,指定不能使用信用卡支付可设置为 no_credit + extra.put("limit_pay", "no_credit"); + // 必填,商品 ID,1-32 位字符串。此 id 为二维码中包含的商品 ID,商户可自定义。 + extra.put("product_id", "286801346868493272"); + // 必填,商品列表 + List goodsList = goodsListForCbWx(); + extra.put("goods_list", goodsList); + return extra; + } + + private Map cbWxPubScanExtra() { + Map extra = new HashMap<>(); + // 必填,客户端软件中展示的条码值,扫码设备扫描获取。 + extra.put("scan_code", "286801346868493272"); + // 可选,指定支付方式,指定不能使用信用卡支付可设置为 no_credit 。 + extra.put("limit_pay", "no_credit"); + // 可选,终端号,要求不同终端此号码不一样,会显示在对账单中,如A01、SH008等。 + extra.put("terminal_id", "SH008"); + // 必填,商品列表 + List goodsList = goodsListForCbWx(); + extra.put("goods_list", goodsList); + return extra; + } + + private List goodsListForIsv() { + List goodsList = new ArrayList<>(); + Map goods = new HashMap<>(); + goods.put("goods_id", "iphone6s16G"); // 商户定义商品编号(一般为商品条码)。 + goods.put("unified_goods_id", "1001"); // 统一商品编号,可选。 + goods.put("goods_name", "iPhone 6s 16G"); // 商品名称。 + goods.put("goods_num", 1); // 商品数量。 + goods.put("price", 528800); // 商品价格,单位为分。 + goods.put("goods_category", "smartphone"); // 商品类目,可选。 + goods.put("body", "苹果手机 iPhone 6s 16G"); // 商品描述信息,可选。 + goods.put("show_url", "https://www.example.com"); // 商品的展示网址,可选。 + goodsList.add(goods); + + return goodsList; + } + + private List goodsListForAlipayScan() { + List goodsList = new ArrayList<>(); + Map goods = new HashMap<>(); + goods.put("goods_id", "iphone"); // 商户定义商品编号(一般为商品条码)。 + goods.put("goods_name", "iPhone"); // 商品名称 + goods.put("quantity", 1); // 商品数量。 + goods.put("price", "528800"); // 商品价格,单位为分。 + goods.put("goods_category", "123456"); // 商品类目,可选。 + goods.put("body", "苹果手机"); // 商品描述信息,可选。 + goods.put("show_url", "https://www.example.com"); // 商品的展示网址,可选。 + goodsList.add(goods); + + return goodsList; + } + + private List goodsListForCbWx() { + List goodsList = new ArrayList<>(); + Map goods = new HashMap<>(); + goods.put("goods_name", "iPhone"); // 商品名称 + goods.put("goods_num", "1"); // 数量 + goodsList.add(goods); + return goodsList; + } +} diff --git a/example/src/main/java/com/pingxx/example/CustomsExample.java b/example/src/main/java/com/pingxx/example/CustomsExample.java new file mode 100644 index 0000000..82c67eb --- /dev/null +++ b/example/src/main/java/com/pingxx/example/CustomsExample.java @@ -0,0 +1,100 @@ +/** + * Ping++ Server SDK + * 说明: + * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。 + * 接入支付流程参考开发者中心:https://www.pingxx.com/docs/server/charge ,文档可筛选后端语言和接入渠道。 + * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。 + */ +package com.pingxx.example; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.Customs; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Customs 对象相关示例 + * + * 该实例程序演示了如何从 Ping++ 服务器创建 customs ,查询 customs。 + * + * 开发者需要填写 apiKey 和 appId , + * + * apiKey 有 TestKey 和 LiveKey 两种。 + * + * 报关(customs)仅支持 Live 模式。 + */ +public class CustomsExample { + + private String appId; + + CustomsExample(String appId) { + this.appId = appId; + } + + public static void runDemos(String appId) { + CustomsExample example = new CustomsExample(appId); + System.out.println("------- 报关 customs 仅支持 live 模式 -------"); + +// System.out.println("------- 创建 customs -------"); +// Customs obj = example.createCustoms(); +// System.out.println("------- 查询 customs -------"); +// example.retrieve(obj.getId()); + } + + /** + * 创建 Customs + * + * 创建 Customs 用户需要组装一个 map 对象作为参数传递给 Customs.create(); + * map 里面参数的具体说明请参考:https://www.pingxx.com/api + * @return Charge + */ + public Customs createCustoms() { + Customs obj = null; + Map params = new HashMap(); + params.put("channel", "alipay"); + String orderNo = new Date().getTime() + Main.randomString(7); + params.put("trade_no", orderNo); // 8-20 位,要求数字或字母,不允许其他字符 + params.put("customs_code", "SHANGHAI"); // https://www.pingxx.com/api#海关编号说明 + params.put("amount", 10000); // 报关金额, 人民币单位:分(如金额为 100 元,此处请填 10000) + params.put("charge", ""); + params.put("app", appId); + Map extra = new HashMap(); + // 根据不同渠道传不同参数 + // extra.put("pay_account", ""); + // extra.put("certif_type", "01"); // https://www.pingxx.com/api#报关接口 + // extra.put("customer_name", ""); + // extra.put("certif_id", ""); + params.put("extra", extra); + + try { + //发起交易请求 + obj = Customs.create(params); + System.out.println(obj); + } catch (PingppException e) { + e.printStackTrace(); + } + + return obj; + } + + /** + * 查询 Customs + * + * 参考文档:https://www.pingxx.com/api + * + * @param id + */ + public Customs retrieve(String id) { + Customs obj = null; + try { + obj = Customs.retrieve(id); + System.out.println(obj); + } catch (PingppException e) { + e.printStackTrace(); + } + + return obj; + } +} diff --git a/example/src/main/java/com/pingxx/example/EventExample.java b/example/src/main/java/com/pingxx/example/EventExample.java new file mode 100644 index 0000000..ef3e638 --- /dev/null +++ b/example/src/main/java/com/pingxx/example/EventExample.java @@ -0,0 +1,62 @@ +package com.pingxx.example; + +import java.util.HashMap; +import java.util.Map; + +import com.pingplusplus.exception.*; +import com.pingplusplus.model.Charge; +import com.pingplusplus.model.Event; +import com.pingplusplus.model.EventCollection; +import com.pingplusplus.model.Refund; +import com.pingplusplus.model.Summary; +import com.pingplusplus.model.Webhooks; + + +/** + * + * Event 事件参考文档:https://www.pingxx.com/api#api-event + * + * 该实例演示如何查询 Event + * + * apiKey 有 TestKey 和 LiveKey 两种。 + * + * TestKey 模式下不会产生真实的交易。 + * + */ +public class EventExample { + + public static void runDemos() { + EventExample eventExample = new EventExample(); + System.out.println("------- 查询 event -------"); + + String eventId = "evt_vTmGHwcHc842hWLRWNS4bwFM"; + eventExample.retrieve(eventId); + } + + /** + * 根据 ID 查询 Evnet + * + * 传递 Event 的 Id 查询 Event。 + * 参考文档:https://www.pingxx.com/api#api-event-inquiry + * @param id + */ + public void retrieve(String id) { + try { + Event event = Event.retrieve(id); + System.out.println(event); + + // 解析 webhooks 可以采用如下方法 +// Object obj = Webhooks.getObject(event.toString()); +// if (obj instanceof Charge) { +// System.out.println("webhooks 发送了 Charge"); +// } else if (obj instanceof Refund) { +// System.out.println("webhooks 发送了 Refund"); +// } else if (obj instanceof Summary) { +// System.out.println("webhooks 发送了 Summary"); +// } + } catch (PingppException e) { + e.printStackTrace(); + } + + } +} diff --git a/example/src/main/java/com/pingxx/example/IdentificationExample.java b/example/src/main/java/com/pingxx/example/IdentificationExample.java new file mode 100644 index 0000000..fef7986 --- /dev/null +++ b/example/src/main/java/com/pingxx/example/IdentificationExample.java @@ -0,0 +1,87 @@ +package com.pingxx.example; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.Identification; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * 身份证银行卡信息认证接口参考文档:https://www.pingxx.com/api#身份证银行卡信息认证接口 + * + * 该实例演示如何调用身份证银行卡信息认证接口 + * + */ +public class IdentificationExample { + + private String appId; + + IdentificationExample(String appId) { + this.appId = appId; + } + + public static void runDemos(String appId) { + IdentificationExample eventExample = new IdentificationExample(appId); + System.out.println("------- 认证身份证信息 -------"); + eventExample.identifyIdCard(); + + System.out.println("------- 认证银行卡信息 -------"); + eventExample.identifyBankCard(); + } + + /** + * 认证身份证信息 + * + * 参考文档:https://www.pingxx.com/api#请求认证接口 + */ + public void identifyIdCard() { + try { + Map params = new HashMap(); + params.put("app", appId); + params.put("type", "id_card"); // 身份证信息或者银行卡信息串,取值范围: "id_card"(身份证信息串);"bank_card"(银行卡信息串)。 + Map data = new HashMap(); + data.put("id_name", "张三"); + data.put("id_number", "320291198811110000"); + params.put("data", data); + Identification result = Identification.identify(params); + if (result.getResultCode() == 0) { + System.out.println("身份认证通过"); + } else { + System.out.println(result.getResultCode()); + System.out.println(result.getMessage()); + } + System.out.println(result); + } catch (PingppException e) { + e.printStackTrace(); + } + } + + /** + * 认证银行卡信息 + * + * 参考文档:https://www.pingxx.com/api#请求认证接口 + */ + public void identifyBankCard() { + try { + Map params = new HashMap(); + params.put("app", appId); + params.put("type", "bank_card"); // 身份证信息或者银行卡信息串,取值范围: "id_card"(身份证信息串);"bank_card"(银行卡信息串)。 + Map data = new HashMap(); + data.put("id_name", "张三"); + data.put("id_number", "320291198811110000"); + data.put("card_number", "6201111122223333"); + params.put("data", data); + Identification result = Identification.identify(params); + if (result.getResultCode() == 0) { + System.out.println("银行卡信息认证通过"); + } else { + System.out.println(result.getResultCode()); + System.out.println(result.getMessage()); + } + System.out.println(result); + } catch (PingppException e) { + e.printStackTrace(); + } + } +} diff --git a/example/src/main/java/com/pingxx/example/Main.java b/example/src/main/java/com/pingxx/example/Main.java new file mode 100644 index 0000000..c38f9f2 --- /dev/null +++ b/example/src/main/java/com/pingxx/example/Main.java @@ -0,0 +1,112 @@ +package com.pingxx.example; + +import com.pingplusplus.Pingpp; + +import java.math.BigInteger; +import java.net.URL; +import java.security.SecureRandom; + +/** + * Created by Afon on 16/4/26. + */ +public class Main { + + /** + * Pingpp 管理平台对应的 API Key,api_key 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击管理平台右上角公司名称->开发信息-> Secret Key + */ + private final static String apiKey = "sk_test_ibbTe5jLGCi5rzfH4OqPW9KC"; + + /** + * Pingpp 管理平台对应的应用 ID,app_id 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击你创建的应用->应用首页->应用 ID(App ID) + */ + private final static String appId = "app_1Gqj58ynP0mHeX1q"; + + /** + * 设置请求签名密钥,密钥对需要你自己用 openssl 工具生成,如何生成可以参考帮助中心:https://help.pingxx.com/article/123161; + * 生成密钥后,需要在代码中设置请求签名的私钥(rsa_private_key.pem); + * 然后登录 [Dashboard](https://dashboard.pingxx.com)->点击右上角公司名称->开发信息->商户公钥(用于商户身份验证) + * 将你的公钥复制粘贴进去并且保存->先启用 Test 模式进行测试->测试通过后启用 Live 模式 + */ + + // 你生成的私钥路径 + private final static String privateKeyFilePath = "res/your_rsa_private_key_pkcs8.pem"; + + private final static String verifyKeyFilePath = "pingpp_public_key.pem"; + + protected static String projectDir; + + public static void main(String[] args) throws Exception { + projectDir = System.getProperty("user.dir") + "/example/"; + + // 设置 API Key + Pingpp.apiKey = apiKey; + + Pingpp.appId = appId; + + // 设置私钥路径,用于请求签名 + //Pingpp.privateKeyPath = projectDir + privateKeyFilePath; + + /* + * 或者直接设置私钥内容 + * Pingpp.privateKey = "... PKCS8私钥内容字符串 ..."; + */ + Pingpp.privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDHYyS3FwoESp1hGLYiBhy6k9Ag3lzGCIEvm50IIEkE0Ftc9qq44TWqyl+EHUpTMdcBOcI42JLO5stwFOfCLa3PQStEJ4llIRFEKlsrHh67pvWd5RNaSBrvGlnFY40S+SZmjk2WF/h9dE9Ric79t0YI0alD8dIl9Yu3OaEKo7VonBWFwOYMxjPhtORlq+EUF1XJd//yftQrKWTTd7KaUonWzBCl4VzFop/OyTWYlTuZz3eYJaNpH5VaQ1vDgBAcPIeBvMf7NgBHMKW6LLmFd2LEYQ/6I7hkGTjysSzWEpO8bPWT6OEsJ2R2kFGOrSkr+G2MDcJ7ykXYAmz5+A3plS6ZAgMBAAECggEAVrgwR9GlcahiOtDcpn+yDxQq+aC9CQS561LrQZWJLKbSleRS7IZHKTlLwdJbeUO8F7RfXQoVEBghc2YkRrhHWFUn1ES95VY0hElHzcET7Nn5CeuQNzwVOtljIg7iVNY4dXJ/HEDguu/Tb8tYU9FajItj60FJ/WiGk/JksJPzWsOCVPVniy9fTbTLy1e+dCpCI6OXirtm7hvbodRNDjree0wSEzm7vL0wVzEZFo6kX+ABGUwaoO7pPyH+hgyI5Iuhc65NHsHzTJpf8yNFl9QGhkxvm2Ff2oEtDt1idOTBrHB6tg+ti9Ctb2+2yzBnk14hsSYJnKitR7wM6ZCFPX4eYQKBgQD+JAREeFkodec/SC+GX+4Q4Y68uMPkfUPrMKXM4cyY5wgXk64RBvRVxIxX7x6Y3tIKn9v8tWAprbsyVr15eb4RcAFEVwjuoZixhd9sIPsRhfdNolKn/fSPIsHL4ywcJMSIt7KVKHuQeqBNHy0o0PxQjNej1ozsmrAWqV55cbKHswKBgQDI2JQRTPIEC/2y6LdmBVhGJW9OKWTYdVNjq7rX+Yw4uxOtfd5hBqpvgZEklKEk72aazFdEcERlAm9SqoX09qk6zK/wcq4Xn5Q/qy8ecmjuyf2AK9X+HUdMerMVxhK9RpeevKYP/RO2F/wIN64anlQVYygVkXXgdOvWhBE4YABKgwKBgDRtmbPGYB5ItHwJmERQZfx1i8zDESaB8RED6DBsJJkmkDTM8ovws1c+RPWfDuDalto6QFfR0xTGEmhAHLaCtwNB6AEBM4aHL8jvpTfZVfI3gN0zL3oYmestcG1vYBouO504yE6dG2Ci6479b4OMGYFEjPfvuwLUpp8GMcc7/WihAoGANCp8mtm/ammq5VMof2kX+nAyrrx1ovsmQ5cRGpOIZhvBCqjMn6rZjci7aCLqj+tWXRKCABagzROK0o/T50JBxjHv6KYArcYW/Up7HI9ezdbM7wNzu2LjZ+veo+MkbuDs9J/PCgwTmJI2NfQwVl2VPVDZ0nBLi5cSwk7fIiNdL/0CgYEAtECmC1QDs53Di2MIsa/Fe4sWfJGSDqEWqhcA/aPwf1skM6VJJXBBMV1qFtwgO1AlLnu9dQYra6ylsUoubVYIXM9XK7EMhbqi57+Q75jHFTc0DnzOTyho5Gp4Ddi8dztmZGNWdWTGdeMqh+svqMXkD6VdJeddyGu/Zlgj7Wk6whU="; + + //(可选,推荐设置)设置响应验证公钥,用于验证响应是否真实有效;不设置或设置密钥错误将不验签 + Pingpp.setVerifyPublicKeyPath(getResPath(verifyKeyFilePath)); + + // Charge 示例 + ChargeExample.runDemos(appId); + + // Refund 示例 + RefundExample.runDemos(); + + // RedEnvelope 示例 + RedEnvelopeExample.runDemos(appId); + + // Transfer 示例 + TransferExample.runDemos(appId); + + // Event 示例 + EventExample.runDemos(); + + // Webhooks 验证示例 + WebhooksVerifyExample.runDemos(); + + // 微信公众号 openid 相关示例 + WxPubOAuthExample.runDemos(appId); + + // 身份证银行卡信息认证接口 + // 请使用 live key 调用该接口 + // IdentificationExample.runDemos(appId); + + // 批量付款示例 + BatchTransferExample.runDemos(appId); + + // 报关 + // 请使用 live key 调用该接口 + CustomsExample.runDemos(appId); + + //签约代扣示例 + AgreementExample.runDemos(appId); + } + + private static final SecureRandom random = new SecureRandom(); + + public static String randomString(int length) { + String str = new BigInteger(130, random).toString(32); + return str.substring(0, length); + } + + public static String getResPath(String subPath) { + if (subPath == null) { + throw new NullPointerException(); + } + URL resource = Thread.currentThread().getContextClassLoader().getResource(subPath); + return resource != null ? resource.getPath() : subPath; + } + + public static int currentTimeSeconds() { + return (int) (System.currentTimeMillis() / 1000); + } +} diff --git a/example/src/main/java/com/pingxx/example/RedEnvelopeExample.java b/example/src/main/java/com/pingxx/example/RedEnvelopeExample.java new file mode 100644 index 0000000..e741f1a --- /dev/null +++ b/example/src/main/java/com/pingxx/example/RedEnvelopeExample.java @@ -0,0 +1,123 @@ +/* * + * Ping++ Server SDK + * 说明: + * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。 + * 接入红包流程参考开发者中心:https://www.pingxx.com/docs/server/red-envelope ,文档可筛选后端语言和接入渠道。 + * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。 +*/ +package com.pingxx.example; + +import com.pingplusplus.exception.*; +import com.pingplusplus.model.RedEnvelope; +import com.pingplusplus.model.RedEnvelopeCollection; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * + * 该实例演示如何操作微信红包 + * + * 开发者需要填写 apiKey 、appId 和 openid , + * + * apiKey 有 TestKey 和 LiveKey 两种。 + * + * TestKey 模式下不会产生真实的交易。 + * + * openid 是发送红包的对象在公共平台下的 openid ,获得 openid 的方法可以参考微信文档:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html + * + */ +public class RedEnvelopeExample { + + private String appId; + /** + * 微信用户在微信公共号的 openid + */ + public static String openid = "USER_OPENID";// 用户在商户微信公众号下的唯一标识,获取方式可参考 WxPubOAuthExample.java + + RedEnvelopeExample(String appId) { + this.appId = appId; + } + + public static void runDemos(String appId) { + + RedEnvelopeExample redEnvelopeExample = new RedEnvelopeExample(appId); + System.out.println("------- 创建 RedEnvelope -------"); + RedEnvelope redEnvelope = redEnvelopeExample.create(); + System.out.println("------- 查询 RedEnvelope -------"); + redEnvelopeExample.retrieve(redEnvelope.getId()); + System.out.println("------- 查询 RedEnvelope 列表 -------"); + redEnvelopeExample.list(); + } + + /** + * 创建红包 + * + * 创建红包需要传递一个 map 到 RedEnvelope.create(redenvelope) + * map 里面的具体参数参考:https://www.pingxx.com/api#api-e-new + * @return + */ + public RedEnvelope create() { + Map redenvelope = new HashMap(); + redenvelope.put("amount", 100);// 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100,金额限制在 100 ~ 20000 之间,即 1 ~ 200 元) + redenvelope.put("currency", "cny"); + redenvelope.put("subject", "Your Subject"); + redenvelope.put("body", "Your Body"); + String orderNo = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date()); + redenvelope.put("order_no", orderNo);// 红包使用的商户订单号。wx_pub 规定为 1 ~ 28 位不能重复的数字 + redenvelope.put("channel", "wx_pub");// 目前支持 wx_pub + redenvelope.put("recipient", openid);// 接收者 id, 为用户在 wx_pub 下的 open_id + redenvelope.put("description", "Your Description"); + Map app = new HashMap(); + app.put("id", appId); + redenvelope.put("app", app); + Map extra = new HashMap(); + extra.put("send_name", "Send Name");// 商户名称,最多 32 个字节 + redenvelope.put("extra", extra); + RedEnvelope red = null; + try { + red = RedEnvelope.create(redenvelope); + System.out.println(red); + } catch (PingppException e) { + e.printStackTrace(); + } + return red; + + } + + /** + * 查询红包 + * + * 根据红包的 ID 查询红包。 + * 参考文档:https://www.pingxx.com/api#api-e-inquiry + * @param id + */ + public void retrieve(String id) { + try { + RedEnvelope redEnvelope = RedEnvelope.retrieve(id); + System.out.println(redEnvelope); + } catch (PingppException e) { + e.printStackTrace(); + } + } + + /** + * 批量查询红包 + * + * 批量查询接口,默认一次查询 10 条。用户可以通过 limit 自定义查询数目,最多不超过 100 条。 + */ + public void list() { + RedEnvelopeCollection redEnvelopeCollection = null; + Map chargeParams = new HashMap(); + chargeParams.put("limit", 3); + try { + redEnvelopeCollection = RedEnvelope.list(chargeParams); + System.out.println(redEnvelopeCollection); + } catch (PingppException e) { + e.printStackTrace(); + } + + } +} diff --git a/example/SimpleExample/src/main/java/com/pingxx/example/RefundExample.java b/example/src/main/java/com/pingxx/example/RefundExample.java similarity index 54% rename from example/SimpleExample/src/main/java/com/pingxx/example/RefundExample.java rename to example/src/main/java/com/pingxx/example/RefundExample.java index 8b7e554..0c15f5b 100644 --- a/example/SimpleExample/src/main/java/com/pingxx/example/RefundExample.java +++ b/example/src/main/java/com/pingxx/example/RefundExample.java @@ -7,11 +7,7 @@ */ package com.pingxx.example; -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; +import com.pingplusplus.exception.*; import com.pingplusplus.model.Charge; import com.pingplusplus.model.ChargeRefundCollection; import com.pingplusplus.model.Refund; @@ -32,22 +28,10 @@ */ public class RefundExample { - private Charge charge; + private String charge; RefundExample(String chargeId) { - try { - this.charge = Charge.retrieve(chargeId); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } + this.charge = chargeId; } public static void runDemos() { @@ -55,10 +39,10 @@ public static void runDemos() { String chargeId = "ch_5CWrz5rnz9GS84arXHLiPOqL"; RefundExample refundExample = new RefundExample(chargeId); - System.out.println("------- 创建 refund -------"); - Refund refund = refundExample.refund(1); - System.out.println("------- 查询 refund -------"); - refundExample.retrieve(refund.getId()); +// System.out.println("------- 创建 refund -------"); +// Refund refund = refundExample.refund(1); +// System.out.println("------- 查询 refund -------"); +// refundExample.retrieve(refund.getId()); System.out.println("------- 查询 refund 列表 -------"); refundExample.all(); } @@ -67,7 +51,7 @@ public static void runDemos() { * 退款 * * 创建退款,需要先获得 charge ,然后调用 charge.getRefunds().create(); - * 参数具体说明参考:https://pingxx.com/document/api#api-r-new + * 参数具体说明参考:https://www.pingxx.com/api#api-r-new * * 可以一次退款,也可以分批退款。 * @@ -84,20 +68,11 @@ public Refund refund(Integer amount) { params.put("amount", amount);// 退款的金额, 单位为对应币种的最小货币单位,例如:人民币为分(如退款金额为 1 元,此处请填 100)。必须小于等于可退款金额,默认为全额退款 try { - refund = charge.getRefunds().create(params); + refund = Refund.create(this.charge, params); System.out.println(refund); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { + } catch (PingppException e) { e.printStackTrace(); - } catch (ChannelException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + } return refund; } @@ -105,7 +80,7 @@ public Refund refund(Integer amount) { * 查询退款 * * 根据 Id 查询退款记录。需要传递 charge。 - * 参考文档:https://pingxx.com/document/api#api-r-inquiry + * 参考文档:https://www.pingxx.com/api#api-r-inquiry * * @param id */ @@ -114,26 +89,18 @@ public void retrieve(String id) { return; } try { - Refund refund = charge.getRefunds().retrieve(id); + Refund refund = Refund.retrieve(this.charge, id); System.out.println(refund); - } catch (AuthenticationException e) { - e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { + } catch (PingppException e) { e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } + } } /** * 分页查询退款 * * 批量查询退款。默认一次 10 条,用户可以通过 limit 自定义查询数目,但是最多不超过 100 条。 - * 参考文档:https://pingxx.com/document/api#api-r-list + * 参考文档:https://www.pingxx.com/api#api-r-list * */ public void all() { @@ -143,18 +110,10 @@ public void all() { Map refundParams = new HashMap(); refundParams.put("limit", 3); try { - ChargeRefundCollection refunds = charge.getRefunds().all(refundParams); + ChargeRefundCollection refunds = Refund.list(this.charge, refundParams); System.out.println(refunds); - } catch (AuthenticationException e) { + } catch (PingppException e) { e.printStackTrace(); - } catch (InvalidRequestException e) { - e.printStackTrace(); - } catch (APIConnectionException e) { - e.printStackTrace(); - } catch (APIException e) { - e.printStackTrace(); - } catch (ChannelException e) { - e.printStackTrace(); - } + } } } diff --git a/example/src/main/java/com/pingxx/example/TransferExample.java b/example/src/main/java/com/pingxx/example/TransferExample.java new file mode 100644 index 0000000..ba01da1 --- /dev/null +++ b/example/src/main/java/com/pingxx/example/TransferExample.java @@ -0,0 +1,279 @@ +/* * + * Ping++ Server SDK + * 说明: + * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。 + * 接入企业付款流程参考开发者中心:https://www.pingxx.com/docs/server/transfer ,文档可筛选后端语言和接入渠道。 + * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。 +*/ +package com.pingxx.example; + +import com.pingplusplus.exception.*; +import com.pingplusplus.model.Transfer; +import com.pingplusplus.model.TransferCollection; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * + * 该实例演示如何使用 Ping++ 进行企业转账。 + * + * 开发者需要填写 apiKey ,openid 和 appId , + * + * apiKey 有 TestKey 和 LiveKey 两种。 + * + * TestKey 模式下不会产生真实的交易。 + * + * openid 是发送红包的对象在公共平台下的 openid ,获得 openid 的方法可以参考微信文档:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html + * + */ +public class TransferExample { + + private String appId; + + /** + * 接收者的 openid + */ + public static String openid = "USER_OPENID"; // 用户在商户微信公众号下的唯一标识,获取方式可参考 WxPubOAuthExample.java + + public static void runDemos(String appId) { + + TransferExample transferExample = new TransferExample(appId); + System.out.println("------- 创建 Transfer -------"); + Transfer transfer = transferExample.create(); + System.out.println("------- 查询 Transfer -------"); + transferExample.retrieve(transfer.getId()); + System.out.println("------- 查询 Transfer 列表 -------"); + transferExample.list(); + + } + + TransferExample(String appId) { + this.appId = appId; + } + + /** + * 创建企业转账 + * + * 创建企业转账需要传递一个 map 给 Transfer.create(); + * map 填写的具体介绍可以参考:https://www.pingxx.com/api#api-t-new + * + * @return + */ + public Transfer create() { + Transfer transfer = null; + String channel = "alipay"; + + String orderNo = new SimpleDateFormat("yyyyMMddhhmmss").format(new Date()); + Map transferMap = new HashMap(); + transferMap.put("channel", channel); // 目前支持 支付宝:alipay,银联:unionpay,微信公众号:wx_pub,通联:allinpay,京东:jdpay + + // 付款使用的商户内部订单号。 + // wx_pub 规定为 1 ~ 50 位不能重复的数字字母组合; + // alipay 为 1 ~ 64 位不能重复的数字字母组合; + // unionpay 为 1 ~ 16 位的纯数字; + // jdpay 限长 1 ~ 64 位不能重复的数字字母组合; + // allinpay 限长 20 ~ 40 位不能重复的数字字母组合,必须以签约的通联的商户号开头(建议组合格式:通联商户号 + 时间戳 + 固定位数顺序流水号,不包含+号) + + if (channel == "allinpay") { + orderNo += System.currentTimeMillis(); + } + + transferMap.put("order_no", orderNo); + transferMap.put("amount", 200); // 付款金额,相关渠道的限额,请查看 https://help.pingxx.com/article/133366/ 。单位为对应币种的最小货币单位,例如:人民币为分。 + transferMap.put("type", "b2c"); // 付款类型,转账到个人用户为 b2c,转账到企业用户为 b2b(微信公众号 wx_pub 的企业付款,仅支持 b2c)。 + transferMap.put("currency", "cny"); + transferMap.put("recipient", channelRecipient(channel)); // 接收者 + + // 备注信息。 + // 渠道为 unionpay 时,最多 99 个 Unicode 字符; + // 渠道为 wx_pub 时,最多 99 个英文和数字的组合或最多 33 个中文字符,不可以包含特殊字符; + // 渠道为 alipay 时,最多 100 个 Unicode 字符。 + // 渠道为 jdpay 最多100个 Unicode 字符。 + // 渠道为 allinpay 最多30个 Unicode 字符 + transferMap.put("description", "your description"); + + transferMap.put("extra", channelExtra(channel)); + + Map app = new HashMap(); + app.put("id", appId); + transferMap.put("app", app); + + try { + transfer = Transfer.create(transferMap); + System.out.println(transfer); + } catch (PingppException e) { + e.printStackTrace(); + } + return transfer; + } + + /** + * 根据 ID 查询 + * + * 根据 ID 查询企业转账记录。 + * 参考文档:https://www.pingxx.com/api#api-t-inquiry + * @param id + */ + public void retrieve(String id) { + Map param = new HashMap(); + try { + Transfer transfer = Transfer.retrieve(id, param); + System.out.println(transfer); + } catch (PingppException e) { + e.printStackTrace(); + } + + } + + /** + * 批量查询 + * + * 批量查询企业转账记录,默认一次查询 10 条,用户可以使用 limit 自定义查询数目,但是最多不超过 100 条。 + */ + public void list() { + Map param = new HashMap(); + param.put("limit", 3); + param.put("app[id]", appId); + + try { + TransferCollection transferCollection = Transfer.list(param); + System.out.println(transferCollection); + } catch (PingppException e) { + e.printStackTrace(); + } + } + + private String channelRecipient(String channel) { + String recipient = null; + + switch (channel) { + case "wx_pub": + // 渠道为 wx_pub 时,需要传 recipient 为用户在商户 appid 下的 open_id + recipient = "o7xEMsySBFG3MVHI-9VsAJX-j50W"; + break; + case "alipay": + // 渠道为 alipay 时,若 type 为 b2c,为个人支付宝账号,若 type 为 b2b,为企业支付宝账号。 + recipient = "alipayaccount@gmail.com"; + break; + case "unionpay": + case "allinpay": + case "jdpay": + break; + } + + return recipient; + } + + private Map channelExtra(String channel) { + Map extra = new HashMap<>(); + + switch (channel) { + case "alipay": + extra = alipayExtra(); + break; + case "wx_pub": + extra = wxPubExtra(); + break; + case "unionpay": + extra = unionpayExtra(); + break; + case "allinpay": + extra = allinpayExtra(); + break; + case "jdpay": + extra = jdpayExtra(); + break; + } + + return extra; + } + + private Map alipayExtra() { + Map extra = new HashMap<>(); + // 必须,收款人姓名,1~50位。 + extra.put("recipient_name", "张三"); + + // 可选,收款方账户类型。可取值:1、 ALIPAY_USERID :支付宝账号对应的支付宝唯一用户号。以2088开头的16位纯数字组成。 2、 ALIPAY_LOGONID (默认值):支付宝登录号,支持邮箱和手机号格式。 + // extra.put("recipient_account_type", "ALIPAY_LOGONID"); + + return extra; + } + + private Map wxPubExtra() { + Map extra = new HashMap<>(); + // 可选,收款人姓名。当该参数为空,则不校验收款人姓名。 + // extra.put("user_name", "张三"); + + // 可选,是否强制校验收款人姓名。仅当 user_name 参数不为空时该参数生效。 + // extra.put("force_check", true); + + return extra; + } + + private Map unionpayExtra() { + Map extra = new HashMap<>(); + // 必须,1~32位,收款人银行卡号或者存折号。 + extra.put("card_number", "6228480402564890011"); + + // 必须,1~100位,收款人姓名。 + extra.put("user_name", "张三"); + + /** + * open_bank_code 和 open_bank 两个参数必传一个,建议使用 open_bank_code ,若都传参则优先使用 open_bank_code 读取规则;prov 和 city 均为可选参数,如果不传参,则使用默认值 "上海" 给渠道接口。 + */ + + // 条件可选,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:https://www.pingxx.com/api#%E9%93%B6%E8%A1%8C%E7%BC%96%E5%8F%B7%E8%AF%B4%E6%98%8E。 + extra.put("open_bank_code", "0103"); + + // 条件可选,1~50位,开户银行,详情请参考 企业付款(银行卡)银行编号说明:https://www.pingxx.com/api#%E9%93%B6%E8%A1%8C%E7%BC%96%E5%8F%B7%E8%AF%B4%E6%98%8E。 + extra.put("open_bank", "农业银行"); + + // 可选,1~20位,省份。 + // extra.put("prov", "上海"); + + // 可选,1~40位,城市。 + // extra.put("city", "上海"); + + // 可选,1~80位,开户支行名称。 + // extra.put("sub_bank", "上海陆家嘴支行"); + + return extra; + } + + private Map allinpayExtra() { + Map extra = new HashMap<>(); + // 必须,1~32位,收款人银行卡号或者存折号。 + extra.put("card_number", "6228480402564890011"); + + // 必须,1~100位,收款人姓名。 + extra.put("user_name", "张三"); + + // 必须,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:https://www.pingxx.com/api#%E9%93%B6%E8%A1%8C%E7%BC%96%E5%8F%B7%E8%AF%B4%E6%98%8E。 + extra.put("open_bank_code", "0103"); + + // 可选,5位,业务代码,根据通联业务人员提供,不填使用通联提供默认值09900。 + // extra.put("business_code", "09900"); + + // 可选,1位,银行卡号类型,0:银行卡、1:存折,不填默认使用银行卡。 + // extra.put("card_type", 0); + + return extra; + } + + private Map jdpayExtra() { + Map extra = new HashMap<>(); + // 必须,1~32位,收款人银行卡号或者存折号。 + extra.put("card_number", "6228480402564890011"); + + // 必须,1~100位,收款人姓名。 + extra.put("user_name", "张三"); + + // 必须,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:https://www.pingxx.com/api#%E9%93%B6%E8%A1%8C%E7%BC%96%E5%8F%B7%E8%AF%B4%E6%98%8E。 + extra.put("open_bank_code", "0103"); + + return extra; + } +} diff --git a/example/src/main/java/com/pingxx/example/WebhooksVerifyExample.java b/example/src/main/java/com/pingxx/example/WebhooksVerifyExample.java new file mode 100644 index 0000000..891e1ed --- /dev/null +++ b/example/src/main/java/com/pingxx/example/WebhooksVerifyExample.java @@ -0,0 +1,50 @@ +/* * + * Ping++ Server SDK + * 说明: + * 以下代码只是为了方便商户测试而提供的样例代码,商户可根据自己网站需求按照技术文档编写, 并非一定要使用该代码。 + * 接入 webhooks 流程参考开发者中心:https://www.pingxx.com/docs/webhooks/webhooks + * 该代码仅供学习和研究 Ping++ SDK 使用,仅供参考。 + */ +package com.pingxx.example; + +import com.pingplusplus.Pingpp; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.util.PingppSignature; + +/** + * webhooks 验证签名示例 + *

+ * 该实例演示如何对 Ping++ webhooks 通知进行验证。 + * 验证是为了让开发者确认该通知来自 Ping++ ,防止恶意伪造通知。用户如果有别的验证机制,可以不进行验证签名。 + *

+ * 验证签名需要 签名、公钥、验证信息,该实例采用文件存储方式进行演示。 + * 实际项目中,需要用户从异步通知的 HTTP header 中读取签名,从 HTTP body 中读取验证信息。公钥的存储方式也需要用户自行设定。 + *

+ * 该实例仅供演示如何验证签名,请务必不要直接 copy 到实际项目中使用。 + */ +public class WebhooksVerifyExample { + /** + * 验证 webhooks 签名,仅供参考 + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + runDemos(); + } + + public static void runDemos() throws Exception { + String verifyPublicKey = Pingpp.verifyPublicKey; + // 该数据请从 request 中获取原始 POST 请求数据, 以下仅作为示例 + String webhooksRawPostData = "{\"id\":\"evt_400240816160755820469807\",\"created\":1723795675,\"livemode\":false,\"type\":\"charge.succeeded\",\"data\":{\"object\":{\"id\":\"ch_100240816592822384640019\",\"object\":\"charge\",\"created\":1723795492,\"livemode\":false,\"paid\":true,\"refunded\":false,\"reversed\":false,\"app\":\"app_eTC8yLuj9GSSL0yv\",\"channel\":\"wx_pub\",\"order_no\":\"1723795491985uqclqj7\",\"client_ip\":\"127.0.0.1\",\"amount\":100,\"amount_settle\":100,\"currency\":\"cny\",\"subject\":\"Your Subject\",\"body\":\"Your Body\",\"extra\":{\"open_id\":\"o7xEMsySBFG3MVHI-9VsAJX-j50W\",\"limit_pay\":\"no_credit\",\"bank_type\":\"your bank type\"},\"time_paid\":1723795675,\"time_expire\":1723802692,\"time_settle\":null,\"transaction_no\":\"1290362656202408163243920572\",\"refunds\":{\"object\":\"list\",\"url\":\"/v1/charges/ch_100240816592822384640019/refunds\",\"has_more\":false,\"data\":[]},\"amount_refunded\":0,\"failure_code\":null,\"failure_msg\":null,\"metadata\":{},\"credential\":{},\"description\":null}},\"object\":\"event\",\"request\":\"iar_mrrvj9ivPOaHPOi9aLPWPqvT\",\"pending_webhooks\":0}"; + System.out.println("------- POST 原始数据 -------"); + System.out.println(webhooksRawPostData); + // 签名数据请从 request 的 header 中获取, key 为 X-Pingplusplus-Signature (请忽略大小写, 建议自己做格式化) + String signature = "Ju5ItDM9Hblkm6Pbb/r3G9iM58oCtAUJlJDrOud0E23TUtGBxKYJSMcuTFbPgLGLKy5QHYovJJojjMjM1CMGCp82F+SOY1U2zuwzkAk0lVqhfQk+CWGpcyUzOtLOOblKidyuIb+axZDTIg4kK/JoOR2xMH3+cJD9BN6rtfzEDbHqyZIfv6n3y/LdZNhsXfQq+qoIRuLdHrFexk1USgk7SXFvH1pCOIt8o2+dryp/ixlNj1vGq57eE8sbEzPo72vxLtzPazlgR+67cS1bUxjzObh7YFbSSTJxkHDEIi3ipTpoiI7Kc5ng7EzsWgp3cAl7on5HztfFLfT8+Bjpdvtr6w=="; + System.out.println("------- 签名 -------"); + System.out.println(signature); + + boolean result = PingppSignature.verify(signature, webhooksRawPostData, verifyPublicKey, APIResource.CHARSET.name()); + System.out.println("验签结果:" + (result ? "通过" : "失败")); + } +} diff --git a/example/SimpleExample/src/main/java/com/pingxx/example/WxPubOAuthExample.java b/example/src/main/java/com/pingxx/example/WxPubOAuthExample.java similarity index 64% rename from example/SimpleExample/src/main/java/com/pingxx/example/WxPubOAuthExample.java rename to example/src/main/java/com/pingxx/example/WxPubOAuthExample.java index 03b2e33..9b56190 100644 --- a/example/SimpleExample/src/main/java/com/pingxx/example/WxPubOAuthExample.java +++ b/example/src/main/java/com/pingxx/example/WxPubOAuthExample.java @@ -1,11 +1,8 @@ package com.pingxx.example; import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.Map; -import com.pingplusplus.Pingpp; -import com.pingplusplus.exception.PingppException; +import com.pingplusplus.exception.ChannelException; import com.pingplusplus.model.Charge; import com.pingplusplus.util.WxpubOAuth; @@ -23,23 +20,23 @@ */ public class WxPubOAuthExample { - /** - * Ping++ 管理平台对应的应用 ID,app_id 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击你创建的应用->应用首页->应用 ID(App ID) - */ - private static String appId; + /** + * Ping++ 管理平台对应的应用 ID,app_id 获取方式:登录 [Dashboard](https://dashboard.pingxx.com)->点击你创建的应用->应用首页->应用 ID(App ID) + */ + private static String appId; - /** - * 微信公共号里面获取 openid 时的回跳 URL - */ - public static String redirectUrl = "YOUR_URL"; - /** - * 微信公共号的 appId,通常为 `wx` 开头的字符串 - */ - public static String wxAppId="YOUR_WX_APP_ID"; - /** - * 微信公共号的 secret - */ - public static String wxAppSecret ="YOUR_WX_APP_SECRET"; + /** + * 微信公共号里面获取 openid 时的回跳 URL + */ + public static String redirectUrl = "YOUR_URL"; + /** + * 微信公共号的 appId,通常为 `wx` 开头的字符串 + */ + public static String wxAppId="YOUR_WX_APP_ID"; + /** + * 微信公共号的 secret + */ + public static String wxAppSecret ="YOUR_WX_APP_SECRET"; public static void runDemos(String appId) throws UnsupportedEncodingException { WxPubOAuthExample.appId = appId; @@ -50,7 +47,7 @@ public static void runDemos(String appId) throws UnsupportedEncodingException { jsapiSignatureDemo(); } - public static void getOpenid() throws UnsupportedEncodingException { + public static void getOpenid() throws UnsupportedEncodingException { System.out.println("1. 你需要有一个处理回跳的 URL"); redirectUrl = "http://用于处理回跳的URL"; @@ -65,11 +62,16 @@ public static void getOpenidWithCode() throws UnsupportedEncodingException { System.out.println("3. 微信内置浏览器会带上参数 code 跳转到你传的地址: " + redirectUrl + "?code=os823ndskelcncfyfms"); // 获取 URL 中的 code 参数 String code = "os823ndskelcncfyfms"; - String openid = WxpubOAuth.getOpenId(wxAppId, wxAppSecret, code); - System.out.println("4. 得到 openid 用于创建 charge"); - ChargeExample chargeExample = new ChargeExample(appId); - openid = "USER_OPENID"; - chargeExample.createChargeWithOpenid(openid); + try { + String openid = WxpubOAuth.getOpenId(wxAppId, wxAppSecret, code); + System.out.println("4. 得到 openid 用于创建 charge"); + } catch (ChannelException e) { + e.printStackTrace(); + } + +// ChargeExample chargeExample = new ChargeExample(appId); +// openid = "USER_OPENID"; +// chargeExample.createCharge(); } public static void jsapiSignatureDemo() throws UnsupportedEncodingException { @@ -78,7 +80,7 @@ public static void jsapiSignatureDemo() throws UnsupportedEncodingException { System.out.println("ticket " + ticket); // 创建 Charge ChargeExample chargeExample = new ChargeExample(appId); - Charge charge = chargeExample.createChargeWithOpenid("USER_OPENID"); + Charge charge = chargeExample.createCharge(); // wx_pub // 获得签名 String signature = WxpubOAuth.getSignature(charge.toString(), ticket, redirectUrl); System.out.println("------- JSAPI 签名 -------"); diff --git a/example/src/main/resources/pingpp_public_key.pem b/example/src/main/resources/pingpp_public_key.pem new file mode 100644 index 0000000..c0f5d19 --- /dev/null +++ b/example/src/main/resources/pingpp_public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCJqcTaGUab0vBZSkGNE1AaGiY +RcbPd7QdCQuM8EpbEpEQGr9/NjbJHCLd3eaUmYM0vy34Wux+VHnw4ckiDfBuW6/Z +fIo5GBRCI/nZLOnWcOX98ZAXYnn/VVJXuBtHtHL8DWEbYmMp+Gl4k1rFSuQKk52k +YLXeFJZJV8CBV5jA+wIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..6ffa237 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..68566cb --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Dec 16 11:18:35 HKT 2016 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://mirrors.aliyun.com/macports/distfiles/gradle/gradle-8.6-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..9aa616c --- /dev/null +++ b/gradlew @@ -0,0 +1,169 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [[ "$(uname)" == "Darwin" ]] && [[ "$HOME" == "$PWD" ]]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/libs/pingpp-java-2.1.7.jar b/libs/pingpp-java-2.1.7.jar deleted file mode 100644 index 1438238..0000000 Binary files a/libs/pingpp-java-2.1.7.jar and /dev/null differ diff --git a/libs/pingpp-sdk-2.5.3.jar b/libs/pingpp-sdk-2.5.3.jar new file mode 100644 index 0000000..72f00e6 Binary files /dev/null and b/libs/pingpp-sdk-2.5.3.jar differ diff --git a/pingpp-sdk/build.gradle b/pingpp-sdk/build.gradle new file mode 100644 index 0000000..cd44911 --- /dev/null +++ b/pingpp-sdk/build.gradle @@ -0,0 +1,52 @@ +buildscript { + repositories { + maven { + url 'https://maven.aliyun.com/repository/central' + } + mavenLocal() + mavenCentral() + } +} + +plugins { + id "maven-publish" + id "java" +} + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +configurations { + compileOnly { + extendsFrom annotationProcessor + } + testCompileOnly { + extendsFrom testAnnotationProcessor + } +} + +dependencies { + implementation 'com.google.code.gson:gson:2.10' + implementation 'commons-codec:commons-codec:1.17.0' + testImplementation 'junit:junit:4.13.2' +} + +java { + withSourcesJar() +} + +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + versionMapping { + usage('java-api') { + fromResolutionOf('runtimeClasspath') + } + usage('java-runtime') { + fromResolutionResult() + } + } + } + } +} \ No newline at end of file diff --git a/pingpp-sdk/pom.xml b/pingpp-sdk/pom.xml new file mode 100644 index 0000000..ab60a11 --- /dev/null +++ b/pingpp-sdk/pom.xml @@ -0,0 +1,123 @@ + + + 4.0.0 + + com.pingxx + pingpp-java + 2.5.6 + jar + + pingpp-java + A Java SDK for Ping++ Payment API. + https://github.com/PingPlusPlus/pingpp-java + + + Apache License 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + repo + + + + + scm:git:https://github.com/PingPlusPlus/pingpp-java.git + + + + afon + Afon + xufeng.weng@pingxx.com + + + + + 1.8 + 1.8 + + + + + com.google.code.gson + gson + 2.10.1 + compile + + + commons-codec + commons-codec + 1.17.0 + compile + + + junit + junit + 4.13.2 + test + + + + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.3.1 + + + attach-sources + + jar-no-fork + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.11.2 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 3.2.8 + + + sign-artifacts + verify + + sign + + + ${gpg.keyname} + ${gpg.passphrase} + + --pinentry-mode + loopback + + + + + + + org.sonatype.central + central-publishing-maven-plugin + 0.8.0 + true + + central + true + + + + + diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/Pingpp.java b/pingpp-sdk/src/main/java/com/pingplusplus/Pingpp.java new file mode 100644 index 0000000..444f8b4 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/Pingpp.java @@ -0,0 +1,161 @@ +package com.pingplusplus; + +import com.pingplusplus.net.APIResource; +import com.pingplusplus.util.StreamUtils; + +import java.io.FileInputStream; +import java.io.IOException; + +/** + * Ping++ Base class + */ +public abstract class Pingpp { + /** + * Ping++ API BASE URL + */ + public static final String LIVE_API_BASE = "https://api.pingxx.com"; + /** + * version + */ + public static final String VERSION = "2.5.6"; + /** + * api key + */ + public static volatile String apiKey; + + public static volatile String appId; + + public static String acceptLanguage = "zh-CN"; + + private static volatile String apiBase = LIVE_API_BASE; + + public static volatile String privateKey; + public static volatile String verifyPublicKey; + public static volatile String privateKeyPath; + + public static Boolean DEBUG = false; + + public static final int DEFAULT_CONNECT_TIMEOUT = 30 * 1000; + public static final int DEFAULT_READ_TIMEOUT = 80 * 1000; + + private static volatile int connectTimeout = -1; + private static volatile int readTimeout = -1; + + private static volatile int maxNetworkRetries = 1; + + /** + * (FOR TESTING ONLY) + * If you'd like your API requests to hit your own (mocked) server, + * you can set this up here by overriding the base api URL. + * @param overriddenApiBase API 地址 + */ + public static void overrideApiBase(final String overriddenApiBase) { + apiBase = overriddenApiBase; + } + + /** + * get api url + * + * @return String api url + */ + public static String getApiBase() { + return apiBase; + } + + /** + * set api url + * + * @param apiBase apiBase API 地址 + */ + public static void setApiBase(String apiBase) { + Pingpp.apiBase = apiBase; + } + + /** + * 网络连接超时时间 + * + * @return timeout value in milliseconds + */ + public static int getConnectTimeout() { + if (connectTimeout == -1) { + return DEFAULT_CONNECT_TIMEOUT; + } + return connectTimeout; + } + + /** + * 设置网络连接超时时间 (毫秒) + * + * @param timeout timeout value in milliseconds + */ + public static void setConnectTimeout(final int timeout) { + connectTimeout = timeout; + } + + /** + * 数据读取超时时间 + * + * @return timeout value in milliseconds + */ + public static int getReadTimeout() { + if (readTimeout == -1) { + return DEFAULT_READ_TIMEOUT; + } + return readTimeout; + } + + /** + * 设置数据读取超时时间 (毫秒) + * 不同接口的耗时时间不一样,部分接口的耗时可能比较长。 + * + * @param timeout timeout value in milliseconds + */ + public static void setReadTimeout(final int timeout) { + readTimeout = timeout; + } + + /** + * 连接失败时的最大重试次数 + * + * @return the maximum number of times requests will be retried + */ + public static int getMaxNetworkRetries() { + return maxNetworkRetries; + } + + /** + * 设置连接失败时的最大重试次数 + * + * @param numRetries the maximum number of times requests will be retried + */ + public static void setMaxNetworkRetries(final int numRetries) { + maxNetworkRetries = numRetries; + } + + public static String getAcceptLanguage() { + return acceptLanguage; + } + + public static void setAcceptLanguage(String acceptLanguage) { + Pingpp.acceptLanguage = acceptLanguage; + } + + public static void setVerifyPublicKeyPath(String keyFilePath) throws IOException { + Pingpp.verifyPublicKey = readKeyFromFilePath(keyFilePath); + } + + /** + * 读取密钥文件 + * + * @param filePath 文件路径 + * @return 密钥内容 + * @throws IOException IO 异常 + */ + private static String readKeyFromFilePath(String filePath) throws IOException { + FileInputStream inputStream = new FileInputStream(filePath); + String privateKey = StreamUtils.readToEnd(inputStream, APIResource.CHARSET); + inputStream.close(); + + return privateKey; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/exception/APIConnectionException.java b/pingpp-sdk/src/main/java/com/pingplusplus/exception/APIConnectionException.java new file mode 100644 index 0000000..556945e --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/exception/APIConnectionException.java @@ -0,0 +1,15 @@ +package com.pingplusplus.exception; + +public class APIConnectionException extends PingppException { + + private static final long serialVersionUID = 2L; + + public APIConnectionException(String message) { + super(message); + } + + public APIConnectionException(String message, Throwable e) { + super(message, e); + } + +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/exception/APIException.java b/pingpp-sdk/src/main/java/com/pingplusplus/exception/APIException.java new file mode 100644 index 0000000..1c5095d --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/exception/APIException.java @@ -0,0 +1,10 @@ +package com.pingplusplus.exception; + +public class APIException extends PingppException { + + private static final long serialVersionUID = 2L; + + public APIException(String message, String type, String code, int statusCode, Throwable e) { + super(message, type, code, statusCode, e); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/exception/AuthenticationException.java b/pingpp-sdk/src/main/java/com/pingplusplus/exception/AuthenticationException.java new file mode 100644 index 0000000..42681d0 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/exception/AuthenticationException.java @@ -0,0 +1,16 @@ +package com.pingplusplus.exception; + +public class AuthenticationException extends PingppException { + + + public AuthenticationException(String message) { + super(message); + } + + public AuthenticationException(String message, String type, String code, int statusCode, Throwable e) { + super(message, type, code, statusCode, e); + } + + private static final long serialVersionUID = 2L; + +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/exception/ChannelException.java b/pingpp-sdk/src/main/java/com/pingplusplus/exception/ChannelException.java new file mode 100644 index 0000000..a820f85 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/exception/ChannelException.java @@ -0,0 +1,23 @@ +package com.pingplusplus.exception; + +public class ChannelException extends PingppException { + + private static final long serialVersionUID = 2L; + + private final String param; + + public ChannelException(String message, String type, String code, int statusCode, Throwable e) { + super(message, type, code, statusCode, e); + this.param = null; + } + + public ChannelException(String message, String type, String code, String param, int statusCode, Throwable e) { + super(message, type, code, statusCode, e); + this.param = param; + } + + public String getParam() { + return param; + } + +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/exception/InvalidRequestException.java b/pingpp-sdk/src/main/java/com/pingplusplus/exception/InvalidRequestException.java new file mode 100644 index 0000000..da74498 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/exception/InvalidRequestException.java @@ -0,0 +1,17 @@ +package com.pingplusplus.exception; + +public class InvalidRequestException extends PingppException { + + private static final long serialVersionUID = 2L; + + private final String param; + + public InvalidRequestException(String message, String type, String code, String param, int statusCode, Throwable e) { + super(message, type, code, statusCode, e); + this.param = param; + } + + public String getParam() { + return param; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/exception/PingppException.java b/pingpp-sdk/src/main/java/com/pingplusplus/exception/PingppException.java new file mode 100644 index 0000000..129a5cc --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/exception/PingppException.java @@ -0,0 +1,52 @@ +package com.pingplusplus.exception; + +public abstract class PingppException extends Exception { + private String type; + + private String code; + + private int statusCode; + + public PingppException(String message) { + super(message, null); + } + + public PingppException(String message, Throwable e) { + super(message, e); + } + + public PingppException(String message, String type, String code, int statusCode, Throwable e) { + super(message, e); + this.type = type; + this.code = code; + this.statusCode = statusCode; + } + + private static final long serialVersionUID = 2L; + + public String getType() { + return type; + } + + public String getCode() { + return code; + } + + public int getStatusCode() { + return statusCode; + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(super.toString()); + if (type != null) { + sb.append("; type: ").append(type); + } + if (code != null) { + sb.append("; code: ").append(code); + } + + return sb.toString(); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/exception/RateLimitException.java b/pingpp-sdk/src/main/java/com/pingplusplus/exception/RateLimitException.java new file mode 100644 index 0000000..080bca4 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/exception/RateLimitException.java @@ -0,0 +1,14 @@ +package com.pingplusplus.exception; + +public class RateLimitException extends PingppException { + + private static final long serialVersionUID = 2L; + + public RateLimitException(String message, Throwable e) { + super(message, e); + } + + public RateLimitException(String message, String type, String code, int statusCode, Throwable e) { + super(message, type, code, statusCode, e); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/Agreement.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Agreement.java new file mode 100644 index 0000000..ae64880 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Agreement.java @@ -0,0 +1,280 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.HashMap; +import java.util.Map; + +/** + * 签约 + */ +public class Agreement extends APIResource { + String id; + String object; + Boolean livemode; + String app; + Long created; + String channel; + String contractNo; + String contractId; + Map credential; + String status; + Long timeSucceeded; + Long timeCanceled; + String failureCode; + String failureMsg; + Map extra; + Map metadata; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public String getContractNo() { + return contractNo; + } + + public void setContractNo(String contractNo) { + this.contractNo = contractNo; + } + + public String getContractId() { + return contractId; + } + + public void setContractId(String contractId) { + this.contractId = contractId; + } + + public Map getCredential() { + return credential; + } + + public void setCredential(Map credential) { + this.credential = credential; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Long getTimeSucceeded() { + return timeSucceeded; + } + + public void setTimeSucceeded(Long timeSucceeded) { + this.timeSucceeded = timeSucceeded; + } + + public Long getTimeCanceled() { + return timeCanceled; + } + + public void setTimeCanceled(Long timeCanceled) { + this.timeCanceled = timeCanceled; + } + + public String getFailureCode() { + return failureCode; + } + + public void setFailureCode(String failureCode) { + this.failureCode = failureCode; + } + + public String getFailureMsg() { + return failureMsg; + } + + public void setFailureMsg(String failureMsg) { + this.failureMsg = failureMsg; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + /** + * 创建签约(agreement) + * + * @param params 签约参数 + * @return Agreement + * @throws PingppException + */ + public static Agreement create(Map params) throws PingppException { + return create(params, null); + } + + /** + * 创建签约(agreement) + * + * @param params 签约参数 + * @param options the specific options + * @return Agreement + * @throws PingppException + */ + public static Agreement create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(RequestMethod.POST, classURL(Agreement.class), params, Agreement.class, options); + } + + /** + * 查询签约(agreement) + * + * @param id id + * @return Agreement + * @throws PingppException + */ + public static Agreement retrieve(String id) throws PingppException { + return retrieve(id, null); + } + + + + /** + * 查询签约(agreement) + * + * @param id id + * @param options the specific options + * @return Agreement + * @throws PingppException + */ + public static Agreement retrieve(String id, RequestOptions options) throws PingppException { + return APIResource.request(RequestMethod.GET, instanceURL(Agreement.class, id), null, Agreement.class, options); + } + + /** + * 查询签约列表 + * + * @param params 分页参数等 + * @return AgreementCollection + * @throws PingppException + */ + public static AgreementCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询签约列表 + * + * @param params 分页参数等 + * @param options the specific options + * @return AgreementCollection + * @throws PingppException + */ + public static AgreementCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(RequestMethod.GET, classURL(Agreement.class), params, AgreementCollection.class, options); + } + + /** + * 解除签约(agreement) + * + * @param id id + * @return Agreement + * @throws PingppException + */ + public static Agreement cancel(String id) throws PingppException { + return cancel(id, null); + } + + /** + * 解除签约(agreement) + * + * @param id id + * @param options the specific options + * @return Agreement + * @throws PingppException + */ + public static Agreement cancel(String id, RequestOptions options) throws PingppException { + Map params = new HashMap(); + params.put("status", "canceled"); + return APIResource.request(RequestMethod.PUT, instanceURL(Agreement.class, id), params, Agreement.class, options); + } + + /** + * 签约修改 + * @param id + * @param params + * @param options + * @return + * @throws PingppException + */ + public static Agreement modify(String id,Map params, RequestOptions options) throws PingppException { + return APIResource.request(RequestMethod.POST, String.format("%s/%s/modify/", classURL(Agreement.class), id), params, Agreement.class, options); + } + + /** + * 签约修改 + * @param id + * @param params + * @return + * @throws PingppException + */ + public static Agreement modify(String id, Map params) throws PingppException { + return modify(id, params, null); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/AgreementCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/AgreementCollection.java new file mode 100644 index 0000000..c112561 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/AgreementCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class AgreementCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/AgreementNotify.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/AgreementNotify.java new file mode 100644 index 0000000..9fd9970 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/AgreementNotify.java @@ -0,0 +1,44 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class AgreementNotify extends APIResource { + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Boolean getSucceed() { + return succeed; + } + + public void setSucceed(Boolean succeed) { + this.succeed = succeed; + } + + String id; + Boolean succeed; + + public static AgreementNotify create(String id, Map params) throws PingppException { + return create(id, params, null); + } + + /** + * 签约扣款-商户预扣费通知 + * @param agreementId + * @param params + * @param options + * @return + * @throws PingppException + */ + public static AgreementNotify create(String agreementId, Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, String.format("%s/notify", instanceURL(Agreement.class, agreementId)), params, AgreementNotify.class, options); + } +} diff --git a/src/main/java/com/pingplusplus/model/App.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/App.java similarity index 100% rename from src/main/java/com/pingplusplus/model/App.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/App.java diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceBonus.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceBonus.java new file mode 100644 index 0000000..911abdd --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceBonus.java @@ -0,0 +1,220 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; +import java.util.Map; + +public class BalanceBonus extends AppBasedResource { + String id; + String object; + String app; + Long created; + Boolean livemode; + Boolean paid; + Boolean refunded; + Integer amount; + Integer amountRefunded; + String orderNo; + Long timePaid; + String user; + String balanceTransaction; + String description; + Map metadata; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public Boolean getPaid() { + return paid; + } + + public void setPaid(Boolean paid) { + this.paid = paid; + } + + public Boolean getRefunded() { + return refunded; + } + + public void setRefunded(Boolean refunded) { + this.refunded = refunded; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public Integer getAmountRefunded() { + return amountRefunded; + } + + public void setAmountRefunded(Integer amountRefunded) { + this.amountRefunded = amountRefunded; + } + + public String getOrderNo() { + return orderNo; + } + + public void setOrderNo(String orderNo) { + this.orderNo = orderNo; + } + + public Long getTimePaid() { + return timePaid; + } + + public void setTimePaid(Long timePaid) { + this.timePaid = timePaid; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getBalanceTransaction() { + return balanceTransaction; + } + + public void setBalanceTransaction(String balanceTransaction) { + this.balanceTransaction = balanceTransaction; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + /** + * 创建 balance_bonus + * + * @param params 请求参数 + * @return BalanceBonus + * @throws PingppException + */ + public static BalanceBonus create(Map params) + throws PingppException { + return create(params, null); + } + + /** + * 创建 balance_bonus + * + * @param params 请求参数 + * @param options the specific options + * @return BalanceBonus + * @throws PingppException + */ + public static BalanceBonus create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(BalanceBonus.class), params, BalanceBonus.class, options); + } + + /** + * 查询 balance_bonus + * + * @param id + * @return BalanceBonus + * @throws PingppException + */ + public static BalanceBonus retrieve(String id) + throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 balance_bonus + * + * @param id + * @param options the specific options + * @return BalanceBonus + * @throws PingppException + */ + public static BalanceBonus retrieve(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(BalanceBonus.class, id), null, BalanceBonus.class, options); + } + + /** + * 查询 balance_bonus 列表 + * + * @param params + * @return BalanceBonusCollection + * @throws PingppException + */ + public static BalanceBonusCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 balance_bonus 列表 + * + * @param params + * @param options the specific options + * @return BalanceBonusCollection + * @throws PingppException + */ + public static BalanceBonusCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(BalanceBonus.class), params, BalanceBonusCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceBonusCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceBonusCollection.java new file mode 100644 index 0000000..6c47f7a --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceBonusCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class BalanceBonusCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceSettlement.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceSettlement.java new file mode 100644 index 0000000..2a60832 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceSettlement.java @@ -0,0 +1,213 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; +import java.util.Map; + +public class BalanceSettlement extends AppBasedResource { + String id; + String object; + String app; + Integer amount; + Integer amountRefunded; + Long created; + String charge; + Boolean livemode; + String failureMsg; + Boolean refunded; + String orderNo; + String status; + Long timeCredited; + Long timeSucceeded; + String transactionNo; + String user; + String userFee; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public Integer getAmountRefunded() { + return amountRefunded; + } + + public void setAmountRefunded(Integer amountRefunded) { + this.amountRefunded = amountRefunded; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getCharge() { + return charge; + } + + public void setCharge(String charge) { + this.charge = charge; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getFailureMsg() { + return failureMsg; + } + + public void setFailureMsg(String failureMsg) { + this.failureMsg = failureMsg; + } + + public Boolean getRefunded() { + return refunded; + } + + public void setRefunded(Boolean refunded) { + this.refunded = refunded; + } + + public String getOrderNo() { + return orderNo; + } + + public void setOrderNo(String orderNo) { + this.orderNo = orderNo; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Long getTimeCredited() { + return timeCredited; + } + + public void setTimeCredited(Long timeCredited) { + this.timeCredited = timeCredited; + } + + public Long getTimeSucceeded() { + return timeSucceeded; + } + + public void setTimeSucceeded(Long timeSucceeded) { + this.timeSucceeded = timeSucceeded; + } + + public String getTransactionNo() { + return transactionNo; + } + + public void setTransactionNo(String transactionNo) { + this.transactionNo = transactionNo; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getUserFee() { + return userFee; + } + + public void setUserFee(String userFee) { + this.userFee = userFee; + } + + /** + * 查询 balance_settlement + * + * @param id balance_settlement ID + * @return BalanceSettlement + * @throws PingppException + */ + public static BalanceSettlement retrieve(String id) + throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 balance_settlement + * + * @param id balance_settlement ID + * @param options the specific options + * @return BalanceSettlement + * @throws PingppException + */ + public static BalanceSettlement retrieve(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(BalanceSettlement.class, id), null, BalanceSettlement.class, options); + } + + /** + * 查询 balance_transaction 列表 + * + * @param params 过滤参数 + * @return BalanceSettlementCollection + * @throws PingppException + */ + public static BalanceSettlementCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 balance_transaction 列表 + * + * @param params 过滤参数 + * @param options the specific options + * @return BalanceSettlementCollection + * @throws PingppException + */ + public static BalanceSettlementCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(BalanceSettlement.class), params, BalanceSettlementCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceSettlementCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceSettlementCollection.java new file mode 100644 index 0000000..5e72a8c --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceSettlementCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class BalanceSettlementCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransaction.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransaction.java new file mode 100644 index 0000000..4873833 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransaction.java @@ -0,0 +1,160 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class BalanceTransaction extends AppBasedResource { + String id; + String object; + String app; + Integer amount; + Integer availableBalance; + Long created; + String description; + Boolean livemode; + String source; + String type; + String user; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public Integer getAvailableBalance() { + return availableBalance; + } + + public void setAvailableBalance(Integer availableBalance) { + this.availableBalance = availableBalance; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + /** + * 查询 balance_transaction + * + * @param id + * @return BalanceTransaction + * @throws PingppException + */ + public static BalanceTransaction retrieve(String id) + throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 balance_transaction + * + * @param id + * @param options the specific options + * @return BalanceTransaction + * @throws PingppException + */ + public static BalanceTransaction retrieve(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(BalanceTransaction.class, id), null, BalanceTransaction.class, options); + } + + /** + * 查询 balance_transaction 列表 + * + * @param params + * @return BalanceTransactionCollection + * @throws PingppException + */ + public static BalanceTransactionCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 balance_transaction 列表 + * + * @param params + * @param options the specific options + * @return BalanceTransactionCollection + * @throws PingppException + */ + public static BalanceTransactionCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(BalanceTransaction.class), params, BalanceTransactionCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransactionCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransactionCollection.java new file mode 100644 index 0000000..d860ff0 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransactionCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class BalanceTransactionCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransfer.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransfer.java new file mode 100644 index 0000000..61b1cb9 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransfer.java @@ -0,0 +1,221 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class BalanceTransfer extends AppBasedResource { + String id; + String object; + String app; + String orderNo; + Long created; + Boolean livemode; + String status; + Integer amount; + String user; + String userFee; + String recipient; + String userBalanceTransaction; + String recipientBalanceTransaction; + String description; + Map metadata; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public String getOrderNo() { + return orderNo; + } + + public void setOrderNo(String orderNo) { + this.orderNo = orderNo; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getUserFee() { + return userFee; + } + + public void setUserFee(String userFee) { + this.userFee = userFee; + } + + public String getRecipient() { + return recipient; + } + + public void setRecipient(String recipient) { + this.recipient = recipient; + } + + public String getUserBalanceTransaction() { + return userBalanceTransaction; + } + + public void setUserBalanceTransaction(String userBalanceTransaction) { + this.userBalanceTransaction = userBalanceTransaction; + } + + public String getRecipientBalanceTransaction() { + return recipientBalanceTransaction; + } + + public void setRecipientBalanceTransaction(String recipientBalanceTransaction) { + this.recipientBalanceTransaction = recipientBalanceTransaction; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + /** + * 创建 balance_transfer + * + * @param params + * @return BalanceTransfer + * @throws PingppException + */ + public static BalanceTransfer create(Map params) + throws PingppException { + return create(params, null); + } + + /** + * 创建 balance_transfer + * + * @param params + * @param options the specific options + * @return BalanceTransfer + * @throws PingppException + */ + public static BalanceTransfer create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(BalanceTransfer.class), params, BalanceTransfer.class, options); + } + + /** + * 查询 balance_transfer + * + * @param id + * @return BalanceTransfer + * @throws PingppException + */ + public static BalanceTransfer retrieve(String id) + throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 balance_transfer + * + * @param id + * @param options the specific options + * @return BalanceTransfer + * @throws PingppException + */ + public static BalanceTransfer retrieve(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(BalanceTransfer.class, id), null, BalanceTransfer.class, options); + } + + /** + * 查询 balance_transfer 列表 + * + * @param params + * @return BalanceTransferCollection + * @throws PingppException + */ + public static BalanceTransferCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 balance_transfer 列表 + * + * @param params + * @param options the specific options + * @return BalanceTransferCollection + * @throws PingppException + */ + public static BalanceTransferCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(BalanceTransfer.class), params, BalanceTransferCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransferCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransferCollection.java new file mode 100644 index 0000000..eb1913f --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BalanceTransferCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class BalanceTransferCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchRefund.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchRefund.java new file mode 100644 index 0000000..be83e92 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchRefund.java @@ -0,0 +1,211 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.List; +import java.util.Map; + +public class BatchRefund extends APIResource { + String id; + String object; + String app; + String batchNo; + Long created; + String description; + Boolean livemode; + Map metadata; + List charges; + ChargeRefundCollection refunds; + String refundUrl; + String status; + Long timeSucceeded; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public String getBatchNo() { + return batchNo; + } + + public void setBatchNo(String batchNo) { + this.batchNo = batchNo; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getMetadata() { + return metadata; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public List getCharges() { + return charges; + } + + public void setCharges(List charges) { + this.charges = charges; + } + + public ChargeRefundCollection getRefunds() { + return refunds; + } + + public void setRefunds(ChargeRefundCollection refunds) { + this.refunds = refunds; + } + + public String getRefundUrl() { + return refundUrl; + } + + public void setRefundUrl(String refundUrl) { + this.refundUrl = refundUrl; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Long getTimeSucceeded() { + return timeSucceeded; + } + + public void setTimeSucceeded(Long timeSucceeded) { + this.timeSucceeded = timeSucceeded; + } + + /** + * @param clazz + * @return String + */ + protected static String classURL(Class clazz) { + return apiBasePrefixedURL("/v1/batch_refunds"); + } + + /** + * 创建 batch_refund + * + * @param params + * @return BatchRefund + * @throws PingppException + */ + public static BatchRefund create(Mapparams) + throws PingppException { + return create(params, null); + } + + /** + * 创建 batch_refund + * + * @param params + * @param options the specific options + * @return BatchRefund + * @throws PingppException + */ + public static BatchRefund create(Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(BatchRefund.class), params, BatchRefund.class, options); + } + + /** + * 查询 batch_refund + * + * @param id + * @return BatchRefund + * @throws PingppException + */ + public static BatchRefund retrieve(String id) + throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 batch_refund + * + * @param id + * @param options the specific options + * @return BatchRefund + * @throws PingppException + */ + public static BatchRefund retrieve(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(BatchRefund.class, id), null, BatchRefund.class, options); + } + + /** + * 查询 batch_refund 列表 + * + * @param params + * @return BatchRefundCollection + * @throws PingppException + */ + public static BatchRefundCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 batch_refund 列表 + * + * @param params + * @param options the specific options + * @return BatchRefundCollection + * @throws PingppException + */ + public static BatchRefundCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(BatchRefund.class), params, BatchRefundCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchRefundCharges.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchRefundCharges.java new file mode 100644 index 0000000..ab7ba56 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchRefundCharges.java @@ -0,0 +1,52 @@ +package com.pingplusplus.model; + +/** + * Created by Afon on 17/01/12. + */ +public class BatchRefundCharges extends PingppObject { + String charge; + Integer amount; + String description; + String status; + String fundingSource; + + public String getCharge() { + return charge; + } + + public void setCharge(String account) { + this.charge = charge; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getFundingSource() { + return fundingSource; + } + + public void setFundingSource(String fundingSource) { + this.fundingSource = fundingSource; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchRefundCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchRefundCollection.java new file mode 100644 index 0000000..2d89805 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchRefundCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class BatchRefundCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchTransfer.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchTransfer.java new file mode 100644 index 0000000..90d1114 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchTransfer.java @@ -0,0 +1,282 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.List; +import java.util.Map; + +public class BatchTransfer extends APIResource { + String id; + String object; + String app; + Long amount; + String batchNo; + String channel; + String currency; + Long created; + String description; + Map extra; + String failureMsg; + Integer fee; + Boolean livemode; + Map metadata; + List recipients; + String status; + Long timeSucceeded; + String type; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Long getAmount() { + return amount; + } + + public void setAmount(Long amount) { + this.amount = amount; + } + + public String getBatchNo() { + return batchNo; + } + + public void setBatchNo(String batchNo) { + this.batchNo = batchNo; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } + + public String getFailureMsg() { + return failureMsg; + } + + public void setFailureMsg(String failureMsg) { + this.failureMsg = failureMsg; + } + + public Integer getFee() { + return fee; + } + + public void setFee(Integer fee) { + this.fee = fee; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public List getRecipients() { + return recipients; + } + + public void setRecipients(List recipients) { + this.recipients = recipients; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Long getTimeSucceeded() { + return timeSucceeded; + } + + public void setTimeSucceeded(Long timeSucceeded) { + this.timeSucceeded = timeSucceeded; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + /** + * @param clazz + * @return String + */ + protected static String classURL(Class clazz) { + return apiBasePrefixedURL("/v1/batch_transfers"); + } + + /** + * 创建 batch_transfer + * + * @param params + * @return BatchTransfer + * @throws PingppException + */ + public static BatchTransfer create(Mapparams) + throws PingppException { + return create(params, null); + } + + /** + * 创建 batch_transfer + * + * @param params + * @param options the specific options + * @return BatchTransfer + * @throws PingppException + */ + public static BatchTransfer create(Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(BatchTransfer.class), params, BatchTransfer.class, options); + } + + /** + * 查询 batch_transfer + * + * @param id + * @return BatchTransfer + * @throws PingppException + */ + public static BatchTransfer retrieve(String id) + throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 batch_transfer + * + * @param id + * @param options the specific options + * @return BatchTransfer + * @throws PingppException + */ + public static BatchTransfer retrieve(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(BatchTransfer.class, id), null, BatchTransfer.class, options); + } + + /** + * 查询 batch_transfer 列表 + * + * @param params + * @return BatchTransferCollection + * @throws PingppException + */ + public static BatchTransferCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 batch_transfer 列表 + * + * @param params + * @param options the specific options + * @return BatchTransferCollection + * @throws PingppException + */ + public static BatchTransferCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(BatchTransfer.class), params, BatchTransferCollection.class, options); + } + + /** + * 更新 BatchTransfer + * @param id batch_transfer ID + * @param params 更新参数 + * @return BatchTransfer + * @throws PingppException + */ + public static BatchTransfer update(String id, Map params) + throws PingppException { + return update(id, params, null); + } + + /** + * 更新 BatchTransfer + * + * @param id + * @param params + * @param options the specific options + * @return BatchTransfer + * @throws PingppException + */ + public static BatchTransfer update(String id, Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.PUT, instanceURL(BatchTransfer.class, id), params, BatchTransfer.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchTransferCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchTransferCollection.java new file mode 100644 index 0000000..f9f5014 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchTransferCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class BatchTransferCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchTransferRecipient.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchTransferRecipient.java new file mode 100644 index 0000000..b771e1e --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchTransferRecipient.java @@ -0,0 +1,142 @@ +package com.pingplusplus.model; + +/** + * Created by Afon on 16/11/05. + */ +public class BatchTransferRecipient extends PingppObject { + String account; + Integer amount; + String name; + String description; + String transfer; + String status; + String openBankCode; + String openBank; + Integer fee; + String failureMsg; + String orderNo; + String transactionNo; + String accountType; + String businessCode; + String cardType; + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getTransfer() { + return transfer; + } + + public void setTransfer(String transfer) { + this.transfer = transfer; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getOpenBankCode() { + return openBankCode; + } + + public void setOpenBankCode(String openBankCode) { + this.openBankCode = openBankCode; + } + + public String getOpenBank() { + return openBank; + } + + public void setOpenBank(String openBank) { + this.openBank = openBankCode; + } + + public Integer getFee() { + return fee; + } + + public void setFee(Integer fee) { + this.fee = fee; + } + + public String getFailureMsg() { + return failureMsg; + } + + public void setFailureMsg(String failureMsg) { + this.failureMsg = failureMsg; + } + + public String getOrderNo() { + return orderNo; + } + + public void setOrderNo(String orderNo) { + this.orderNo = orderNo; + } + + public String getTransactionNo() { + return transactionNo; + } + + public void setTransactionNo(String transactionNo) { + this.transactionNo = transactionNo; + } + + public String getAccountType() { + return accountType; + } + + public void setAccountType(String accountType) { + this.accountType = accountType; + } + + public String getBusinessCode() { + return businessCode; + } + + public void setBusinessCode(String businessCode) { + this.businessCode = businessCode; + } + + public String getCardType() { + return cardType; + } + + public void setCardType(String cardType) { + this.cardType = cardType; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchWithdrawal.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchWithdrawal.java new file mode 100644 index 0000000..33eeba1 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchWithdrawal.java @@ -0,0 +1,275 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class BatchWithdrawal extends AppBasedResource { + String id; + String object; + String app; + Long created; + Boolean livemode; + Long amount; + Long amountSucceeded; + Long amountFailed; + Long amountCanceled; + Integer count; + Integer countSucceeded; + Integer countFailed; + Integer countCanceled; + Integer fee; + Map metadata; + String operationUrl; + String source; + String status; + Long timeFinished; + Integer userFee; + WithdrawalCollectionBase withdrawals; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public Long getAmount() { + return amount; + } + + public void setAmount(Long amount) { + this.amount = amount; + } + + public Long getAmountSucceeded() { + return amountSucceeded; + } + + public void setAmountSucceeded(Long amountSucceeded) { + this.amountSucceeded = amountSucceeded; + } + + public Long getAmountFailed() { + return amountFailed; + } + + public void setAmountFailed(Long amountFailed) { + this.amountFailed = amountFailed; + } + + public Long getAmountCanceled() { + return amountCanceled; + } + + public void setAmountCanceled(Long amountCanceled) { + this.amountCanceled = amountCanceled; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public Integer getCountSucceeded() { + return countSucceeded; + } + + public void setCountSucceeded(Integer countSucceeded) { + this.countSucceeded = countSucceeded; + } + + public Integer getCountFailed() { + return countFailed; + } + + public void setCountFailed(Integer countFailed) { + this.countFailed = countFailed; + } + + public Integer getCountCanceled() { + return countCanceled; + } + + public void setCountCanceled(Integer countCanceled) { + this.countCanceled = countCanceled; + } + + public Integer getFee() { + return fee; + } + + public void setFee(Integer fee) { + this.fee = fee; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public String getOperationUrl() { + return operationUrl; + } + + public void setOperationUrl(String operationUrl) { + this.operationUrl = operationUrl; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Integer getUserFee() { + return userFee; + } + + public void setUserFee(Integer userFee) { + this.userFee = userFee; + } + + public WithdrawalCollectionBase getWithdrawals() { + return withdrawals; + } + + public void setWithdrawals(WithdrawalCollectionBase withdrawals) { + this.withdrawals = withdrawals; + } + + public Long getTimeFinished() { + return timeFinished; + } + + public void setTimeFinished(Long timeFinished) { + this.timeFinished = timeFinished; + } + + /** + * 创建 batch_withdrawal + * + * @param params + * @return BatchWithdrawal + * @throws PingppException + */ + public static BatchWithdrawal create(Map params) + throws PingppException { + return create(params, null); + } + + /** + * 创建 batch_withdrawal + * + * @param params + * @param options the specific options + * @return BatchWithdrawal + * @throws PingppException + */ + public static BatchWithdrawal create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(BatchWithdrawal.class), params, BatchWithdrawal.class, options); + } + + /** + * 查询 batch_withdrawal + * + * @param id + * @return BatchWithdrawal + * @throws PingppException + */ + public static BatchWithdrawal retrieve(String id) + throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 batch_withdrawal + * + * @param id + * @param options the specific options + * @return BatchWithdrawal + * @throws PingppException + */ + public static BatchWithdrawal retrieve(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(BatchWithdrawal.class, id), null, BatchWithdrawal.class, options); + } + + /** + * 查询 batch_withdrawal 列表 + * + * @param params + * @return BatchWithdrawalCollection + * @throws PingppException + */ + public static BatchWithdrawalCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 batch_withdrawal 列表 + * + * @param params + * @param options the specific options + * @return BatchWithdrawalCollection + * @throws PingppException + */ + public static BatchWithdrawalCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(BatchWithdrawal.class), params, BatchWithdrawalCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchWithdrawalCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchWithdrawalCollection.java new file mode 100644 index 0000000..500e53a --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/BatchWithdrawalCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class BatchWithdrawalCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/CardInfo.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/CardInfo.java new file mode 100644 index 0000000..7d3d650 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/CardInfo.java @@ -0,0 +1,90 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.List; +import java.util.Map; + +public class CardInfo extends APIResource { + String app; + String cardBin; + Integer cardType; + String openBankCode; + String openBank; + List supportChannels; + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public String getCardBin() { + return cardBin; + } + + public void setCardBin(String cardBin) { + this.cardBin = cardBin; + } + + public Integer getCardType() { + return cardType; + } + + public void setCardType(Integer cardType) { + this.cardType = cardType; + } + + public String getOpenBankCode() { + return openBankCode; + } + + public void setOpenBankCode(String openBankCode) { + this.openBankCode = openBankCode; + } + + public String getOpenBank() { + return openBank; + } + + public void setOpenBank(String openBank) { + this.openBank = openBank; + } + + public List getSupportChannels() { + return supportChannels; + } + + public void setSupportChannels(List supportChannels) { + this.supportChannels = supportChannels; + } + + /** + * 银行卡信息查询 + * + * @param params 卡号等信息 + * @return CardInfo + * @throws PingppException + */ + public static CardInfo query(Map params) + throws PingppException { + return query(params, null); + } + + /** + * 银行卡信息查询 + * + * @param params 卡号等信息 + * @param options the specific options + * @return CardInfo + * @throws PingppException + */ + public static CardInfo query(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, singleClassURL(CardInfo.class), params, CardInfo.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/Channel.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Channel.java new file mode 100644 index 0000000..aea7dd8 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Channel.java @@ -0,0 +1,185 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; +import com.pingplusplus.net.SubAppBasedResource; + +import java.util.Map; + +public class Channel extends SubAppBasedResource { + String object; + Long created; + String channel; + Boolean banned; + String bannedMsg; + String description; + Map params; + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public Boolean getBanned() { + return banned; + } + + public void setBanned(Boolean banned) { + this.banned = banned; + } + + public String getBannedMsg() { + return bannedMsg; + } + + public void setBannedMsg(String bannedMsg) { + this.bannedMsg = bannedMsg; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getParams() { + return params; + } + + public void setParams(Map params) { + this.params = params; + } + + /** + * 创建渠道参数 + * + * @param subAppId + * @param params + * @return Channel + * @throws PingppException + */ + public static Channel create(String subAppId, Mapparams) + throws PingppException { + return create(subAppId, params, null); + } + + /** + * 创建渠道参数 + * + * @param subAppId + * @param params + * @param options the specific options + * @return Channel + * @throws PingppException + */ + public static Channel create(String subAppId, Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(Channel.class, subAppId), params, Channel.class, options); + } + + /** + * 查询渠道参数 + * + * @param subAppId + * @param channel + * @return Channel + * @throws PingppException + */ + public static Channel retrieve(String subAppId, String channel) + throws PingppException { + return retrieve(subAppId, channel, null); + } + + + /** + * 查询渠道参数 + * + * @param subAppId + * @param channel + * @param options the specific options + * @return Channel + * @throws PingppException + */ + public static Channel retrieve(String subAppId, String channel, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(Channel.class, subAppId, channel), null, Channel.class, options); + } + + /** + * 更新渠道参数 + * + * @param subAppId + * @param channel + * @param params + * @return Channel + * @throws PingppException + */ + public static Channel update(String subAppId, String channel, Mapparams) + throws PingppException { + return update(subAppId, channel, params, null); + } + + /** + * 更新渠道参数 + * + * @param subAppId + * @param channel + * @param params + * @param options the specific options + * @return Channel + * @throws PingppException + */ + public static Channel update(String subAppId, String channel, Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.PUT, instanceURL(Channel.class, subAppId, channel), params, Channel.class, options); + } + + /** + * 删除渠道参数 + * + * @param subAppId + * @param channel + * @return DeletedChannel + * @throws PingppException + */ + public static DeletedChannel delete(String subAppId, String channel) + throws PingppException { + return delete(subAppId, channel, null); + } + + /** + * 删除渠道参数 + * + * @param subAppId + * @param channel + * @param options the specific options + * @return DeletedChannel + * @throws PingppException + */ + public static DeletedChannel delete(String subAppId, String channel, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.DELETE, instanceURL(Channel.class, subAppId, channel), null, DeletedChannel.class, options); + } +} diff --git a/src/main/java/com/pingplusplus/model/Charge.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Charge.java similarity index 53% rename from src/main/java/com/pingplusplus/model/Charge.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/Charge.java index 7c81982..d76a27f 100644 --- a/src/main/java/com/pingplusplus/model/Charge.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Charge.java @@ -1,13 +1,11 @@ package com.pingplusplus.model; - -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; import com.pingplusplus.exception.InvalidRequestException; +import com.pingplusplus.exception.PingppException; import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; +import java.util.HashMap; import java.util.Map; public class Charge extends APIResource { @@ -17,6 +15,7 @@ public class Charge extends APIResource { Boolean livemode; Boolean paid; Boolean refunded; + Boolean reversed; Object app; String channel; String orderNo; @@ -34,7 +33,7 @@ public class Charge extends APIResource { Integer amountRefunded; String failureCode; String failureMsg; - Map metadata; + Map metadata; Map credential; Map extra; String description; @@ -95,6 +94,14 @@ public void setRefunded(Boolean refunded) { this.refunded = refunded; } + public Boolean getReversed() { + return reversed; + } + + public void setReversed(Boolean reversed) { + this.reversed = reversed; + } + public String getDescription() { return description; } @@ -152,19 +159,14 @@ public void setObject(String object) { } public ChargeRefundCollection getRefunds() { - // API versions 2014-05-19 and earlier render charge refunds as an array - // instead of an object, meaning there is no sublist URL. - if (refunds.getURL() == null) { - refunds.setURL(String.format("/v1/charges/%s/refunds", getId())); - } return refunds; } - public Map getMetadata() { + public Map getMetadata() { return metadata; } - public void setMetadata(Map metadata) { + public void setMetadata(Map metadata) { this.metadata = metadata; } @@ -261,34 +263,36 @@ public void setTimeSettle(Long timeSettle) { * 创建 charge * * @param params - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @return Charge + * @throws PingppException */ public static Charge create(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return request(RequestMethod.POST, classURL(Charge.class), params, Charge.class); + throws PingppException { + return create(params, null); + } + + /** + * 创建 charge + * + * @param params + * @param options the specific options + * @return Charge + * @throws PingppException + */ + public static Charge create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(Charge.class), params, Charge.class, options); } /** * 查询 charge * * @param id - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @return Charge + * @throws PingppException */ - public static Charge retrieve(String id) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - return request(RequestMethod.GET, instanceURL(Charge.class, id), null, Charge.class); + public static Charge retrieve(String id) throws PingppException { + return retrieve(id, null, null); } /** @@ -296,34 +300,123 @@ public static Charge retrieve(String id) throws AuthenticationException, * * @param id * @param params - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @return Charge + * @throws PingppException + */ + public static Charge retrieve(String id, Map params) throws PingppException { + return retrieve(id, params, null); + } + + /** + * 查询 charge + * + * @param id + * @param options the specific options + * @return Charge + * @throws PingppException */ - public static Charge retrieve(String id, Map params) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - return request(RequestMethod.GET, instanceURL(Charge.class, id), params, Charge.class); + public static Charge retrieve(String id, RequestOptions options) throws PingppException { + return retrieve(id, null, options); } /** * 查询 charge * + * @param id + * @param params + * @param options the specific options + * @return Charge + * @throws PingppException + */ + public static Charge retrieve(String id, Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(Charge.class, id), params, Charge.class, options); + } + + /** + * 查询 charge 列表 + * + * @param params + * @return ChargeCollection + * @throws PingppException + */ + public static ChargeCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 charge 列表 + * + * @param params + * @param options the specific options + * @return ChargeCollection + * @throws PingppException + */ + public static ChargeCollection list(Map params, RequestOptions options) + throws PingppException { + if (params != null + && ((params.containsKey("app") && (params.get("app") instanceof Map) && ((Map) params.get("app")).containsKey("id")) + || (params.containsKey("app[id]") && (params.get("app[id]") instanceof String)))) { + return request(RequestMethod.GET, classURL(Charge.class), params, ChargeCollection.class, options); + } + throw new InvalidRequestException( + "Please pass app[id] as parameter.", + "invalid_request_error", + "request_param_error", + "app[id]", + 0, + null); + } + + /** + * 撤销 charge + * + * @param id + * @param params + * @param options the specific options + * @return Charge + * @throws PingppException + */ + public static Charge reverse(String id, Map params, RequestOptions options) throws PingppException { + String reverseUrl = String.format("%s/reverse", instanceURL(Charge.class, id)); + if (params == null) { + params = new HashMap(); + } + return APIResource.request(APIResource.RequestMethod.POST, reverseUrl, params, Charge.class, options); + } + + /** + * 撤销 charge + * + * @param id * @param params - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @return Charge + * @throws PingppException */ - public static ChargeCollection all(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return request(RequestMethod.GET, classURL(Charge.class), params, ChargeCollection.class); + public static Charge reverse(String id, Map params) throws PingppException { + return reverse(id, params, null); } + /** + * 撤销 charge + * + * @param id + * @return Charge + * @throws PingppException + */ + public static Charge reverse(String id) throws PingppException { + return reverse(id, null, null); + } + + /** + * 撤销 charge + * + * @param id + * @param options the specific options + * @return Charge + * @throws PingppException + */ + public static Charge reverse(String id, RequestOptions options) throws PingppException { + return reverse(id, null, options); + } } diff --git a/src/main/java/com/pingplusplus/model/ChargeCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/ChargeCollection.java similarity index 100% rename from src/main/java/com/pingplusplus/model/ChargeCollection.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/ChargeCollection.java diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/ChargeEssentials.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/ChargeEssentials.java new file mode 100644 index 0000000..a92fd5b --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/ChargeEssentials.java @@ -0,0 +1,45 @@ +package com.pingplusplus.model; + +import java.util.Map; + +/** + * Created by Afon on 16/11/04. + */ +public class ChargeEssentials extends PingppObject { + String channel; + String transactionNo; + Map credential; + Map extra; + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public String getTransactionNo() { + return transactionNo; + } + + public void setTransactionNo(String transactionNo) { + this.transactionNo = transactionNo; + } + + public Map getCredential() { + return credential; + } + + public void setCredential(Map credential) { + this.credential = credential; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/ChargeRefundCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/ChargeRefundCollection.java new file mode 100644 index 0000000..012a9e1 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/ChargeRefundCollection.java @@ -0,0 +1,51 @@ +package com.pingplusplus.model; + +import com.pingplusplus.Pingpp; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class ChargeRefundCollection extends PingppCollectionAPIResource { + + public ChargeRefundCollection list(Map params) + throws PingppException { + + return list(params, null); + } + + public ChargeRefundCollection list(Map params, RequestOptions options) + throws PingppException { + + String url = String.format("%s%s", Pingpp.getApiBase(), this.getURL()); + return APIResource.request(APIResource.RequestMethod.GET, url, params, ChargeRefundCollection.class, options); + } + + public Refund retrieve(String id) + throws PingppException { + + return retrieve(id, null); + } + + public Refund retrieve(String id, RequestOptions options) + throws PingppException { + + String url = String.format("%s%s/%s", Pingpp.getApiBase(), this.getURL(), id); + return APIResource.request(APIResource.RequestMethod.GET, url, null, Refund.class, options); + } + + public Refund create(Map params) + throws PingppException { + + return create(params, null); + } + + public Refund create(Map params, RequestOptions options) + throws PingppException { + + String url = String.format("%s%s", Pingpp.getApiBase(), this.getURL()); + return APIResource.request(APIResource.RequestMethod.POST, url, params, Refund.class, options); + } + +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/Contact.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Contact.java new file mode 100644 index 0000000..caf2b50 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Contact.java @@ -0,0 +1,72 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class Contact extends AppBasedResource { + String user; + Boolean livemode; + String accNo; + String contactNo; + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getAccNo() { + return accNo; + } + + public void setAccNo(String accNo) { + this.accNo = accNo; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getContactNo() { + return contactNo; + } + + public void setContactNo(String contactNo) { + this.contactNo = contactNo; + } + + /** + * 新增联系人 + * + * @param params 请求参数 + * @return Contact + * @throws PingppException + */ + public static Contact create(Map params) + throws PingppException { + return create(params, null); + } + + /** + * 新增联系人 + * + * @param params 请求参数 + * @param options the specific options + * @return Contact + * @throws PingppException + */ + public static Contact create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, singleClassURL(Contact.class), params, Contact.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/Coupon.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Coupon.java new file mode 100644 index 0000000..253984a --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Coupon.java @@ -0,0 +1,293 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; +import com.pingplusplus.net.UserBasedResource; + +import java.util.Map; + +public class Coupon extends UserBasedResource { + String id; + String object; + String app; + Integer actualAmount; + CouponTemplate couponTemplate; + Long created; + Boolean livemode; + Map metadata; + String order; + Boolean redeemed; + Long timeEnd; + Long timeStart; + String user; + Boolean valid; + Integer userTimesCirculated; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Integer getActualAmount() { + return actualAmount; + } + + public void setActualAmount(Integer actualAmount) { + this.actualAmount = actualAmount; + } + + public CouponTemplate getCouponTemplate() { + return couponTemplate; + } + + public void setCouponTemplate(CouponTemplate couponTemplate) { + this.couponTemplate = couponTemplate; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public String getOrder() { + return order; + } + + public void setOrder(String order) { + this.order = order; + } + + public Boolean getRedeemed() { + return redeemed; + } + + public void setRedeemed(Boolean redeemed) { + this.redeemed = redeemed; + } + + public Long getTimeEnd() { + return timeEnd; + } + + public void setTimeEnd(Long timeEnd) { + this.timeEnd = timeEnd; + } + + public Long getTimeStart() { + return timeStart; + } + + public void setTimeStart(Long timeStart) { + this.timeStart = timeStart; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public Boolean getValid() { + return valid; + } + + public void setValid(Boolean valid) { + this.valid = valid; + } + + public Integer getUserTimesCirculated() { + return userTimesCirculated; + } + + public void setUserTimesCirculated(Integer userTimesCirculated) { + this.userTimesCirculated = userTimesCirculated; + } + + /** + * 创建 coupon + * + * @param userId + * @param params + * @return Coupon + * @throws PingppException + */ + public static Coupon create(String userId, Mapparams) + throws PingppException { + User.checkUserId(userId); + return create(userId, params, null); + } + + /** + * 创建 coupon + * + * @param userId + * @param params + * @param options the specific options + * @return Coupon + * @throws PingppException + */ + public static Coupon create(String userId, Mapparams, RequestOptions options) + throws PingppException { + User.checkUserId(userId); + return APIResource.request(APIResource.RequestMethod.POST, classURL(Coupon.class, userId), params, Coupon.class, options); + } + + /** + * 查询 coupon + * + * @param userId + * @param id + * @return Coupon + * @throws PingppException + */ + public static Coupon retrieve(String userId, String id) + throws PingppException { + User.checkUserId(userId); + return retrieve(userId, id, null); + } + + /** + * 查询 coupon + * + * @param userId + * @param id + * @param options the specific options + * @return Coupon + * @throws PingppException + */ + public static Coupon retrieve(String userId, String id, RequestOptions options) + throws PingppException { + User.checkUserId(userId); + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(Coupon.class, userId, id), null, Coupon.class, options); + } + + /** + * 查询 coupon 列表 + * + * @param userId + * @param params + * @return CouponCollection + * @throws PingppException + */ + public static CouponCollection list(String userId, Map params) + throws PingppException { + User.checkUserId(userId); + return list(userId, params, null); + } + + /** + * 查询 coupon 列表 + * + * @param userId + * @param params + * @param options the specific options + * @return CouponCollection + * @throws PingppException + */ + public static CouponCollection list(String userId, Map params, RequestOptions options) + throws PingppException { + User.checkUserId(userId); + return APIResource.request(APIResource.RequestMethod.GET, classURL(Coupon.class, userId), params, CouponCollection.class, options); + } + + /** + * 更新 coupon + * + * @param userId + * @param id + * @param params + * @return Coupon + * @throws PingppException + */ + public static Coupon update(String userId, String id, Mapparams) + throws PingppException { + User.checkUserId(userId); + return update(userId, id, params, null); + } + + /** + * 更新 coupon + * + * @param userId + * @param id + * @param params + * @param options the specific options + * @return Coupon + * @throws PingppException + */ + public static Coupon update(String userId, String id, Mapparams, RequestOptions options) + throws PingppException { + User.checkUserId(userId); + return APIResource.request(APIResource.RequestMethod.PUT, instanceURL(Coupon.class, userId, id), params, Coupon.class, options); + } + + /** + * 删除 coupon + * + * @param userId + * @param id + * @return DeletedCoupon + * @throws PingppException + */ + public static DeletedCoupon delete(String userId, String id) + throws PingppException { + User.checkUserId(userId); + return delete(userId, id, null); + } + + /** + * 删除 coupon + * + * @param userId + * @param id + * @param options the specific options + * @return DeletedCoupon + * @throws PingppException + */ + public static DeletedCoupon delete(String userId, String id, RequestOptions options) + throws PingppException { + User.checkUserId(userId); + return APIResource.request(APIResource.RequestMethod.DELETE, instanceURL(Coupon.class, userId, id), null, DeletedCoupon.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponCollection.java new file mode 100644 index 0000000..ada387f --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class CouponCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponTemplate.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponTemplate.java new file mode 100644 index 0000000..e33014f --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponTemplate.java @@ -0,0 +1,349 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class CouponTemplate extends AppBasedResource { + String id; + String object; + String app; + Integer amountAvailable; + Integer amountOff; + Long created; + CouponTemplateExpiration expiration; + Boolean livemode; + Integer maxCirculation; + Integer maxUserCirculation; + Map metadata; + String name; + Integer percentOff; + Long timesCirculated; + Long timesRedeemed; + Integer type; + Boolean refundable; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Integer getAmountAvailable() { + return amountAvailable; + } + + public void setAmountAvailable(Integer amountAvailable) { + this.amountAvailable = amountAvailable; + } + + public Integer getAmountOff() { + return amountOff; + } + + public void setAmountOff(Integer amountOff) { + this.amountOff = amountOff; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public CouponTemplateExpiration getExpiration() { + return expiration; + } + + public void setExpiration(CouponTemplateExpiration expiration) { + this.expiration = expiration; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public Integer getMaxCirculation() { + return maxCirculation; + } + + public void setMaxCirculation(Integer maxCirculation) { + this.maxCirculation = maxCirculation; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getPercentOff() { + return percentOff; + } + + public void setPercentOff(Integer percentOff) { + this.percentOff = percentOff; + } + + public Long getTimesCirculated() { + return timesCirculated; + } + + public void setTimesCirculated(Long timesCirculated) { + this.timesCirculated = timesCirculated; + } + + public Long getTimesRedeemed() { + return timesRedeemed; + } + + public void setTimesRedeemed(Long timesRedeemed) { + this.timesRedeemed = timesRedeemed; + } + + public Integer getType() { + return type; + } + + public void setType(Integer type) { + this.type = type; + } + + public Boolean getRefundable() { + return refundable; + } + + public void setRefundable(Boolean refundable) { + this.refundable = refundable; + } + + public Integer getMaxUserCirculation() { + return maxUserCirculation; + } + + public void setMaxUserCirculation(Integer maxUserCirculation) { + this.maxUserCirculation = maxUserCirculation; + } + + /** + * 创建 coupon_template + * + * @param params + * @return CouponTemplate + * @throws PingppException + */ + public static CouponTemplate create(Mapparams) + throws PingppException { + return create(params, null); + } + + /** + * 创建 coupon_template + * + * @param params + * @param options the specific options + * @return CouponTemplate + * @throws PingppException + */ + public static CouponTemplate create(Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(CouponTemplate.class), params, CouponTemplate.class, options); + } + + /** + * 查询 coupon_template + * + * @param id + * @return CouponTemplate + * @throws PingppException + */ + public static CouponTemplate retrieve(String id) + throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 coupon_template + * + * @param id + * @param options the specific options + * @return CouponTemplate + * @throws PingppException + */ + public static CouponTemplate retrieve(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(CouponTemplate.class, id), null, CouponTemplate.class, options); + } + + /** + * 查询 coupon_template 列表 + * + * @param params + * @return CouponTemplateCollection + * @throws PingppException + */ + public static CouponTemplateCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 coupon_template 列表 + * + * @param params + * @param options the specific options + * @return CouponTemplateCollection + * @throws PingppException + */ + public static CouponTemplateCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(CouponTemplate.class), params, CouponTemplateCollection.class, options); + } + + /** + * 更新 coupon_template + * + * @param id + * @param params + * @return CouponTemplate + * @throws PingppException + */ + public static CouponTemplate update(String id, Mapparams) + throws PingppException { + return update(id, params, null); + } + + /** + * 更新 coupon_template + * + * @param id + * @param params + * @param options the specific options + * @return CouponTemplate + * @throws PingppException + */ + public static CouponTemplate update(String id, Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.PUT, instanceURL(CouponTemplate.class, id), params, CouponTemplate.class, options); + } + + /** + * 删除 coupon_template + * + * @param id + * @return DeletedCouponTemplate + * @throws PingppException + */ + public static DeletedCouponTemplate delete(String id) + throws PingppException { + return delete(id, null); + } + + /** + * 删除 coupon_template + * + * @param id + * @param options the specific options + * @return DeletedCouponTemplate + * @throws PingppException + */ + public static DeletedCouponTemplate delete(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.DELETE, instanceURL(CouponTemplate.class, id), null, DeletedCouponTemplate.class, options); + } + + public static String couponsURL(String tmplId) { + return String.format("%s/coupons", instanceURL(CouponTemplate.class, tmplId)); + } + + /** + * 批量创建 coupon + * + * @param id + * @param params + * @return CouponCollection + * @throws PingppException + */ + public static CouponCollection createCoupons(String id, Mapparams) + throws PingppException { + return createCoupons(id, params, null); + } + + /** + * 批量创建 coupon + * + * @param id + * @param params + * @param options the specific options + * @return CouponCollection + * @throws PingppException + */ + public static CouponCollection createCoupons(String id, Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, couponsURL(id), params, CouponCollection.class, options); + } + + /** + * 查询 coupon 列表 + * + * @param id + * @param params + * @return CouponCollection + * @throws PingppException + */ + public static CouponCollection listCoupons(String id, Mapparams) + throws PingppException { + return listCoupons(id, params, null); + } + + /** + * 查询 coupon 列表 + * + * @param id + * @param params + * @param options the specific options + * @return CouponCollection + * @throws PingppException + */ + public static CouponCollection listCoupons(String id, Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, couponsURL(id), params, CouponCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponTemplateCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponTemplateCollection.java new file mode 100644 index 0000000..013c926 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponTemplateCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class CouponTemplateCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponTemplateExpiration.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponTemplateExpiration.java new file mode 100644 index 0000000..f08e33e --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/CouponTemplateExpiration.java @@ -0,0 +1,34 @@ +package com.pingplusplus.model; + +/** + * Created by Afon on 16/11/07. + */ +public class CouponTemplateExpiration extends PingppObject { + Long timeStart; + Long timeEnd; + Long duration; + + public Long getTimeStart() { + return timeStart; + } + + public void setTimeStart(Long timeStart) { + this.timeStart = timeStart; + } + + public Long getTimeEnd() { + return timeEnd; + } + + public void setTimeEnd(Long timeEnd) { + this.timeEnd = timeEnd; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/Customs.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Customs.java new file mode 100644 index 0000000..96306af --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Customs.java @@ -0,0 +1,245 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class Customs extends APIResource { + String id; + String object; + Long created; + Object app; + String channel; + String tradeNo; + String customsCode; + Integer amount; + String charge; + Integer transportAmount; + Boolean isSplit; + String subOrderNo; + Map extra; + Long timeSucceeded; + String status; + String failureCode; + String failureMsg; + String transactionNo; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Object getApp() { + return app; + } + + public void setApp(Object app) { + this.app = app; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public String getTradeNo() { + return tradeNo; + } + + public void setTradeNo(String tradeNo) { + this.tradeNo = tradeNo; + } + + public String getCustomsCode() { + return customsCode; + } + + public void setCustomsCode(String customsCode) { + this.customsCode = customsCode; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getCharge() { + return charge; + } + + public void setCharge(String charge) { + this.charge = charge; + } + + public Integer getTransportAmount() { + return transportAmount; + } + + public void setTransportAmount(Integer transportAmount) { + this.transportAmount = transportAmount; + } + + public Boolean getSplit() { + return isSplit; + } + + public void setSplit(Boolean split) { + isSplit = split; + } + + public String getSubOrderNo() { + return subOrderNo; + } + + public void setSubOrderNo(String subOrderNo) { + this.subOrderNo = subOrderNo; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } + + public Long getTimeSucceeded() { + return timeSucceeded; + } + + public void setTimeSucceeded(Long timeSucceeded) { + this.timeSucceeded = timeSucceeded; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getFailureCode() { + return failureCode; + } + + public void setFailureCode(String failureCode) { + this.failureCode = failureCode; + } + + public String getFailureMsg() { + return failureMsg; + } + + public void setFailureMsg(String failureMsg) { + this.failureMsg = failureMsg; + } + + public String getTransactionNo() { + return transactionNo; + } + + public void setTransactionNo(String transactionNo) { + this.transactionNo = transactionNo; + } + + /** + * 创建 customs + * + * @param params + * @return Customs + * @throws PingppException + */ + public static Customs create(Map params) + throws PingppException { + return create(params, null); + } + + /** + * 创建 customs + * + * @param params + * @param options the specific options + * @return Customs + * @throws PingppException + */ + public static Customs create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(Customs.class), params, Customs.class, options); + } + + /** + * 查询 customs + * + * @param id + * @return Customs + * @throws PingppException + */ + public static Customs retrieve(String id) throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 customs + * + * @param id + * @param options the specific options + * @return Customs + * @throws PingppException + */ + public static Customs retrieve(String id, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(Customs.class, id), null, Customs.class, options); + } + + /** + * 查询 customs 列表 + * + * @param params + * @return CustomsCollection + * @throws PingppException + */ + public static CustomsCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 customs 列表 + * + * @param params + * @param options the specific options + * @return CustomsCollection + * @throws PingppException + */ + public static CustomsCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(Customs.class), params, CustomsCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/CustomsCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/CustomsCollection.java new file mode 100644 index 0000000..7005866 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/CustomsCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class CustomsCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/DeleteRoyaltyTemplate.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeleteRoyaltyTemplate.java new file mode 100644 index 0000000..2b9f4ad --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeleteRoyaltyTemplate.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class DeleteRoyaltyTemplate extends DeletedObjectBase { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedChannel.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedChannel.java new file mode 100644 index 0000000..00c6e41 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedChannel.java @@ -0,0 +1,22 @@ +package com.pingplusplus.model; + +/** + * Created by Afon on 17/03/27. + */ +public class DeletedChannel extends PingppObject { + String channel; + Boolean deleted; + + public String getChannel() { + return channel; + } + public void setChannel(String channel) { + this.channel = channel; + } + public Boolean getDeleted() { + return deleted; + } + public void setDeleted(Boolean deleted) { + this.deleted = deleted; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedCoupon.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedCoupon.java new file mode 100644 index 0000000..85272b7 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedCoupon.java @@ -0,0 +1,7 @@ +package com.pingplusplus.model; + +/** + * Created by Afon on 16/11/04. + */ +public class DeletedCoupon extends DeletedObjectBase { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedCouponTemplate.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedCouponTemplate.java new file mode 100644 index 0000000..0309144 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedCouponTemplate.java @@ -0,0 +1,7 @@ +package com.pingplusplus.model; + +/** + * Created by Afon on 16/11/04. + */ +public class DeletedCouponTemplate extends DeletedObjectBase { +} diff --git a/src/main/java/com/pingplusplus/model/DeletedCard.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedObjectBase.java similarity index 72% rename from src/main/java/com/pingplusplus/model/DeletedCard.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedObjectBase.java index b57fef6..d8227d2 100644 --- a/src/main/java/com/pingplusplus/model/DeletedCard.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedObjectBase.java @@ -1,9 +1,9 @@ package com.pingplusplus.model; /** - * Created by Afon on 15/12/23. + * Created by Afon on 17/03/27. */ -public class DeletedCard extends PingppObject implements DeletedPingppObject { +public abstract class DeletedObjectBase extends PingppObject implements DeletedPingppObject { String id; Boolean deleted; @@ -19,4 +19,4 @@ public Boolean getDeleted() { public void setDeleted(Boolean deleted) { this.deleted = deleted; } -} +} \ No newline at end of file diff --git a/src/main/java/com/pingplusplus/model/DeletedPingppObject.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedPingppObject.java similarity index 100% rename from src/main/java/com/pingplusplus/model/DeletedPingppObject.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedPingppObject.java diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedSettleAccount.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedSettleAccount.java new file mode 100644 index 0000000..d627289 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedSettleAccount.java @@ -0,0 +1,7 @@ +package com.pingplusplus.model; + +/** + * Created by Afon on 17/03/27. + */ +public class DeletedSettleAccount extends DeletedObjectBase { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedSplitReceiver.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedSplitReceiver.java new file mode 100644 index 0000000..bea8d75 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedSplitReceiver.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class DeletedSplitReceiver extends DeletedObjectBase { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedSubApp.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedSubApp.java new file mode 100644 index 0000000..230c430 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/DeletedSubApp.java @@ -0,0 +1,7 @@ +package com.pingplusplus.model; + +/** + * Created by Afon on 17/03/27. + */ +public class DeletedSubApp extends DeletedObjectBase { +} diff --git a/src/main/java/com/pingplusplus/model/Event.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Event.java similarity index 52% rename from src/main/java/com/pingplusplus/model/Event.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/Event.java index dd4c022..25a694f 100644 --- a/src/main/java/com/pingplusplus/model/Event.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Event.java @@ -1,11 +1,8 @@ package com.pingplusplus.model; -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; +import com.pingplusplus.exception.PingppException; import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; import java.util.Map; @@ -91,52 +88,47 @@ public void setRequest(String request) { * 查询 Event * * @param id - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @return Event + * @throws PingppException */ - public static Event retrieve(String id) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - return request(APIResource.RequestMethod.GET, instanceURL(Event.class, id), null, Event.class); + public static Event retrieve(String id) throws PingppException { + return retrieve(id, null, null); } /** * 查询 Event * * @param id - * @param params - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @param options Ping++ ApiKey + * @return Event + * @throws PingppException */ - public static Event retrieve(String id, Map params) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - return request(APIResource.RequestMethod.GET, instanceURL(Event.class, id), params, Event.class); + public static Event retrieve(String id, RequestOptions options) throws PingppException { + return retrieve(id, null, options); } /** * 查询 Event * + * @param id * @param params - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @return Event + * @throws PingppException */ - public static EventCollection all(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return request(APIResource.RequestMethod.GET, classURL(Event.class), params, EventCollection.class); + public static Event retrieve(String id, Map params) throws PingppException { + return retrieve(id, params, null); } + /** + * 查询 Event + * + * @param id + * @param params + * @param options the specific options + * @return Event + * @throws PingppException + */ + public static Event retrieve(String id, Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(Event.class, id), params, Event.class, options); + } } diff --git a/src/main/java/com/pingplusplus/model/EventCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/EventCollection.java similarity index 100% rename from src/main/java/com/pingplusplus/model/EventCollection.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/EventCollection.java diff --git a/src/main/java/com/pingplusplus/model/EventData.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/EventData.java similarity index 100% rename from src/main/java/com/pingplusplus/model/EventData.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/EventData.java diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/Identification.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Identification.java new file mode 100644 index 0000000..ee01014 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Identification.java @@ -0,0 +1,89 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class Identification extends APIResource { + String type; + Object app; + Integer resultCode; + String message; + Boolean paid; + Map data; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Boolean getPaid() { + return paid; + } + + public void setPaid(Boolean paid) { + this.paid = paid; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Integer getResultCode() { + return resultCode; + } + + public void setResultCode(Integer resultCode) { + this.resultCode = resultCode; + } + + public Map getData() { + return data; + } + + public void setData(Map data) { + this.data = data; + } + + public Object getApp() { + return app; + } + + public void setApp(Object app) { + this.app = app; + } + + /** + * 请求认证 + * + * @param params + * @return Identification + * @throws PingppException + */ + public static Identification identify(Map params) + throws PingppException { + return identify(params, null); + } + + /** + * 请求认证 + * + * @param params + * @param options the specific options + * @return Identification + * @throws PingppException + */ + public static Identification identify(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, singleClassURL(Identification.class), params, Identification.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/Order.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Order.java new file mode 100644 index 0000000..7d51268 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Order.java @@ -0,0 +1,582 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Order extends APIResource { + String id; + String object; + Long created; + Boolean livemode; + String status; + Boolean paid; + Boolean refunded; + Object app; + String charge; + String uid; + String merchantOrderNo; + Integer amount; + Integer couponAmount; + Integer actualAmount; + Integer amountRefunded; + Integer amountPaid; + String currency; + String subject; + String body; + String clientIp; + Long timePaid; + Long timeExpire; + String coupon; + ChargeCollection charges; + String description; + Map metadata; + ChargeEssentials chargeEssentials; + Long availableBalance; + String receiptApp; + String serviceApp; + List availableMethods; + Integer discountAmount; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Boolean getPaid() { + return paid; + } + + public void setPaid(Boolean paid) { + this.paid = paid; + } + + public Boolean getRefunded() { + return refunded; + } + + public void setRefunded(Boolean refunded) { + this.refunded = refunded; + } + + public Object getApp() { + return app; + } + + public void setApp(Object app) { + this.app = app; + } + + public String getUid() { + return uid; + } + + public void setUid(String uid) { + this.uid = uid; + } + + public String getMerchantOrderNo() { + return merchantOrderNo; + } + + public void setMerchantOrderNo(String merchantOrderNo) { + this.merchantOrderNo = merchantOrderNo; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public Integer getCouponAmount() { + return couponAmount; + } + + public void setCouponAmount(Integer couponAmount) { + this.couponAmount = couponAmount; + } + + public Integer getActualAmount() { + return actualAmount; + } + + public void setActualAmount(Integer actualAmount) { + this.actualAmount = actualAmount; + } + + public Integer getAmountRefunded() { + return amountRefunded; + } + + public void setAmountRefunded(Integer amountRefunded) { + this.amountRefunded = amountRefunded; + } + + public Integer getAmountPaid() { + return amountPaid; + } + + public void setAmountPaid(Integer amountPaid) { + this.amountPaid = amountPaid; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getClientIp() { + return clientIp; + } + + public void setClientIp(String clientIp) { + this.clientIp = clientIp; + } + + public Long getTimePaid() { + return timePaid; + } + + public void setTimePaid(Long timePaid) { + this.timePaid = timePaid; + } + + public Long getTimeExpire() { + return timeExpire; + } + + public void setTimeExpire(Long timeExpire) { + this.timeExpire = timeExpire; + } + + public String getCoupon() { + return coupon; + } + + public void setCoupon(String coupon) { + this.coupon = coupon; + } + + public ChargeCollection getCharges() { + return charges; + } + + public void setCharges(ChargeCollection charges) { + this.charges = charges; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public ChargeEssentials getChargeEssentials() { + return chargeEssentials; + } + + public void setChargeEssentials(ChargeEssentials chargeEssentials) { + this.chargeEssentials = chargeEssentials; + } + + public Long getAvailableBalance() { + return availableBalance; + } + + public void setAvailableBalance(Long availableBalance) { + this.availableBalance = availableBalance; + } + + public String getReceiptApp() { + return receiptApp; + } + + public void setReceiptApp(String receiptApp) { + this.receiptApp = receiptApp; + } + + public String getServiceApp() { + return serviceApp; + } + + public void setServiceApp(String serviceApp) { + this.serviceApp = serviceApp; + } + + public List getAvailableMethods() { + return availableMethods; + } + + public void setAvailableMethods(List availableMethods) { + this.availableMethods = availableMethods; + } + + public String getCharge() { + return charge; + } + + public void setCharge(String charge) { + this.charge = charge; + } + + public Integer getDiscountAmount() { + return discountAmount; + } + + public void setDiscountAmount(Integer discountAmount) { + this.discountAmount = discountAmount; + } + + /** + * 创建 order + * + * @param params + * @return Order + * @throws PingppException + */ + public static Order create(Map params) + throws PingppException { + return create(params, null); + } + + /** + * 创建 order + * + * @param params + * @param options the specific options + * @return Order + * @throws PingppException + */ + public static Order create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(Order.class), params, Order.class, options); + } + + /** + * 查询 order + * + * @param id + * @return Order + * @throws PingppException + */ + public static Order retrieve(String id) throws PingppException { + return retrieve(id, null, null); + } + + /** + * 查询 order + * + * @param id + * @param params + * @return Order + * @throws PingppException + */ + public static Order retrieve(String id, Map params) throws PingppException { + return retrieve(id, params, null); + } + + /** + * 查询 order + * + * @param id + * @param options the specific options + * @return Order + * @throws PingppException + */ + public static Order retrieve(String id, RequestOptions options) throws PingppException { + return retrieve(id, null, options); + } + + /** + * 查询 order + * + * @param id + * @param params + * @param options the specific options + * @return Order + * @throws PingppException + */ + public static Order retrieve(String id, Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(Order.class, id), params, Order.class, options); + } + + /** + * 查询 order 列表 + * + * @param params + * @return OrderCollection + * @throws PingppException + */ + public static OrderCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 order 列表 + * + * @param params + * @param options the specific options + * @return OrderCollection + * @throws PingppException + */ + public static OrderCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(Order.class), params, OrderCollection.class, options); + } + + /** + * 更新 order + * + * @param id + * @param params + * @return Order + * @throws PingppException + */ + public static Order update(String id, Map params) + throws PingppException { + return update(id, params, null); + } + + /** + * 更新 order + * + * @param id + * @param params + * @param options the specific options + * @return Order + * @throws PingppException + */ + public static Order update(String id, Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.PUT, instanceURL(Order.class, id), params, Order.class, options); + } + + /** + * 取消 order + * + * @return Order + * @throws PingppException + */ + public Order cancel() + throws PingppException { + Map params = new HashMap(); + params.put("status", "canceled"); + return Order.update(this.getId(), params, null); + } + + /** + * 取消 order + * + * @param options the specific options + * @return Order + * @throws PingppException + */ + public Order cancel(RequestOptions options) + throws PingppException { + Map params = new HashMap(); + params.put("status", "canceled"); + return Order.update(this.getId(), params, options); + } + + /** + * 取消 order + * + * @param id + * @return Order + * @throws PingppException + */ + public static Order cancel(String id) + throws PingppException { + Map params = new HashMap(); + params.put("status", "canceled"); + return update(id, params); + } + + /** + * 取消 order + * + * @param id + * @param options the specific options + * @return Order + * @throws PingppException + */ + public static Order cancel(String id, RequestOptions options) + throws PingppException { + Map params = new HashMap(); + params.put("status", "canceled"); + return update(id, params, options); + } + + /** + * 支付 order + * + * @param params + * @return Order + * @throws PingppException + */ + public Order pay(Map params) throws PingppException { + return Order.pay(this.getId(), params, null); + } + + /** + * 支付 order + * + * @param params + * @param options the specific options + * @return Order + * @throws PingppException + */ + public Order pay(Map params, RequestOptions options) throws PingppException { + return Order.pay(this.getId(), params, options); + } + + /** + * 支付 order + * + * @param id + * @param params + * @return Order + * @throws PingppException + */ + public static Order pay(String id, Map params) throws PingppException { + return pay(id, params, null); + } + + /** + * 支付 order + * + * @param id + * @param params + * @param options the specific options + * @return Order + * @throws PingppException + */ + public static Order pay(String id, Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, String.format("%s/pay", + instanceURL(Order.class, id)), params, Order.class, options); + } + + /** + * 查询订单 Charge 列表 + * + * @param id + * @param params + * @return ChargeCollection + * @throws PingppException + */ + public static ChargeCollection chargeList(String id, Map params) throws PingppException { + return chargeList(id, params, null); + } + + /** + * 查询订单 Charge 列表 + * + * @param id + * @param params + * @param options the specific options + * @return ChargeCollection + * @throws PingppException + */ + public static ChargeCollection chargeList(String id, Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, String.format("%s/charges", instanceURL(Order.class, id)), + params, ChargeCollection.class, options); + } + + /** + * 查询订单 Charge + * + * @param orderId + * @param chargeId + * @return Charge + * @throws PingppException + */ + public static Charge retrieveCharge(String orderId, String chargeId) throws PingppException { + return retrieveCharge(orderId, chargeId, null); + } + + /** + * 查询订单 Charge + * + * @param orderId + * @param chargeId + * @param options the specific options + * @return Charge + * @throws PingppException + */ + public static Charge retrieveCharge(String orderId, String chargeId, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, String.format("%s/charges/%s", instanceURL(Order.class, orderId), chargeId), + null, Charge.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/OrderCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/OrderCollection.java new file mode 100644 index 0000000..70dd500 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/OrderCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class OrderCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/OrderRefund.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/OrderRefund.java new file mode 100644 index 0000000..8d30fd3 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/OrderRefund.java @@ -0,0 +1,119 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class OrderRefund extends APIResource { + + /** + * 创建 order_refund + * + * @param orderId + * @param params + * @return OrderRefundCollection + * @throws PingppException + */ + public static OrderRefundCollection create(String orderId, Map params) + throws PingppException { + return create(orderId, params, null); + } + + /** + * 创建 order_refund + * + * @param orderId + * @param params + * @param options the specific options + * @return OrderRefundCollection + * @throws PingppException + */ + public static OrderRefundCollection create(String orderId, Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, String.format("%s/order_refunds", instanceURL(Order.class, orderId)), + params, OrderRefundCollection.class, options); + } + + /** + * 查询 order_refund + * + * @param orderId + * @param refundId + * @return Refund + * @throws PingppException + */ + public static Refund retrieve(String orderId, String refundId) + throws PingppException { + return retrieve(orderId, refundId, null); + } + + /** + * 查询 order_refund + * + * @param orderId + * @param refundId + * @param options the specific options + * @return Refund + * @throws PingppException + */ + public static Refund retrieve(String orderId, String refundId, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, String.format("%s/order_refunds/%s", instanceURL(Order.class, orderId), refundId), + null, Refund.class, options); + } + + /** + * 查询 order_refund 列表 + * + * @param orderId + * @param params + * @return OrderRefundCollection + * @throws PingppException + */ + public static OrderRefundCollection list(String orderId, Mapparams) + throws PingppException { + return list(orderId, params, null); + } + + /** + * 查询 order_refund 列表 + * + * @param orderId + * @return OrderRefundCollection + * @throws PingppException + */ + public static OrderRefundCollection list(String orderId) + throws PingppException { + return list(orderId, null, null); + } + + /** + * 查询 order_refund 列表 + * + * @param orderId + * @param options the specific options + * @return OrderRefundCollection + * @throws PingppException + */ + public static OrderRefundCollection list(String orderId, RequestOptions options) + throws PingppException { + return list(orderId, null, options); + } + + /** + * 查询 order_refund 列表 + * + * @param orderId + * @param params + * @param options the specific options + * @return OrderRefundCollection + * @throws PingppException + */ + public static OrderRefundCollection list(String orderId, Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, String.format("%s/order_refunds", instanceURL(Order.class, orderId)), + params, OrderRefundCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/OrderRefundCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/OrderRefundCollection.java new file mode 100644 index 0000000..80d6bda --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/OrderRefundCollection.java @@ -0,0 +1,5 @@ +package com.pingplusplus.model; + +public class OrderRefundCollection extends PingppCollection { + +} diff --git a/src/main/java/com/pingplusplus/model/PingppCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppCollection.java similarity index 100% rename from src/main/java/com/pingplusplus/model/PingppCollection.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/PingppCollection.java diff --git a/src/main/java/com/pingplusplus/model/PingppCollectionAPIResource.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppCollectionAPIResource.java similarity index 100% rename from src/main/java/com/pingplusplus/model/PingppCollectionAPIResource.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/PingppCollectionAPIResource.java diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppError.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppError.java new file mode 100644 index 0000000..49cfa1a --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppError.java @@ -0,0 +1,27 @@ +package com.pingplusplus.model; + +public class PingppError extends PingppObject { + String type; + + String message; + + String code; + + String param; + + public String getType() { + return type; + } + + public String getMessage() { + return message; + } + + public String getCode() { + return code; + } + + public String getParam() { + return param; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppObject.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppObject.java new file mode 100644 index 0000000..ee89588 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppObject.java @@ -0,0 +1,57 @@ +package com.pingplusplus.model; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.pingplusplus.net.PingppResponse; +import com.pingplusplus.serializer.*; + +import java.lang.reflect.Field; + +public abstract class PingppObject implements PingppObjectInterface { + + public static final Gson PRETTY_PRINT_GSON = new GsonBuilder() + .setPrettyPrinting() + .serializeNulls() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .disableHtmlEscaping() + .registerTypeAdapter(BatchTransferRecipient.class, new BatchTransferRecipientSerializer()) + .registerTypeAdapter(BatchRefundCharges.class, new BatchRefundChargesSerializer()) + .registerTypeAdapter(Double.class, new DoubleTypeSerializer()) + .registerTypeAdapter(ChargeEssentials.class, new ChargeEssentialsSerializer()) + .registerTypeAdapter(CouponTemplateExpiration.class, new CouponTemplateExpirationSerializer()) + .registerTypeAdapter(SettleAccountRecipient.class, new SettleAccountRecipientSerializer()) + .create(); + + public static Gson getPrettyPrintGson() { + try { + Class klass = Class.forName("com.pingplusplus.net.AppBasedResource"); + Field field = klass.getField("PRETTY_PRINT_GSON"); + return (Gson) field.get(klass); + } catch (ClassNotFoundException e) { + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } + + return PRETTY_PRINT_GSON; + } + + @Override + public String toString() { + return getPrettyPrintGson().toJson(this); + } + + private transient PingppResponse lastResponse; + + @Override + public PingppResponse getLastResponse() { + return lastResponse; + } + + @Override + public void setLastResponse(PingppResponse response) { + this.lastResponse = response; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppObjectInterface.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppObjectInterface.java new file mode 100644 index 0000000..3b68826 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppObjectInterface.java @@ -0,0 +1,9 @@ +package com.pingplusplus.model; + +import com.pingplusplus.net.PingppResponse; + +public interface PingppObjectInterface { + public PingppResponse getLastResponse(); + + public void setLastResponse(PingppResponse response); +} diff --git a/src/main/java/com/pingplusplus/model/PingppRawJsonObject.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/PingppRawJsonObject.java similarity index 100% rename from src/main/java/com/pingplusplus/model/PingppRawJsonObject.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/PingppRawJsonObject.java diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/ProfitTransaction.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/ProfitTransaction.java new file mode 100644 index 0000000..cdd5f23 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/ProfitTransaction.java @@ -0,0 +1,187 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +/** + * 分账明细 + */ +public class ProfitTransaction extends APIResource { + String id; + String object; + Boolean livemode; + String app; + Long created; + Integer amount; + String currency; + String name; + String status; + String description; + String splitReceiver; + String splitProfit; + Long timeFinished; + String failureMsg; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getSplitReceiver() { + return splitReceiver; + } + + public void setSplitReceiver(String splitReceiver) { + this.splitReceiver = splitReceiver; + } + + public String getSplitProfit() { + return splitProfit; + } + + public void setSplitProfit(String splitProfit) { + this.splitProfit = splitProfit; + } + + public Long getTimeFinished() { + return timeFinished; + } + + public void setTimeFinished(Long timeFinished) { + this.timeFinished = timeFinished; + } + + public String getFailureMsg() { + return failureMsg; + } + + public void setFailureMsg(String failureMsg) { + this.failureMsg = failureMsg; + } + + /** + * 查询分账明细 + * + * @param id id + * @return ProfitTransaction + * @throws PingppException + */ + public static ProfitTransaction retrieve(String id) throws PingppException { + return retrieve(id, null); + } + + /** + * 查询分账明细 + * + * @param id id + * @param options the specific options + * @return ProfitTransaction + * @throws PingppException + */ + public static ProfitTransaction retrieve(String id, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(ProfitTransaction.class, id), null, ProfitTransaction.class, options); + } + + /** + * 查询分账明细列表 + * + * @param params 分页参数等 + * @return ProfitTransactionCollection + * @throws PingppException + */ + public static ProfitTransactionCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询分账明细列表 + * + * @param params 分页参数等 + * @param options the specific options + * @return ProfitTransactionCollection + * @throws PingppException + */ + public static ProfitTransactionCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(ProfitTransaction.class), params, ProfitTransactionCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/ProfitTransactionCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/ProfitTransactionCollection.java new file mode 100644 index 0000000..07a2f59 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/ProfitTransactionCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class ProfitTransactionCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/Recharge.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Recharge.java new file mode 100644 index 0000000..5a08820 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Recharge.java @@ -0,0 +1,239 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class Recharge extends AppBasedResource { + String id; + String object; + String app; + Long created; + Boolean livemode; + Integer amount; + Boolean succeeded; + Long timeSucceeded; + Boolean refunded; + String user; + String fromUser; + Long userFee; + Charge charge; + BalanceBonus balanceBonus; + String balanceTransaction; + String description; + Map metadata; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public Boolean getSucceeded() { + return succeeded; + } + + public void setSucceeded(Boolean succeeded) { + this.succeeded = succeeded; + } + + public Long getTimeSucceeded() { + return timeSucceeded; + } + + public void setTimeSucceeded(Long timeSucceeded) { + this.timeSucceeded = timeSucceeded; + } + + public Boolean getRefunded() { + return refunded; + } + + public void setRefunded(Boolean refunded) { + this.refunded = refunded; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getFromUser() { + return fromUser; + } + + public void setFromUser(String fromUser) { + this.fromUser = fromUser; + } + + public Long getUserFee() { + return userFee; + } + + public void setUserFee(Long userFee) { + this.userFee = userFee; + } + + public Charge getCharge() { + return charge; + } + + public void setCharge(Charge charge) { + this.charge = charge; + } + + public BalanceBonus getBalanceBonus() { + return balanceBonus; + } + + public void setBalanceBonus(BalanceBonus balanceBonus) { + this.balanceBonus = balanceBonus; + } + + public String getBalanceTransaction() { + return balanceTransaction; + } + + public void setBalanceTransaction(String balanceTransaction) { + this.balanceTransaction = balanceTransaction; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + /** + * 创建 recharge + * + * @param params + * @return Recharge + * @throws PingppException + */ + public static Recharge create(Map params) + throws PingppException { + return create(params, null); + } + + /** + * 创建 recharge + * + * @param params + * @param options the specific options + * @return Recharge + * @throws PingppException + */ + public static Recharge create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(Recharge.class), params, Recharge.class, options); + } + + /** + * 查询 recharge + * + * @param id + * @return Recharge + * @throws PingppException + */ + public static Recharge retrieve(String id) + throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 recharge + * + * @param id + * @param options the specific options + * @return Recharge + * @throws PingppException + */ + public static Recharge retrieve(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(Recharge.class, id), null, Recharge.class, options); + } + + /** + * 查询 recharge 列表 + * + * @param params + * @return RechargeCollection + * @throws PingppException + */ + public static RechargeCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 recharge 列表 + * + * @param params + * @param options the specific options + * @return RechargeCollection + * @throws PingppException + */ + public static RechargeCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(Recharge.class), params, RechargeCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/RechargeCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RechargeCollection.java new file mode 100644 index 0000000..b0c3c1e --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RechargeCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class RechargeCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/RechargeRefund.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RechargeRefund.java new file mode 100644 index 0000000..99a9f07 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RechargeRefund.java @@ -0,0 +1,120 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class RechargeRefund extends AppBasedResource { + /** + * 创建 recharge_refund + * + * @param rechargeId + * @param params + * @return Refund + * @throws PingppException + */ + public static Refund create(String rechargeId, Map params) + throws PingppException { + return create(rechargeId, params, null); + } + + /** + * 创建 recharge_refund + * + * @param rechargeId + * @param params + * @param options the specific options + * @return Refund + * @throws PingppException + */ + public static Refund create(String rechargeId, Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, String.format("%s/refunds", instanceURL(Recharge.class, rechargeId)), + params, Refund.class, options); + } + + /** + * 查询 recharge_refund + * + * @param rechargeId + * @param refundId + * @return Refund + * @throws PingppException + */ + public static Refund retrieve(String rechargeId, String refundId) + throws PingppException { + return retrieve(rechargeId, refundId, null); + } + + /** + * 查询 recharge_refund + * + * @param rechargeId + * @param refundId + * @param options the specific options + * @return Refund + * @throws PingppException + */ + public static Refund retrieve(String rechargeId, String refundId, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, String.format("%s/refunds/%s", instanceURL(Recharge.class, rechargeId), refundId), + null, Refund.class, options); + } + + /** + * 查询 recharge_refund 列表 + * + * @param rechargeId + * @return RechargeRefundCollection + * @throws PingppException + */ + public static RechargeRefundCollection list(String rechargeId) + throws PingppException { + return list(rechargeId, null, null); + } + + /** + * 查询 recharge_refund 列表 + * + * @param rechargeId + * @param options the specific options + * @return RechargeRefundCollection + * @throws PingppException + */ + public static RechargeRefundCollection list(String rechargeId, RequestOptions options) + throws PingppException { + return list(rechargeId, null, options); + + } + + /** + * 查询 recharge_refund 列表 + * + * @param rechargeId + * @param params + * @return RechargeRefundCollection + * @throws PingppException + */ + public static RechargeRefundCollection list(String rechargeId, Mapparams) + throws PingppException { + return list(rechargeId, params, null); + } + + /** + * 查询 recharge_refund 列表 + * + * @param rechargeId + * @param params + * @param options the specific options + * @return RechargeRefundCollection + * @throws PingppException + */ + public static RechargeRefundCollection list(String rechargeId, Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, String.format("%s/refunds", instanceURL(Recharge.class, rechargeId)), + params, RechargeRefundCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/RechargeRefundCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RechargeRefundCollection.java new file mode 100644 index 0000000..494497b --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RechargeRefundCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class RechargeRefundCollection extends PingppCollection { +} diff --git a/src/main/java/com/pingplusplus/model/RedEnvelope.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RedEnvelope.java similarity index 59% rename from src/main/java/com/pingplusplus/model/RedEnvelope.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/RedEnvelope.java index 0be2ceb..f433bb9 100644 --- a/src/main/java/com/pingplusplus/model/RedEnvelope.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RedEnvelope.java @@ -8,12 +8,9 @@ import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.gson.LongSerializationPolicy; -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; +import com.pingplusplus.exception.PingppException; import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; import java.lang.reflect.Type; import java.util.Map; @@ -39,23 +36,7 @@ public class RedEnvelope extends APIResource { String description; String failureMsg; Map extra; - Map metadata; - - public static final Gson PRETTY_PRINT_GSON = new GsonBuilder(). - setPrettyPrinting(). - serializeNulls(). - disableHtmlEscaping(). - setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES). - setLongSerializationPolicy(LongSerializationPolicy.STRING). - registerTypeAdapter(Double.class, new JsonSerializer() { - @Override - public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) { - if (src == src.longValue()) - return new JsonPrimitive(src.longValue()); - return new JsonPrimitive(src); - } - }). - create(); + Map metadata; public String getStatus() { return status; @@ -218,47 +199,60 @@ public void setBody(String body) { this.body = body; } - public Map getMetadata() { + public Map getMetadata() { return metadata; } - public void setMetadata(Map metadata) { + public void setMetadata(Map metadata) { this.metadata = metadata; } - /** * 创建 RedEnvelope * * @param params - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @return RedEnvelope + * @throws PingppException */ public static RedEnvelope create(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return request(RequestMethod.POST, classURL(RedEnvelope.class), params, RedEnvelope.class); + throws PingppException { + return create(params, null); + } + + /** + * 创建 RedEnvelope + * + * @param params + * @param options the specific options + * @return RedEnvelope + * @throws PingppException + */ + public static RedEnvelope create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(RedEnvelope.class), params, RedEnvelope.class, options); + } + + /** + * 查询 RedEnvelope + * + * @param id + * @return RedEnvelope + * @throws PingppException + */ + public static RedEnvelope retrieve(String id) throws PingppException { + return retrieve(id, null, null); } /** * 查询 RedEnvelope * * @param id - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @param options the specific options + * @return RedEnvelope + * @throws PingppException */ - public static RedEnvelope retrieve(String id) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - return request(RequestMethod.GET, instanceURL(RedEnvelope.class, id), null, RedEnvelope.class); + public static RedEnvelope retrieve(String id, RequestOptions options) throws PingppException { + return retrieve(id, null, options); } /** @@ -266,34 +260,49 @@ public static RedEnvelope retrieve(String id) throws AuthenticationException, * * @param id * @param params - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @return RedEnvelope + * @throws PingppException + */ + public static RedEnvelope retrieve(String id, Map params) throws PingppException { + return retrieve(id, params, null); + } + + /** + * 查询 RedEnvelope + * + * @param id + * @param params + * @param options the specific options + * @return RedEnvelope + * @throws PingppException + */ + public static RedEnvelope retrieve(String id, Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(RedEnvelope.class, id), params, RedEnvelope.class, options); + } + + /** + * 查询 RedEnvelope + * + * @param params + * @return RedEnvelopeCollection + * @throws PingppException */ - public static RedEnvelope retrieve(String id, Map params) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - return request(RequestMethod.GET, instanceURL(RedEnvelope.class, id), params, RedEnvelope.class); + public static RedEnvelopeCollection list(Map params) + throws PingppException { + return list(params, null); } /** * 查询 RedEnvelope * * @param params - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @param options the specific options + * @return RedEnvelopeCollection + * @throws PingppException */ - public static RedEnvelopeCollection all(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return request(RequestMethod.GET, classURL(RedEnvelope.class), params, RedEnvelopeCollection.class); + public static RedEnvelopeCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(RedEnvelope.class), params, RedEnvelopeCollection.class, options); } } diff --git a/src/main/java/com/pingplusplus/model/RedEnvelopeCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RedEnvelopeCollection.java similarity index 100% rename from src/main/java/com/pingplusplus/model/RedEnvelopeCollection.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/RedEnvelopeCollection.java diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/Refund.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Refund.java new file mode 100644 index 0000000..9120769 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Refund.java @@ -0,0 +1,269 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class Refund extends APIResource { + String id; + String app; + String object; + String orderNo; + Integer amount; + String currency; + Long created; + Boolean succeed; + String status; + Long timeSucceed; + String description; + String failureCode; + String failureMsg; + Map metadata; + String charge; + String chargeOrderNo; + String transactionNo; + String fundingSource; + Map extra; + + public String getInstanceURL() { + if (this.charge != null) { + return String.format("%s/%s/refunds/%s", classURL(Charge.class), this.charge, this.getId()); + } + return null; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public void setId(String id) { + this.id = id; + } + public String getId() { + return id; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getCharge() { + return charge; + } + + public void setCharge(String charge) { + this.charge = charge; + } + + public Boolean getSucceed() { + return succeed; + } + + public void setSucceed(Boolean succeed) { + this.succeed = succeed; + } + + public Long getTimeSucceed() { + return timeSucceed; + } + + public void setTimeSucceed(Long timeSucceed) { + this.timeSucceed = timeSucceed; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getFailureMsg() { + return failureMsg; + } + + public void setFailureMsg(String failureMsg) { + this.failureMsg = failureMsg; + } + + public String getFailureCode() { + return failureCode; + } + + public void setFailureCode(String failureCode) { + this.failureCode = failureCode; + } + + public String getOrderNo() { + return orderNo; + } + + public void setOrderNo(String orderNo) { + this.orderNo = orderNo; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public String getChargeOrderNo() { + return chargeOrderNo; + } + + public void setChargeOrderNo(String chargeOrderNo) { + this.chargeOrderNo = chargeOrderNo; + } + + public String getTransactionNo() { + return transactionNo; + } + + public void setTransactionNo(String transactionNo) { + this.transactionNo = transactionNo; + } + + public String getFundingSource() { + return fundingSource; + } + + public void setFundingSource(String fundingSource) { + this.fundingSource = fundingSource; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + /** + * 创建 refund + * + * @param chargeId + * @param params + * @return Refund + * @throws PingppException + */ + public static Refund create(String chargeId, Map params) + throws PingppException { + return create(chargeId, params, null); + } + + /** + * 创建 refund + * + * @param chargeId + * @param params + * @param options the specific options + * @return Refund + * @throws PingppException + */ + public static Refund create(String chargeId, Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, String.format("%s/refunds", instanceURL(Charge.class, chargeId)), + params, Refund.class, options); + } + + /** + * 查询 refund + * + * @param chargeId + * @param id + * @return Refund + * @throws PingppException + */ + public static Refund retrieve(String chargeId, String id) + throws PingppException { + return retrieve(chargeId, id, null); + } + + /** + * 查询 refund + * + * @param chargeId + * @param id + * @param options the specific options + * @return Refund + * @throws PingppException + */ + public static Refund retrieve(String chargeId, String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, String.format("%s/refunds/%s", instanceURL(Charge.class, chargeId), id),null, Refund.class, options); + } + + /** + * 查询 refund 列表 + * + * @param chargeId + * @param params + * @return ChargeRefundCollection + * @throws PingppException + */ + public static ChargeRefundCollection list(String chargeId, Mapparams) + throws PingppException { + return list(chargeId, params, null); + } + + /** + * 查询 refund 列表 + * + * @param chargeId + * @param params + * @param options the specific options + * @return ChargeRefundCollection + * @throws PingppException + */ + public static ChargeRefundCollection list(String chargeId, Mapparams, RequestOptions options) + throws PingppException { + return request(RequestMethod.GET, String.format("%s/refunds", instanceURL(Charge.class, chargeId)), + params, ChargeRefundCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/Royalty.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Royalty.java new file mode 100644 index 0000000..c641ec7 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Royalty.java @@ -0,0 +1,284 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class Royalty extends APIResource { + String id; + String object; + Boolean livemode; + Long created; + Integer amount; + String description; + String method; + String payerApp; + String recipientApp; + String royaltyTransaction; + String royaltySettlement; + String settleAccount; + String sourceApp; + String sourceNo; + String sourceUrl; + String sourceUser; + String status; + Long timeSettled; + Map metadata; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getPayerApp() { + return payerApp; + } + + public void setPayerApp(String payerApp) { + this.payerApp = payerApp; + } + + public String getRecipientApp() { + return recipientApp; + } + + public void setRecipientApp(String recipientApp) { + this.recipientApp = recipientApp; + } + + public String getRoyaltyTransaction() { + return royaltyTransaction; + } + + public void setRoyaltyTransaction(String royaltyTransaction) { + this.royaltyTransaction = royaltyTransaction; + } + + public String getSettleAccount() { + return settleAccount; + } + + public void setSettleAccount(String settleAccount) { + this.settleAccount = settleAccount; + } + + public String getSourceApp() { + return sourceApp; + } + + public void setSourceApp(String sourceApp) { + this.sourceApp = sourceApp; + } + + public String getSourceNo() { + return sourceNo; + } + + public void setSourceNo(String sourceNo) { + this.sourceNo = sourceNo; + } + + public String getSourceUrl() { + return sourceUrl; + } + + public void setSourceUrl(String sourceUrl) { + this.sourceUrl = sourceUrl; + } + + public String getSourceUser() { + return sourceUser; + } + + public void setSourceUser(String sourceUser) { + this.sourceUser = sourceUser; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Long getTimeSettled() { + return timeSettled; + } + + public void setTimeSettled(Long timeSettled) { + this.timeSettled = timeSettled; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public String getRoyaltySettlement() { + return royaltySettlement; + } + + public void setRoyaltySettlement(String royaltySettlement) { + this.royaltySettlement = royaltySettlement; + } + + /** + * 查询 royalty + * + * @param id + * @return Royalty + * @throws PingppException + */ + public static Royalty retrieve(String id) throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 royalty + * + * @param id + * @param options the specific options + * @return Royalty + * @throws PingppException + */ + public static Royalty retrieve(String id, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(Royalty.class, id), null, Royalty.class, options); + } + + /** + * 查询 royalty 列表 + * + * @param params + * @return RoyaltyCollection + * @throws PingppException + */ + public static RoyaltyCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 royalty 列表 + * + * @param params + * @param options the specific options + * @return RoyaltyCollection + * @throws PingppException + */ + public static RoyaltyCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(Royalty.class), params, RoyaltyCollection.class, options); + } + + /** + * 批量更新 royalty + * + * @param params + * @return RoyaltyCollection + * @throws PingppException + */ + public static RoyaltyCollection batchUpdate(Map params) + throws PingppException { + return batchUpdate(params, null); + } + + /** + * 批量更新 royalty + * + * @param params + * @param options the specific options + * @return RoyaltyCollection + * @throws PingppException + */ + public static RoyaltyCollection batchUpdate(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.PUT, classURL(Royalty.class), params, RoyaltyCollection.class, options); + } + + /** + * 创建分润 + * + * @param orderId 订单 ID + * @param params 分润信息参数 + * @return RoyaltyDataResult + * @throws PingppException + */ + public static RoyaltyDataResult createData(String orderId, Map params) + throws PingppException { + return createData(orderId, params, null); + } + + /** + * 创建分润 + * + * @param orderId 订单 ID + * @param params 分润信息参数 + * @param options the specific options + * @return RoyaltyDataResult + * @throws PingppException + */ + public static RoyaltyDataResult createData(String orderId, Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, + String.format("%s/royalty_datas", instanceURL(Order.class, orderId)), + params, + RoyaltyDataResult.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyCollection.java new file mode 100644 index 0000000..ed35300 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class RoyaltyCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyDataResult.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyDataResult.java new file mode 100644 index 0000000..b6902ed --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyDataResult.java @@ -0,0 +1,42 @@ +package com.pingplusplus.model; + +import com.pingplusplus.net.APIResource; + +public class RoyaltyDataResult extends APIResource { + String app; + Boolean livemode; + String order; + Boolean succeeded; + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getOrder() { + return order; + } + + public void setOrder(String order) { + this.order = order; + } + + public Boolean getSucceeded() { + return succeeded; + } + + public void setSucceeded(Boolean succeeded) { + this.succeeded = succeeded; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltySettlement.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltySettlement.java new file mode 100644 index 0000000..e095ecc --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltySettlement.java @@ -0,0 +1,288 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class RoyaltySettlement extends APIResource { + String id; + String object; + Boolean livemode; + Long created; + Long amount; + Long amountSucceeded; + Long amountFailed; + Long amountCanceled; + Integer count; + Integer countSucceeded; + Integer countFailed; + Integer countCanceled; + Integer fee; + String method; + String operationUrl; + String payerApp; + String status; + Long timeFinished; + RoyaltyTransactionCollection royaltyTransactions; + Map metadata; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Long getAmount() { + return amount; + } + + public void setAmount(Long amount) { + this.amount = amount; + } + + public Long getAmountSucceeded() { + return amountSucceeded; + } + + public void setAmountSucceeded(Long amountSucceeded) { + this.amountSucceeded = amountSucceeded; + } + + public Long getAmountFailed() { + return amountFailed; + } + + public void setAmountFailed(Long amountFailed) { + this.amountFailed = amountFailed; + } + + public Long getAmountCanceled() { + return amountCanceled; + } + + public void setAmountCanceled(Long amountCanceled) { + this.amountCanceled = amountCanceled; + } + + public Integer getCount() { + return count; + } + + public void setCount(Integer count) { + this.count = count; + } + + public Integer getCountSucceeded() { + return countSucceeded; + } + + public void setCountSucceeded(Integer countSucceeded) { + this.countSucceeded = countSucceeded; + } + + public Integer getCountFailed() { + return countFailed; + } + + public void setCountFailed(Integer countFailed) { + this.countFailed = countFailed; + } + + public Integer getCountCanceled() { + return countCanceled; + } + + public void setCountCanceled(Integer countCanceled) { + this.countCanceled = countCanceled; + } + + public Integer getFee() { + return fee; + } + + public void setFee(Integer fee) { + this.fee = fee; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getOperationUrl() { + return operationUrl; + } + + public void setOperationUrl(String operationUrl) { + this.operationUrl = operationUrl; + } + + public String getPayerApp() { + return payerApp; + } + + public void setPayerApp(String payerApp) { + this.payerApp = payerApp; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Long getTimeFinished() { + return timeFinished; + } + + public void setTimeFinished(Long timeFinished) { + this.timeFinished = timeFinished; + } + + public RoyaltyTransactionCollection getRoyaltyTransactions() { + return royaltyTransactions; + } + + public void setRoyaltyTransactions(RoyaltyTransactionCollection royaltyTransactions) { + this.royaltyTransactions = royaltyTransactions; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + /** + * 创建 royalty_settlement + * + * @param params + * @return RoyaltySettlement + * @throws PingppException + */ + public static RoyaltySettlement create(Map params) throws PingppException { + return create(params, null); + } + + /** + * 创建 royalty_settlement + * + * @param params + * @param options the specific options + * @return RoyaltySettlement + * @throws PingppException + */ + public static RoyaltySettlement create(Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(RoyaltySettlement.class), params, RoyaltySettlement.class, options); + } + + /** + * 查询 royalty_settlement + * + * @param id + * @return RoyaltySettlement + * @throws PingppException + */ + public static RoyaltySettlement retrieve(String id) throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 royalty_settlement + * + * @param id + * @param options the specific options + * @return RoyaltySettlement + * @throws PingppException + */ + public static RoyaltySettlement retrieve(String id, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(RoyaltySettlement.class, id), null, RoyaltySettlement.class, options); + } + + /** + * 查询 royalty_settlement 列表 + * + * @param params + * @return RoyaltySettlement + * @throws PingppException + */ + public static RoyaltySettlementCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 royalty_settlement 列表 + * + * @param params + * @param options the specific options + * @return RoyaltySettlement + * @throws PingppException + */ + public static RoyaltySettlementCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(RoyaltySettlement.class), params, RoyaltySettlementCollection.class, options); + } + + /** + * 更新 royalty_settlement + * + * @param id + * @param params + * @return RoyaltySettlement + * @throws PingppException + */ + public static RoyaltySettlement update(String id, Map params) + throws PingppException { + return update(id, params, null); + } + + /** + * 更新 royalty_settlement + * + * @param id + * @param params + * @param options the specific options + * @return RoyaltySettlement + * @throws PingppException + */ + public static RoyaltySettlement update(String id, Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.PUT, instanceURL(RoyaltySettlement.class, id), params, RoyaltySettlement.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltySettlementCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltySettlementCollection.java new file mode 100644 index 0000000..78f1697 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltySettlementCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class RoyaltySettlementCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTemplate.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTemplate.java new file mode 100644 index 0000000..94f2877 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTemplate.java @@ -0,0 +1,203 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class RoyaltyTemplate extends APIResource { + String id; + String object; + Boolean livemode; + String app; + String name; + Long created; + String description; + Map rule; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Map getRule() { + return rule; + } + + public void setRule(Map rule) { + this.rule = rule; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + /** + * 创建 royalty_template + * + * @param params + * @return RoyaltyTemplate + * @throws PingppException + */ + public static RoyaltyTemplate create(Map params) throws PingppException { + return create(params, null); + } + + /** + * 创建 royalty_template + * + * @param params + * @param options the specific options + * @return RoyaltyTemplate + * @throws PingppException + */ + public static RoyaltyTemplate create(Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(RoyaltyTemplate.class), params, RoyaltyTemplate.class, options); + } + + /** + * 查询 royalty_template + * + * @param id + * @return RoyaltyTemplate + * @throws PingppException + */ + public static RoyaltyTemplate retrieve(String id) throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 royalty_template + * + * @param id + * @param options the specific options + * @return RoyaltyTemplate + * @throws PingppException + */ + public static RoyaltyTemplate retrieve(String id, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(RoyaltyTemplate.class, id), null, RoyaltyTemplate.class, options); + } + + /** + * 查询 royalty_template 列表 + * + * @param params + * @return RoyaltyTemplateCollection + * @throws PingppException + */ + public static RoyaltyTemplateCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 royalty_template 列表 + * + * @param params + * @param options the specific options + * @return RoyaltyTemplateCollection + * @throws PingppException + */ + public static RoyaltyTemplateCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(RoyaltyTemplate.class), params, RoyaltyTemplateCollection.class, options); + } + + /** + * 删除 royalty_template + * + * @param id + * @return DeleteRoyaltyTemplate + * @throws PingppException + */ + public static DeleteRoyaltyTemplate delete(String id) + throws PingppException { + return delete(id, null); + } + + /** + * 删除 royalty_template + * + * @param id + * @param options the specific options + * @return DeleteRoyaltyTemplate + * @throws PingppException + */ + public static DeleteRoyaltyTemplate delete(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.DELETE, instanceURL(RoyaltyTemplate.class, id), null, DeleteRoyaltyTemplate.class, options); + } + + /** + * 更新 royalty_template + * + * @param id + * @return RoyaltyTemplate + * @throws PingppException + */ + public static RoyaltyTemplate update(String id, Map params) + throws PingppException { + return update(id, params, null); + } + + /** + * 更新 royalty_template + * + * @param id + * @param options the specific options + * @return RoyaltyTemplate + * @throws PingppException + */ + public static RoyaltyTemplate update(String id, Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.PUT, instanceURL(RoyaltyTemplate.class, id), params, RoyaltyTemplate.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTemplateCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTemplateCollection.java new file mode 100644 index 0000000..a7803a4 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTemplateCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class RoyaltyTemplateCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTransaction.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTransaction.java new file mode 100644 index 0000000..c117952 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTransaction.java @@ -0,0 +1,157 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class RoyaltyTransaction extends APIResource { + String id; + String object; + Integer amount; + Long created; + String recipientApp; + String royaltySettlement; + String settleAccount; + String sourceUser; + String status; + String failureMsg; + String transfer; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getRecipientApp() { + return recipientApp; + } + + public void setRecipientApp(String recipientApp) { + this.recipientApp = recipientApp; + } + + public String getRoyaltySettlement() { + return royaltySettlement; + } + + public void setRoyaltySettlement(String royaltySettlement) { + this.royaltySettlement = royaltySettlement; + } + + public String getSettleAccount() { + return settleAccount; + } + + public void setSettleAccount(String settleAccount) { + this.settleAccount = settleAccount; + } + + public String getSourceUser() { + return sourceUser; + } + + public void setSourceUser(String sourceUser) { + this.sourceUser = sourceUser; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getFailureMsg() { + return failureMsg; + } + + public void setFailureMsg(String failureMsg) { + this.failureMsg = failureMsg; + } + + public String getTransfer() { + return transfer; + } + + public void setTransfer(String transfer) { + this.transfer = transfer; + } + + /** + * 查询 royalty_transaction + * + * @param id + * @return RoyaltyTransaction + * @throws PingppException + */ + public static RoyaltyTransaction retrieve(String id) throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 royalty_transaction + * + * @param id + * @param options the specific options + * @return RoyaltyTransaction + * @throws PingppException + */ + public static RoyaltyTransaction retrieve(String id, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(RoyaltyTransaction.class, id), null, RoyaltyTransaction.class, options); + } + + /** + * 查询 royalty_transaction 列表 + * + * @param params + * @return RoyaltyTransactionCollection + * @throws PingppException + */ + public static RoyaltyTransactionCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 royalty_transaction 列表 + * + * @param params + * @param options the specific options + * @return RoyaltyTransactionCollection + * @throws PingppException + */ + public static RoyaltyTransactionCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(RoyaltyTransaction.class), params, RoyaltyTransactionCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTransactionCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTransactionCollection.java new file mode 100644 index 0000000..b66107c --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/RoyaltyTransactionCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class RoyaltyTransactionCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SettleAccount.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SettleAccount.java new file mode 100644 index 0000000..5794490 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SettleAccount.java @@ -0,0 +1,268 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; +import com.pingplusplus.net.UserBasedResource; + +import java.util.Map; + +public class SettleAccount extends UserBasedResource { + String id; + String object; + Boolean livemode; + String channel; + Long created; + SettleAccountRecipient recipient; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public SettleAccountRecipient getRecipient() { + return recipient; + } + + public void setRecipient(SettleAccountRecipient recipient) { + this.recipient = recipient; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + /** + * 创建 settle_account + * + * @param userId + * @param params + * @return SettleAccount + * @throws PingppException + */ + public static SettleAccount create(String userId, Mapparams) + throws PingppException { + User.checkUserId(userId); + return create(userId, params, null); + } + + /** + * 创建 settle_account + * + * @param userId + * @param params + * @param options the specific options + * @return SettleAccount + * @throws PingppException + */ + public static SettleAccount create(String userId, Mapparams, RequestOptions options) + throws PingppException { + User.checkUserId(userId); + return APIResource.request(APIResource.RequestMethod.POST, classURL(SettleAccount.class, userId), params, SettleAccount.class, options); + } + + /** + * 查询 settle_account + * + * @param userId + * @param id + * @return SettleAccount + * @throws PingppException + */ + public static SettleAccount retrieve(String userId, String id) + throws PingppException { + User.checkUserId(userId); + return retrieve(userId, id, null); + } + + /** + * 查询 settle_account + * + * @param userId + * @param id + * @param options the specific options + * @return SettleAccount + * @throws PingppException + */ + public static SettleAccount retrieve(String userId, String id, RequestOptions options) + throws PingppException { + User.checkUserId(userId); + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(SettleAccount.class, userId, id), null, SettleAccount.class, options); + } + + /** + * 查询 settle_account 列表 + * + * @param userId + * @param params + * @return SettleAccountCollection + * @throws PingppException + */ + public static SettleAccountCollection list(String userId, Map params) + throws PingppException { + User.checkUserId(userId); + return list(userId, params, null); + } + + /** + * 查询 settle_account 列表 + * + * @param userId + * @param params + * @param options the specific options + * @return SettleAccountCollection + * @throws PingppException + */ + public static SettleAccountCollection list(String userId, Map params, RequestOptions options) + throws PingppException { + User.checkUserId(userId); + return APIResource.request(APIResource.RequestMethod.GET, classURL(SettleAccount.class, userId), params, SettleAccountCollection.class, options); + } + + /** + * 删除 settle_account + * + * @param userId + * @param id + * @return DeletedSettleAccount + * @throws PingppException + */ + public static DeletedSettleAccount delete(String userId, String id) + throws PingppException { + User.checkUserId(userId); + return delete(userId, id, null); + } + + /** + * 删除 settle_account + * + * @param userId + * @param id + * @param options the specific options + * @return DeletedSettleAccount + * @throws PingppException + */ + public static DeletedSettleAccount delete(String userId, String id, RequestOptions options) + throws PingppException { + User.checkUserId(userId); + return APIResource.request(APIResource.RequestMethod.DELETE, instanceURL(SettleAccount.class, userId, id), null, DeletedSettleAccount.class, options); + } + + /** + * 更新 settle_account + * + * @param userId 用户 ID + * @param id 结算账户 ID + * @param params 更新数据 + * @return SettleAccount + * @throws PingppException + */ + public static SettleAccount update(String userId, String id, Map params) + throws PingppException { + User.checkUserId(userId); + return update(userId, id, params, null); + } + + /** + * 更新 settle_account + * + * @param userId 用户 ID + * @param id 结算账户 ID + * @param params 更新数据 + * @param options the specific options + * @return SettleAccount + * @throws PingppException + */ + public static SettleAccount update(String userId, String id, Map params, RequestOptions options) + throws PingppException { + User.checkUserId(userId); + return APIResource.request(APIResource.RequestMethod.PUT, instanceURL(SettleAccount.class, userId, id), params, SettleAccount.class, options); + } + + /** + * 更新银行手机号 + * + * @param userId 用户 ID + * @param id 结算账号 ID + * @param params 更新参数 + * @return SettleAccount + * @throws PingppException + */ + public static SettleAccount updateMobile(String userId, String id, Map params) throws PingppException { + return updateMobile(userId, id, params, null); + } + + /** + * 更新银行手机号 + * + * @param userId 用户 ID + * @param id 结算账号 ID + * @param params 更新参数 + * @param options the specific options + * @return SettleAccount + * @throws PingppException + */ + public static SettleAccount updateMobile(String userId, String id, Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.PUT, String.format("%s/mobile", instanceURL(SettleAccount.class, userId, id)), + params, SettleAccount.class, options); + } + + /** + * 打款验证 + * + * @param userId 用户 ID + * @param id 结算账号 ID + * @param params 参数 + * @return SettleAccount + * @throws PingppException + */ + public static SettleAccount verify(String userId, String id, Map params) throws PingppException { + return verify(userId, id, params, null); + } + + /** + * 打款验证 + * + * @param userId 用户 ID + * @param id 结算账号 ID + * @param params 参数 + * @param options the specific options + * @return SettleAccount + * @throws PingppException + */ + public static SettleAccount verify(String userId, String id, Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, String.format("%s/verify", instanceURL(SettleAccount.class, userId, id)), + params, SettleAccount.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SettleAccountCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SettleAccountCollection.java new file mode 100644 index 0000000..e4ddd17 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SettleAccountCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class SettleAccountCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SettleAccountRecipient.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SettleAccountRecipient.java new file mode 100644 index 0000000..5cf0425 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SettleAccountRecipient.java @@ -0,0 +1,162 @@ +package com.pingplusplus.model; + +import java.util.Map; + +/** + * Created by Afon on 17/03/27. + */ +public class SettleAccountRecipient extends PingppObject { + String account; + String name; + String type; + String openBankCode; + String openBank; + Boolean forceCheck; + String accountType; + Integer cardType; + String prov; + String city; + String subBank; + String subBankCode; + String mobile; + String useof; + String senderCardNumber; + String senderSubBankCode; + Map extra; + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getOpenBankCode() { + return openBankCode; + } + + public void setOpenBankCode(String openBankCode) { + this.openBankCode = openBankCode; + } + + public String getOpenBank() { + return openBank; + } + + public void setOpenBank(String openBank) { + this.openBank = openBank; + } + + public Boolean getForceCheck() { + return forceCheck; + } + + public void setForceCheck(Boolean forceCheck) { + this.forceCheck = forceCheck; + } + + public String getAccountType() { + return accountType; + } + + public void setAccountType(String accountType) { + this.accountType = accountType; + } + + public Integer getCardType() { + return cardType; + } + + public void setCardType(Integer cardType) { + this.cardType = cardType; + } + + public String getProv() { + return prov; + } + + public void setProv(String prov) { + this.prov = prov; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getSubBank() { + return subBank; + } + + public void setSubBank(String subBank) { + this.subBank = subBank; + } + + public String getSubBankCode() { + return subBankCode; + } + + public void setSubBankCode(String subBankCode) { + this.subBankCode = subBankCode; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getUseof() { + return useof; + } + + public void setUseof(String useof) { + this.useof = useof; + } + + public String getSenderCardNumber() { + return senderCardNumber; + } + + public void setSenderCardNumber(String senderCardNumber) { + this.senderCardNumber = senderCardNumber; + } + + public String getSenderSubBankCode() { + return senderSubBankCode; + } + + public void setSenderSubBankCode(String senderSubBankCode) { + this.senderSubBankCode = senderSubBankCode; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitProfit.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitProfit.java new file mode 100644 index 0000000..f128a2e --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitProfit.java @@ -0,0 +1,222 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.List; +import java.util.Map; + +/** + * 分账 + */ +public class SplitProfit extends APIResource { + String id; + String object; + Boolean livemode; + String app; + Long created; + String charge; + String channel; + String type; + String orderNo; + String transactionNo; + String failureCode; + String failureMsg; + List recipients; + Map extra; + Map metadata; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getCharge() { + return charge; + } + + public void setCharge(String charge) { + this.charge = charge; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getOrderNo() { + return orderNo; + } + + public void setOrderNo(String orderNo) { + this.orderNo = orderNo; + } + + public String getTransactionNo() { + return transactionNo; + } + + public void setTransactionNo(String transactionNo) { + this.transactionNo = transactionNo; + } + + public String getFailureCode() { + return failureCode; + } + + public void setFailureCode(String failureCode) { + this.failureCode = failureCode; + } + + public String getFailureMsg() { + return failureMsg; + } + + public void setFailureMsg(String failureMsg) { + this.failureMsg = failureMsg; + } + + public List getRecipients() { + return recipients; + } + + public void setRecipients(List recipients) { + this.recipients = recipients; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + /** + * 创建分账 + * + * @param params 参数 + * @return SplitProfit + * @throws PingppException + */ + public static SplitProfit create(Map params) + throws PingppException { + return create(params, null); + } + + /** + * 创建分账 + * + * @param params 参数 + * @param options the specific options + * @return SplitProfit + * @throws PingppException + */ + public static SplitProfit create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(SplitProfit.class), params, SplitProfit.class, options); + } + + /** + * 查询分账 + * + * @param id id + * @return SplitProfit + * @throws PingppException + */ + public static SplitProfit retrieve(String id) throws PingppException { + return retrieve(id, null); + } + + /** + * 查询分账 + * + * @param id id + * @param options the specific options + * @return SplitProfit + * @throws PingppException + */ + public static SplitProfit retrieve(String id, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(SplitProfit.class, id), null, SplitProfit.class, options); + } + + /** + * 查询分账列表 + * + * @param params 分页参数等 + * @return SplitProfitCollection + * @throws PingppException + */ + public static SplitProfitCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询分账列表 + * + * @param params 分页参数等 + * @param options the specific options + * @return SplitProfitCollection + * @throws PingppException + */ + public static SplitProfitCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(SplitProfit.class), params, SplitProfitCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitProfitCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitProfitCollection.java new file mode 100644 index 0000000..d7749aa --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitProfitCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class SplitProfitCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitProfitRecipient.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitProfitRecipient.java new file mode 100644 index 0000000..21fcffd --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitProfitRecipient.java @@ -0,0 +1,70 @@ +package com.pingplusplus.model; + +/** + * 分账的接收方数据 + */ +public class SplitProfitRecipient extends PingppObject { + String splitReceiver; + Integer amount; + String name; + String description; + String status; + String currency; + Long timeFinished; + + public String getSplitReceiver() { + return splitReceiver; + } + + public void setSplitReceiver(String splitReceiver) { + this.splitReceiver = splitReceiver; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCurrency() { + return currency; + } + + public void setCurrency(String currency) { + this.currency = currency; + } + + public Long getTimeFinished() { + return timeFinished; + } + + public void setTimeFinished(Long timeFinished) { + this.timeFinished = timeFinished; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitReceiver.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitReceiver.java new file mode 100644 index 0000000..9ca98b3 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitReceiver.java @@ -0,0 +1,209 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.HashMap; +import java.util.Map; + +/** + * 分账接收方 + */ +public class SplitReceiver extends APIResource { + String id; + String object; + Boolean livemode; + String app; + Long created; + String channel; + String type; + String account; + String name; + Map extra; + Map metadata; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + /** + * 创建分账接收方 + * + * @param params 参数 + * @return SplitReceiver + * @throws PingppException + */ + public static SplitReceiver create(Map params) + throws PingppException { + return create(params, null); + } + + /** + * 创建分账接收方 + * + * @param params 参数 + * @param options the specific options + * @return SplitReceiver + * @throws PingppException + */ + public static SplitReceiver create(Map params, RequestOptions options) + throws PingppException { + return request(RequestMethod.POST, classURL(SplitReceiver.class), params, SplitReceiver.class, options); + } + + /** + * 查询分账接收方 + * + * @param id id + * @return SplitReceiver + * @throws PingppException + */ + public static SplitReceiver retrieve(String id) throws PingppException { + return retrieve(id, null); + } + + /** + * 查询分账接收方 + * + * @param id id + * @param options the specific options + * @return SplitReceiver + * @throws PingppException + */ + public static SplitReceiver retrieve(String id, RequestOptions options) throws PingppException { + return request(RequestMethod.GET, instanceURL(SplitReceiver.class, id), null, SplitReceiver.class, options); + } + + /** + * 查询分账接收方列表 + * + * @param params 分页参数等 + * @return SplitReceiverCollection + * @throws PingppException + */ + public static SplitReceiverCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询分账接收方列表 + * + * @param params 分页参数等 + * @param options the specific options + * @return SplitReceiverCollection + * @throws PingppException + */ + public static SplitReceiverCollection list(Map params, RequestOptions options) + throws PingppException { + return request(RequestMethod.GET, classURL(SplitReceiver.class), params, SplitReceiverCollection.class, options); + } + + /** + * 删除分账接收方 + * + * @param id id + * @return DeletedSplitReceiver + * @throws PingppException + */ + public static DeletedSplitReceiver delete(String id) throws PingppException { + return delete(id, null); + } + + /** + * 删除分账接收方 + * + * @param id id + * @param options the specific options + * @return DeletedSplitReceiver + * @throws PingppException + */ + public static DeletedSplitReceiver delete(String id, RequestOptions options) throws PingppException { + return request(RequestMethod.DELETE, instanceURL(SplitReceiver.class, id), null, DeletedSplitReceiver.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitReceiverCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitReceiverCollection.java new file mode 100644 index 0000000..f07cdd8 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SplitReceiverCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class SplitReceiverCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SubApp.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SubApp.java new file mode 100644 index 0000000..6692898 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SubApp.java @@ -0,0 +1,274 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.List; +import java.util.Map; + +public class SubApp extends AppBasedResource { + String id; + String object; + Long created; + String account; + String description; + String displayName; + List availableMethods; + Object user; + Integer level; + String parentApp; + Map metadata; + Map extra; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public List getAvailableMethods() { + return availableMethods; + } + + public void setAvailableMethods(List availableMethods) { + this.availableMethods = availableMethods; + } + + public Object getUser() { + return user; + } + + public void setUser(Object user) { + this.user = user; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public Integer getLevel() { + return level; + } + + public void setLevel(Integer level) { + this.level = level; + } + + public String getParentApp() { + return parentApp; + } + + public void setParentApp(String parentApp) { + this.parentApp = parentApp; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } + + /** + * 创建 sub_app + * + * @param params + * @return SubApp + * @throws PingppException + */ + public static SubApp create(Mapparams) + throws PingppException { + return create(params, null); + } + + /** + * 创建 sub_app + * + * @param params + * @param options the specific options + * @return SubApp + * @throws PingppException + */ + public static SubApp create(Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(SubApp.class), params, SubApp.class, options); + } + + /** + * 查询 sub_app + * + * @param id + * @return SubApp + * @throws PingppException + */ + public static SubApp retrieve(String id) + throws PingppException { + return retrieve(id, null, null); + } + + /** + * 查询 sub_app + * + * @param id SubApp ID + * @param params 参数 + * @return SubApp + * @throws PingppException + */ + public static SubApp retrieve(String id, Map params) + throws PingppException { + return retrieve(id, params, null); + } + + /** + * 查询 sub_app + * + * @param id + * @param options the specific options + * @return SubApp + * @throws PingppException + */ + public static SubApp retrieve(String id, RequestOptions options) + throws PingppException { + return retrieve(id, null, options); + } + + /** + * 查询 sub_app + * + * @param id SubApp ID + * @param params 参数 + * @param options the specific options + * @return SubApp + * @throws PingppException + */ + public static SubApp retrieve(String id, Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(SubApp.class, id), params, SubApp.class, options); + } + + /** + * 查询 sub_app 列表 + * + * @param params + * @return SubApp + * @throws PingppException + */ + public static SubAppCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 sub_app 列表 + * + * @param params + * @param options the specific options + * @return SubApp + * @throws PingppException + */ + public static SubAppCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(SubApp.class), params, SubAppCollection.class, options); + } + + /** + * 更新 sub_app + * + * @param id + * @param params + * @return SubApp + * @throws PingppException + */ + public static SubApp update(String id, Mapparams) + throws PingppException { + return update(id, params, null); + } + + /** + * 更新 sub_app + * + * @param id + * @param params + * @param options the specific options + * @return SubApp + * @throws PingppException + */ + public static SubApp update(String id, Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.PUT, instanceURL(SubApp.class, id), params, SubApp.class, options); + } + + /** + * 删除 sub_app + * + * @param id + * @return DeletedSubApp + * @throws PingppException + */ + public static DeletedSubApp delete(String id) + throws PingppException { + return delete(id, null); + } + + /** + * 删除 sub_app + * + * @param id + * @param options the specific options + * @return DeletedSubApp + * @throws PingppException + */ + public static DeletedSubApp delete(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.DELETE, instanceURL(SubApp.class, id), null, DeletedSubApp.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SubAppCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SubAppCollection.java new file mode 100644 index 0000000..91d0cb0 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SubAppCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class SubAppCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SubBank.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SubBank.java new file mode 100644 index 0000000..1f93941 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SubBank.java @@ -0,0 +1,80 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class SubBank extends APIResource { + String object; + String subBank; + String subBankCode; + String prov; + String city; + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getSubBank() { + return subBank; + } + + public void setSubBank(String subBank) { + this.subBank = subBank; + } + + public String getSubBankCode() { + return subBankCode; + } + + public void setSubBankCode(String subBankCode) { + this.subBankCode = subBankCode; + } + + public String getProv() { + return prov; + } + + public void setProv(String prov) { + this.prov = prov; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + /** + * 银行支行列表查询 + * + * @param params 银行编号和省市信息 + * @return SubBankCollection + * @throws PingppException + */ + public static SubBankCollection query(Map params) + throws PingppException { + return query(params, null); + } + + /** + * 银行支行列表查询 + * + * @param params 银行编号和省市信息 + * @param options the specific options + * @return SubBankCollection + * @throws PingppException + */ + public static SubBankCollection query(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(SubBank.class), params, SubBankCollection.class, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/SubBankCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/SubBankCollection.java new file mode 100644 index 0000000..dd410ce --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/SubBankCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class SubBankCollection extends PingppCollection { +} diff --git a/src/main/java/com/pingplusplus/model/Summary.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Summary.java similarity index 100% rename from src/main/java/com/pingplusplus/model/Summary.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/Summary.java diff --git a/src/main/java/com/pingplusplus/model/Transfer.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Transfer.java similarity index 58% rename from src/main/java/com/pingplusplus/model/Transfer.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/Transfer.java index fb0b8da..79da899 100644 --- a/src/main/java/com/pingplusplus/model/Transfer.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Transfer.java @@ -4,13 +4,11 @@ * Created by sunkai on 15/5/11. */ -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; +import com.pingplusplus.exception.PingppException; import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.RequestOptions; +import java.util.HashMap; import java.util.Map; /** @@ -34,8 +32,8 @@ public class Transfer extends APIResource { String description; String failureMsg; String transaction_no; - Map extra; - Map metadata; + Map extra; + Map metadata; public String getId() { return id; @@ -173,19 +171,19 @@ public void setTransaction_no(String transaction_no) { this.transaction_no = transaction_no; } - public Map getExtra() { + public Map getExtra() { return extra; } - public void setExtra(Map extra) { + public void setExtra(Map extra) { this.extra = extra; } - public Map getMetadata() { + public Map getMetadata() { return metadata; } - public void setMetadata(Map metadata) { + public void setMetadata(Map metadata) { this.metadata = metadata; } @@ -193,66 +191,94 @@ public void setMetadata(Map metadata) { /** * 创建 Transfer * @param params - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @return Transfer + * @throws PingppException */ public static Transfer create(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return request(RequestMethod.POST, classURL(Transfer.class), params, Transfer.class); + throws PingppException { + return create(params, null); + } + + /** + * 创建 Transfer + * + * @param params + * @param options the specific options + * @return Transfer + * @throws PingppException + */ + public static Transfer create(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(Transfer.class), params, Transfer.class, options); + } + + /** + * 查询 Transfer + * @param id + * @return Transfer + * @throws PingppException + */ + public static Transfer retrieve(String id) throws PingppException { + return retrieve(id, null, null); } /** * 查询 Transfer + * * @param id - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @param options the specific options + * @return Transfer + * @throws PingppException */ - public static Transfer retrieve(String id) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - return request(RequestMethod.GET, instanceURL(Transfer.class, id), null, Transfer.class); + public static Transfer retrieve(String id, RequestOptions options) throws PingppException { + return retrieve(id, null, options); } /** * 查询 Transfer * @param id * @param params - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @return Transfer + * @throws PingppException */ - public static Transfer retrieve(String id, Map params) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - return request(RequestMethod.GET, instanceURL(Transfer.class, id), params, Transfer.class); + public static Transfer retrieve(String id, Map params) throws PingppException { + return retrieve(id, params, null); } /** * 查询 Transfer + * + * @param id * @param params - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - * @throws ChannelException + * @param options the specific options + * @return Transfer + * @throws PingppException */ - public static TransferCollection all(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return request(RequestMethod.GET, classURL(Transfer.class), params, TransferCollection.class); + public static Transfer retrieve(String id, Map params, RequestOptions options) throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(Transfer.class, id), params, Transfer.class, options); } + /** + * 查询 Transfer + * @param params 分页参数等 + * @return TransferCollection + * @throws PingppException + */ + public static TransferCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 Transfer + * + * @param params 分页参数等 + * @param options the specific options + * @return TransferCollection + * @throws PingppException + */ + public static TransferCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(Transfer.class), params, TransferCollection.class, options); + } } diff --git a/src/main/java/com/pingplusplus/model/TransferCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/TransferCollection.java similarity index 100% rename from src/main/java/com/pingplusplus/model/TransferCollection.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/TransferCollection.java diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/User.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/User.java new file mode 100644 index 0000000..8c3f1af --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/User.java @@ -0,0 +1,347 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.InvalidRequestException; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.List; +import java.util.Map; + +public class User extends AppBasedResource { + String id; + String object; + String app; + String address; + Long availableBalance; + Integer availableCoupons; + String avatar; + Long created; + Boolean disabled; + String email; + String gender; + Boolean identified; + Boolean livemode; + String mobile; + String name; + Map metadata; + String relatedApp; + List settleAccounts; + String type; + Long withdrawableBalance; + Map identityInfo; + Map extra; + Long totalBalance; + String parentUserId; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public Integer getAvailableCoupons() { + return availableCoupons; + } + + public void setAvailableCoupons(Integer availableCoupons) { + this.availableCoupons = availableCoupons; + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar; + } + + public Long getAvailableBalance() { + return availableBalance; + } + + public void setAvailableBalance(Long availableBalance) { + this.availableBalance = availableBalance; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public Boolean getDisabled() { + return disabled; + } + + public void setDisabled(Boolean disabled) { + this.disabled = disabled; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getGender() { + return gender; + } + + public void setGender(String gender) { + this.gender = gender; + } + + public Boolean getIdentified() { + return identified; + } + + public void setIdentified(Boolean identified) { + this.identified = identified; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public Long getWithdrawableBalance() { + return withdrawableBalance; + } + + public void setWithdrawableBalance(Long withdrawableBalance) { + this.withdrawableBalance = withdrawableBalance; + } + + public String getRelatedApp() { + return relatedApp; + } + + public void setRelatedApp(String relatedApp) { + this.relatedApp = relatedApp; + } + + public List getSettleAccounts() { + return settleAccounts; + } + + public void setSettleAccounts(List settleAccounts) { + this.settleAccounts = settleAccounts; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Map getIdentityInfo() { + return identityInfo; + } + + public void setIdentityInfo(Map identityInfo) { + this.identityInfo = identityInfo; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } + + public Long getTotalBalance() { + return totalBalance; + } + + public void setTotalBalance(Long totalBalance) { + this.totalBalance = totalBalance; + } + + public String getParentUserId() { + return parentUserId; + } + + public void setParentUserId(String parentUserId) { + this.parentUserId = parentUserId; + } + + /** + * 创建 user + * + * @param params + * @return User + * @throws PingppException + */ + public static User create(Mapparams) + throws PingppException { + return create(params, null); + } + + /** + * 创建 user + * + * @param params + * @param options the specific options + * @return User + * @throws PingppException + */ + public static User create(Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(User.class), params, User.class, options); + } + + /** + * 查询 user + * + * @param id + * @return User + * @throws PingppException + */ + public static User retrieve(String id) + throws PingppException { + User.checkUserId(id); + return retrieve(id, null); + } + + /** + * 查询 user + * + * @param id + * @param options the specific options + * @return User + * @throws PingppException + */ + public static User retrieve(String id, RequestOptions options) + throws PingppException { + User.checkUserId(id); + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(User.class, id), null, User.class, options); + } + + /** + * 查询 user 列表 + * + * @param params + * @return UserCollection + * @throws PingppException + */ + public static UserCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 user 列表 + * + * @param params + * @param options the specific options + * @return UserCollection + * @throws PingppException + */ + public static UserCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(User.class), params, UserCollection.class, options); + } + + /** + * 更新 user + * + * @param id + * @param params + * @return User + * @throws PingppException + */ + public static User update(String id, Mapparams) + throws PingppException { + User.checkUserId(id); + return update(id, params, null); + } + + /** + * 更新 user + * + * @param id + * @param params + * @param options the specific options + * @return User + * @throws PingppException + */ + public static User update(String id, Mapparams, RequestOptions options) + throws PingppException { + User.checkUserId(id); + return APIResource.request(APIResource.RequestMethod.PUT, instanceURL(User.class, id), params, User.class, options); + } + + public static void checkUserId(String userId) throws InvalidRequestException { + if (userId == null || userId.trim().length() == 0) { + throw new InvalidRequestException( + "ID should not be null or empty.", + "invalid_request_error", + "request_param_error", + "user_id", + 0, + null); + } + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/UserCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/UserCollection.java new file mode 100644 index 0000000..a9189f7 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/UserCollection.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class UserCollection extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/UserPic.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/UserPic.java new file mode 100644 index 0000000..b1e5ed1 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/UserPic.java @@ -0,0 +1,108 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.Map; + +public class UserPic extends AppBasedResource { + String user; + Boolean livemode; + String type; + String operateType; + String picFmt; + String picType; + String accNo; + String picExternalId; + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getOperateType() { + return operateType; + } + + public void setOperateType(String operateType) { + this.operateType = operateType; + } + + public String getPicFmt() { + return picFmt; + } + + public void setPicFmt(String picFmt) { + this.picFmt = picFmt; + } + + public String getPicType() { + return picType; + } + + public void setPicType(String picType) { + this.picType = picType; + } + + public String getAccNo() { + return accNo; + } + + public void setAccNo(String accNo) { + this.accNo = accNo; + } + + public String getPicExternalId() { + return picExternalId; + } + + public void setPicExternalId(String picExternalId) { + this.picExternalId = picExternalId; + } + + /** + * 证件上传 + * + * @param params 请求参数 + * @return UserPic + * @throws PingppException + */ + public static UserPic upload(Map params) + throws PingppException { + return upload(params, null); + } + + /** + * 证件上传 + * + * @param params 请求参数 + * @param options the specific options + * @return UserPic + * @throws PingppException + */ + public static UserPic upload(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, singleClassURL(UserPic.class), params, UserPic.class, options); + } +} diff --git a/src/main/java/com/pingplusplus/model/Webhooks.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Webhooks.java similarity index 55% rename from src/main/java/com/pingplusplus/model/Webhooks.java rename to pingpp-sdk/src/main/java/com/pingplusplus/model/Webhooks.java index 990955d..6fbeb55 100644 --- a/src/main/java/com/pingplusplus/model/Webhooks.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Webhooks.java @@ -7,25 +7,13 @@ * Created by sunkai on 15/5/11. */ public class Webhooks { - - /** - * 解析 event 中的 object - * - * @param eventStr - * @return Object - */ - @Deprecated - public static Object parseEvnet(String eventStr) { - return getObject(eventStr); - } - /** * 解析 event 中的 object * * @param eventStr - * @return Object + * @return PingppObject */ - public static Object getObject(String eventStr) { + public static PingppObject getObject(String eventStr) { return eventParse(eventStr).getData().getObject(); } @@ -36,6 +24,6 @@ public static Object getObject(String eventStr) { * @return Event */ public static Event eventParse(String eventStr) { - return APIResource.GSON.fromJson(eventStr, Event.class); + return APIResource.getGson().fromJson(eventStr, Event.class); } } diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/Withdrawal.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/Withdrawal.java new file mode 100644 index 0000000..164e0d0 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/Withdrawal.java @@ -0,0 +1,379 @@ +package com.pingplusplus.model; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.net.APIResource; +import com.pingplusplus.net.AppBasedResource; +import com.pingplusplus.net.RequestOptions; + +import java.util.HashMap; +import java.util.Map; + +public class Withdrawal extends AppBasedResource { + String id; + String object; + String app; + Integer amount; + String assetTransaction; + String balanceTransaction; + String channel; + Long created; + String description; + Map extra; + String failureMsg; + Integer fee; + Boolean livemode; + Map metadata; + String operationUrl; + String orderNo; + String source; + String status; + Long timeCanceled; + Long timeSucceeded; + String user; + Integer userFee; + String settleAccount; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public String getApp() { + return app; + } + + public void setApp(String app) { + this.app = app; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getAssetTransaction() { + return assetTransaction; + } + + public void setAssetTransaction(String assetTransaction) { + this.assetTransaction = assetTransaction; + } + + public String getBalanceTransaction() { + return balanceTransaction; + } + + public void setBalanceTransaction(String balanceTransaction) { + this.balanceTransaction = balanceTransaction; + } + + public String getChannel() { + return channel; + } + + public void setChannel(String channel) { + this.channel = channel; + } + + public Long getCreated() { + return created; + } + + public void setCreated(Long created) { + this.created = created; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Map getExtra() { + return extra; + } + + public void setExtra(Map extra) { + this.extra = extra; + } + + public Integer getFee() { + return fee; + } + + public void setFee(Integer fee) { + this.fee = fee; + } + + public Boolean getLivemode() { + return livemode; + } + + public void setLivemode(Boolean livemode) { + this.livemode = livemode; + } + + public Map getMetadata() { + return metadata; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + + public String getOrderNo() { + return orderNo; + } + + public void setOrderNo(String orderNo) { + this.orderNo = orderNo; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Long getTimeCanceled() { + return timeCanceled; + } + + public void setTimeCanceled(Long timeCanceled) { + this.timeCanceled = timeCanceled; + } + + public Long getTimeSucceeded() { + return timeSucceeded; + } + + public void setTimeSucceeded(Long timeSucceeded) { + this.timeSucceeded = timeSucceeded; + } + + public Integer getUserFee() { + return userFee; + } + + public void setUserFee(Integer userFee) { + this.userFee = userFee; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getFailureMsg() { + return failureMsg; + } + + public void setFailureMsg(String failureMsg) { + this.failureMsg = failureMsg; + } + + public String getOperationUrl() { + return operationUrl; + } + + public void setOperationUrl(String operationUrl) { + this.operationUrl = operationUrl; + } + + public String getSettleAccount() { + return settleAccount; + } + + public void setSettleAccount(String settleAccount) { + this.settleAccount = settleAccount; + } + + /** + * 创建 withdrawal + * + * @param params + * @return Withdrawal + * @throws PingppException + */ + public static Withdrawal create(Mapparams) + throws PingppException { + return create(params, null); + } + + /** + * 创建 withdrawal + * + * @param params + * @param options the specific options + * @return Withdrawal + * @throws PingppException + */ + public static Withdrawal create(Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.POST, classURL(Withdrawal.class), params, Withdrawal.class, options); + } + + /** + * 查询 withdrawal + * + * @param id + * @return Withdrawal + * @throws PingppException + */ + public static Withdrawal retrieve(String id) + throws PingppException { + return retrieve(id, null); + } + + /** + * 查询 withdrawal + * + * @param id + * @param options the specific options + * @return Withdrawal + * @throws PingppException + */ + public static Withdrawal retrieve(String id, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, instanceURL(Withdrawal.class, id), null, Withdrawal.class, options); + } + + /** + * 查询 withdrawal 列表 + * + * @param params + * @return WithdrawalCollection + * @throws PingppException + */ + public static WithdrawalCollection list(Map params) + throws PingppException { + return list(params, null); + } + + /** + * 查询 withdrawal 列表 + * + * @param params + * @param options the specific options + * @return WithdrawalCollection + * @throws PingppException + */ + public static WithdrawalCollection list(Map params, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.GET, classURL(Withdrawal.class), params, WithdrawalCollection.class, options); + } + + /** + * 更新 withdrawal + * + * @param id + * @param params + * @return Withdrawal + * @throws PingppException + */ + public static Withdrawal update(String id, Mapparams) + throws PingppException { + return update(id, params, null); + } + + /** + * 更新 withdrawal + * + * @param id + * @param params + * @param options the specific options + * @return Withdrawal + * @throws PingppException + */ + public static Withdrawal update(String id, Mapparams, RequestOptions options) + throws PingppException { + return APIResource.request(APIResource.RequestMethod.PUT, instanceURL(Withdrawal.class, id), params, Withdrawal.class, options); + } + + /** + * 取消 withdrawal + * + * @param id + * @return Withdrawal + * @throws PingppException + */ + public static Withdrawal cancel(String id) + throws PingppException { + Map params = new HashMap(); + params.put("status", "canceled"); + return update(id, params, null); + } + + /** + * 取消 withdrawal + * + * @param id + * @param options the specific options + * @return Withdrawal + * @throws PingppException + */ + public static Withdrawal cancel(String id, RequestOptions options) + throws PingppException { + Map params = new HashMap(); + params.put("status", "canceled"); + return update(id, params, options); + } + + /** + * 确认 withdrawal + * + * @param id + * @return Withdrawal + * @throws PingppException + */ + public static Withdrawal confirm(String id) + throws PingppException { + Map params = new HashMap(); + params.put("status", "pending"); + return update(id, params, null); + } + + /** + * 确认 withdrawal + * + * @param id + * @param options the specific options + * @return Withdrawal + * @throws PingppException + */ + public static Withdrawal confirm(String id, RequestOptions options) + throws PingppException { + Map params = new HashMap(); + params.put("status", "pending"); + return update(id, params, options); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/WithdrawalCollection.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/WithdrawalCollection.java new file mode 100644 index 0000000..319e48a --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/WithdrawalCollection.java @@ -0,0 +1,13 @@ +package com.pingplusplus.model; + +public class WithdrawalCollection extends WithdrawalCollectionBase { + Integer totalWithdrawalsAmount; + + public Integer getTotalWithdrawalsAmount() { + return totalWithdrawalsAmount; + } + + public void setTotalWithdrawalsAmount(Integer totalWithdrawalAmount) { + this.totalWithdrawalsAmount = totalWithdrawalAmount; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/model/WithdrawalCollectionBase.java b/pingpp-sdk/src/main/java/com/pingplusplus/model/WithdrawalCollectionBase.java new file mode 100644 index 0000000..9fd548a --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/model/WithdrawalCollectionBase.java @@ -0,0 +1,4 @@ +package com.pingplusplus.model; + +public class WithdrawalCollectionBase extends PingppCollection { +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/net/APIResource.java b/pingpp-sdk/src/main/java/com/pingplusplus/net/APIResource.java new file mode 100644 index 0000000..10bcb6c --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/net/APIResource.java @@ -0,0 +1,273 @@ +package com.pingplusplus.net; + +import com.google.gson.*; +import com.pingplusplus.Pingpp; +import com.pingplusplus.exception.*; +import com.pingplusplus.model.*; +import com.pingplusplus.serializer.*; +import com.pingplusplus.util.GsonUtils; + +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.*; + +/** + * extends the abstract class when you need requset anything from ping++ + */ +public abstract class APIResource extends PingppObject { + /** + * URLEncoder charset + */ + public static final Charset CHARSET = StandardCharsets.UTF_8; + + private static HttpClient httpClient = new HttpURLConnectionClient(); + + public static final String URIAppIdHolder = ""; + + /** + * Http requset method + */ + protected enum RequestMethod { + GET, + POST, + DELETE, + PUT + } + + /** + * Gson object use to transform json string to resource object + */ + public static final Gson GSON = GsonUtils.baseGsonBuilder() + .registerTypeAdapter(Charge.class, new ChargeDeserializer()) + .registerTypeAdapter(RedEnvelope.class, new RedEnvelopeDeserializer()) + .registerTypeAdapter(Transfer.class, new TransferDeserializer()) + .registerTypeAdapter(ChargeRefundCollection.class, new ChargeRefundCollectionDeserializer()) + .registerTypeAdapter(EventData.class, new EventDataDeserializer()) + .registerTypeAdapter(PingppRawJsonObject.class, new PingppRawJsonObjectDeserializer()) + .registerTypeAdapter(SubApp.class, new SubAppDeserializer()) + .create(); + + public static Gson getGson() { + return GSON; + } + + public static Class getSelfClass() { + return APIResource.class; + } + + /** + * @param clazz the class + * @return className + */ + protected static String className(Class clazz) { + String className = clazz.getSimpleName().toLowerCase().replace("$", " "); + + switch (className) { + case "redenvelope": + return "red_envelope"; + case "batchrefund": + return "batch_refund"; + case "batchtransfer": + return "batch_transfer"; + case "customs": + return "custom"; + case "cardinfo": + return "card_info"; + case "assettransaction": + return "asset_transaction"; + case "balancebonus": + return "balance_bonuse"; + case "balancetransfer": + return "balance_transfer"; + case "balancetransaction": + return "balance_transaction"; + case "coupontemplate": + return "coupon_template"; + case "batchwithdrawal": + return "batch_withdrawal"; + case "transactionstatistics": + return "transaction_statistics"; + case "settleaccount": + return "settle_account"; + case "subapp": + return "sub_app"; + case "royalty": + return "royaltie"; + case "royaltysettlement": + return "royalty_settlement"; + case "royaltytransaction": + return "royalty_transaction"; + case "royaltytemplate": + return "royalty_template"; + case "balancesettlement": + return "balance_settlement"; + case "subbank": + return "sub_bank"; + case "splitreceiver": + return "split_receiver"; + case "splitprofit": + return "split_profit"; + case "profittransaction": + return "profit_transaction"; + case "userpic": + return "users/upload_pic"; + case "contact": + return "sub_apps/contact"; + default: + return className; + } + } + + /** + * @param clazz the object class + * @return singleClassURL + */ + protected static String singleClassURL(Class clazz) { + String className = null; + Class klass = getSelfClass(); + if (!klass.getSimpleName().equalsIgnoreCase("APIResource")) { + try { + Method method = klass.getMethod("className", Class.class); + className = (String)method.invoke(klass, clazz); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + + if (className == null) { + className = className(clazz); + } + + return String.format("%s/v1/%s", Pingpp.getApiBase(), className); + } + + /** + * @param clazz the object class + * @return classURL + */ + protected static String classURL(Class clazz) { + return String.format("%ss", singleClassURL(clazz)); + } + + /** + * @param clazz the object class + * @param id the id of the object + * @return instanceURL + */ + protected static String instanceURL(Class clazz, String id){ + return String.format("%s/%s", classURL(clazz), urlEncode(id)); + } + + protected static String apiBasePrefixedURL(String url) { + return String.format("%s%s", Pingpp.getApiBase(), url); + } + + /** + * @param str the string to encode + * @return urlEncodedString + */ + protected static String urlEncode(String str) { + if (str == null) { + return null; + } + + try { + return URLEncoder.encode(str, CHARSET.name()); + } catch (UnsupportedEncodingException e) { + throw new AssertionError("UTF-8 is unknown"); + } + } + + /** + * @param method the method of request + * @param url the URL of request + * @param params the parameters + * @param clazz the class + * @param type + * @param options the specific options + * @return PingppObject + * @throws PingppException if some error occurs + */ + protected static T request( + APIResource.RequestMethod method, + String url, + Map params, + Class clazz, + RequestOptions options) throws PingppException { + PingppRequest request = new PingppRequest(method, url, params, options); + PingppResponse response = httpClient.requestWithRetries(request); + + int responseCode = response.getResponseCode(); + String responseBody = response.getResponseBody(); + + if (responseCode < 200 || responseCode >= 300) { + handleAPIError(response); + } + + T resource = null; + try { + resource = APIResource.getGson().fromJson(responseBody, clazz); + } catch (JsonSyntaxException e) { + raiseMalformedJsonError(responseBody, responseCode); + } + + if (resource instanceof PingppObject) { + PingppObject obj = (PingppObject) resource; + obj.setLastResponse(response); + } + + return resource; + } + + /** + * 错误处理 + * + * @param response the response + * @throws PingppException + */ + private static void handleAPIError(PingppResponse response) + throws PingppException { + PingppError error = null; + String rBody = response.getResponseBody(); + int rCode = response.getResponseCode(); + try { + JsonObject jsonObject = APIResource.GSON.fromJson(rBody, JsonObject.class).getAsJsonObject("error"); + error = APIResource.GSON.fromJson(jsonObject, PingppError.class); + } catch (JsonSyntaxException e) { + raiseMalformedJsonError(rBody, rCode); + } + + switch (rCode) { + case 400: + case 404: + throw new InvalidRequestException(error.getMessage(), error.getType(), error.getCode(), error.getParam(), rCode, null); + case 403: + case 429: + throw new RateLimitException(error.getMessage(), error.getType(), error.getCode(), rCode, null); + case 402: + throw new ChannelException(error.getMessage(), error.getType(), error.getCode(), error.getParam(), rCode, null); + case 401: + throw new AuthenticationException(error.getMessage(), error.getType(), error.getCode(), rCode, null); + case 502: + throw new APIConnectionException(error.getMessage()); + default: + throw new APIException(error.getMessage(), error.getType(), error.getCode(), rCode, null); + } + } + + private static void raiseMalformedJsonError( + String responseBody, int responseCode) throws APIException { + throw new APIException( + String.format( + "Invalid response object from API: %s. (HTTP response code was %d)", + responseBody, responseCode), + null, + null, + responseCode, + null); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/net/AppBasedResource.java b/pingpp-sdk/src/main/java/com/pingplusplus/net/AppBasedResource.java new file mode 100755 index 0000000..eb4cc02 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/net/AppBasedResource.java @@ -0,0 +1,30 @@ +package com.pingplusplus.net; + +import com.pingplusplus.Pingpp; + +public abstract class AppBasedResource extends APIResource { + /** + * @param clazz the class of object + * @return singleClassURL + */ + protected static String singleClassURL(Class clazz) { + return String.format("%s/v1/apps/%s/%s", Pingpp.getApiBase(), APIResource.URIAppIdHolder, className(clazz)); + } + + /** + * @param clazz the class of object + * @return classURL + */ + protected static String classURL(Class clazz) { + return String.format("%ss", singleClassURL(clazz)); + } + + /** + * @param clazz the class of object + * @param id the id of object + * @return instanceURL + */ + protected static String instanceURL(Class clazz, String id) { + return String.format("%s/%s", classURL(clazz), urlEncode(id)); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpClient.java b/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpClient.java new file mode 100644 index 0000000..6c007ab --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpClient.java @@ -0,0 +1,205 @@ +package com.pingplusplus.net; + +import com.pingplusplus.Pingpp; +import com.pingplusplus.exception.APIConnectionException; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.util.PingppSignature; +import com.pingplusplus.util.StreamUtils; + +import java.io.FileInputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; + +public abstract class HttpClient { + /** Maximum sleep time between tries to send HTTP requests after network failure. */ + public static final long maxNetworkRetriesDelay = 5000; + + /** Minimum sleep time between tries to send HTTP requests after network failure. */ + public static final long minNetworkRetriesDelay = 500; + + /** A value indicating whether the client should sleep between automatic request retries. */ + boolean networkRetriesSleep = true; + + /** Initializes a new instance of the {@link HttpClient} class. */ + public HttpClient() {} + + /** + * Sends the given request to Pingpp's API. + * + * @param request the request + * @return the response + * @throws PingppException If the request fails for any reason + */ + public abstract PingppResponse request(PingppRequest request) throws PingppException; + + /** + * Sends the given request to Pingpp's API, retrying the request in cases of intermittent + * problems. + * + * @param request the request + * @return the response + * @throws PingppException If the request fails for any reason + */ + public PingppResponse requestWithRetries(PingppRequest request) throws PingppException { + APIConnectionException requestException = null; + PingppResponse response = null; + int retry = 0; + + while (true) { + requestException = null; + + try { + response = this.request(request); + } catch (APIConnectionException e) { + requestException = e; + } + + if (!this.shouldRetry(retry, requestException, request, response)) { + break; + } + + retry += 1; + + try { + Thread.sleep(this.sleepTime(retry)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + + if (requestException != null) { + throw requestException; + } + + response.setNumRetries(retry); + + return response; + } + + /** + * Builds the value of the {@code User-Agent} header. + * + * @return a string containing the value of the {@code User-Agent} header + */ + protected static String buildUserAgentString() { + return String.format("Pingpp/v1 JavaBindings/%s", Pingpp.VERSION); + } + + /** + * Builds the value of the {@code X-Pingpp-Client-User-Agent} header. + * + * @return a string containing the value of the {@code X-Pingpp-Client-User-Agent} header + */ + protected static String buildXPingppClientUserAgentString() { + String[] propertyNames = { + "os.name", + "os.version", + "os.arch", + "java.version", + "java.vendor", + "java.vm.version", + "java.vm.vendor" + }; + + Map propertyMap = new HashMap<>(); + for (String propertyName : propertyNames) { + propertyMap.put(propertyName, System.getProperty(propertyName)); + } + propertyMap.put("bindings.version", Pingpp.VERSION); + propertyMap.put("lang", "Java"); + propertyMap.put("publisher", "Pingpp"); + + return APIResource.GSON.toJson(propertyMap); + } + + protected static String buildPingppSignature(PingppRequest request, String currentTime) + throws IOException { + StringBuilder sb = new StringBuilder(); + if (request.content != null) { + sb.append(request.content.stringContent()); + } + sb.append(getRequestURIFromURL(request.url)); + sb.append(currentTime); + + String stringToBeSigned = sb.toString(); + + return generateSign(stringToBeSigned, request.options); + } + + private boolean shouldRetry( + int numRetries, PingppException exception, PingppRequest request, PingppResponse response) { + // Do not retry if we are out of retries. + if (numRetries >= request.options.getMaxNetworkRetries()) { + return false; + } + + // Retry on connection error. + if ((exception != null) + && (exception.getCause() != null) + && (exception.getCause() instanceof ConnectException)) { + return true; + } + + // Retry on 500, 503, and other internal errors. + if ((response != null) && (response.getResponseCode() >= 500)) { + return true; + } + + return false; + } + + private long sleepTime(int numRetries) { + if (!networkRetriesSleep) { + return 0; + } + + long delay = (long) (minNetworkRetriesDelay * Math.pow(2, numRetries - 1)); + + if (delay > maxNetworkRetriesDelay) { + delay = maxNetworkRetriesDelay; + } + + double jitter = ThreadLocalRandom.current().nextDouble(0.75, 1.0); + delay = (long) (delay * jitter); + + if (delay < minNetworkRetriesDelay) { + delay = minNetworkRetriesDelay; + } + + return delay; + } + + protected static String currentTimeString() { + int requestTime = (int) (System.currentTimeMillis() / 1000); + return Integer.toString(requestTime); + } + + private static String getRequestURIFromURL(URL url) { + String path = url.getPath(); + String query = url.getQuery(); + if (query == null) { + return path; + } + return path + "?" + query; + } + + private static String generateSign(String data, RequestOptions options) + throws IOException { + String privatekey = options.getPrivateKey(); + if (privatekey == null) { + if (Pingpp.privateKeyPath == null) { + return null; + } + FileInputStream inputStream = new FileInputStream(Pingpp.privateKeyPath); + privatekey = StreamUtils.readToEnd(inputStream, APIResource.CHARSET); + inputStream.close(); + } + + return PingppSignature.sign(data, privatekey, APIResource.CHARSET.name()); + } + +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpContent.java b/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpContent.java new file mode 100644 index 0000000..28987d6 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpContent.java @@ -0,0 +1,44 @@ +package com.pingplusplus.net; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.util.Map; +import static java.util.Objects.requireNonNull; + +public class HttpContent { + /** The request's content, as a byte array. */ + byte[] byteArrayContent; + + /** The value of the {@code Content-Type} header. */ + String contentType; + + private HttpContent(byte[] byteArrayContent, String contentType) { + this.byteArrayContent = byteArrayContent; + this.contentType = contentType; + } + + /** + * The request's content, as a string. + * @return the string content + */ + public String stringContent() { + return new String(this.byteArrayContent, APIResource.CHARSET); + } + + public static HttpContent buildJSONContent(Map params) { + requireNonNull(params); + + return new HttpContent( + createJSONString(params).getBytes(APIResource.CHARSET), + String.format("application/json; charset=%s", APIResource.CHARSET)); + } + + /** + * @param params the parameters + * @return JSONString + */ + private static String createJSONString(Map params) { + Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create(); + return gson.toJson(params); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpHeaders.java b/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpHeaders.java new file mode 100644 index 0000000..6247b90 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpHeaders.java @@ -0,0 +1,133 @@ +package com.pingplusplus.net; + +import com.pingplusplus.util.CaseInsensitiveMap; + +import java.util.*; + +import static java.util.Objects.requireNonNull; + +public class HttpHeaders { + private CaseInsensitiveMap> headerMap; + + private HttpHeaders(CaseInsensitiveMap> headerMap) { + this.headerMap = headerMap; + } + + /** + * Returns an {@link HttpHeaders} instance initialized from the given map. + * + * @param headerMap the map containing the header names and values + * @return an {@link HttpHeaders} instance containing the given headers + * @throws NullPointerException if {@code headerMap} is {@code null} + */ + public static HttpHeaders of(Map> headerMap) { + requireNonNull(headerMap); + return new HttpHeaders(CaseInsensitiveMap.of(headerMap)); + } + + /** + * Returns a new {@link HttpHeaders} instance containing the headers of the current instance plus + * the provided header. + * + * @param name the name of the header to add + * @param value the value of the header to add + * @return the new {@link HttpHeaders} instance + * @throws NullPointerException if {@code name} or {@code value} is {@code null} + */ + public HttpHeaders withAdditionalHeader(String name, String value) { + requireNonNull(name); + requireNonNull(value); + return this.withAdditionalHeader(name, Arrays.asList(value)); + } + + /** + * Returns a new {@link HttpHeaders} instance containing the headers of the current instance plus + * the provided header. + * + * @param name the name of the header to add + * @param values the values of the header to add + * @return the new {@link HttpHeaders} instance + * @throws NullPointerException if {@code name} or {@code values} is {@code null} + */ + public HttpHeaders withAdditionalHeader(String name, List values) { + requireNonNull(name); + requireNonNull(values); + Map> headerMap = new HashMap<>(); + headerMap.put(name, values); + return this.withAdditionalHeaders(headerMap); + } + + /** + * Returns a new {@link HttpHeaders} instance containing the headers of the current instance plus + * the provided headers. + * + * @param headerMap the map containing the headers to add + * @return the new {@link HttpHeaders} instance + * @throws NullPointerException if {@code headerMap} is {@code null} + */ + public HttpHeaders withAdditionalHeaders(Map> headerMap) { + requireNonNull(headerMap); + Map> newHeaderMap = new HashMap<>(this.map()); + newHeaderMap.putAll(headerMap); + return HttpHeaders.of(newHeaderMap); + } + + /** + * Returns an unmodifiable List of all of the header string values of the given named header. + * Always returns a List, which may be empty if the header is not present. + * + * @param name the header name + * @return a List of headers string values + */ + public List allValues(String name) { + if (this.headerMap.containsKey(name)) { + List values = this.headerMap.get(name); + if ((values != null) && (values.size() > 0)) { + return Collections.unmodifiableList(values); + } + } + return Collections.emptyList(); + } + + /** + * Returns an {@link Optional} containing the first header string value of the given named (and + * possibly multi-valued) header. If the header is not present, then the returned {@code Optional} + * is empty. + * + * @param name the header name + * @return an {@code Optional} containing the first named header string value, if present + */ + public Optional firstValue(String name) { + if (this.headerMap.containsKey(name)) { + List values = this.headerMap.get(name); + if ((values != null) && (values.size() > 0)) { + return Optional.of(values.get(0)); + } + } + return Optional.empty(); + } + + /** + * Returns an unmodifiable Map view of this HttpHeaders. + * + * @return the Map + */ + public Map> map() { + return Collections.unmodifiableMap(this.headerMap); + } + + /** + * Returns this {@link HttpHeaders} as a string. + * + * @return a string describing the HTTP headers + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + sb.append(" { "); + sb.append(map()); + sb.append(" }"); + return sb.toString(); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpURLConnectionClient.java b/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpURLConnectionClient.java new file mode 100644 index 0000000..41d2bcd --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/net/HttpURLConnectionClient.java @@ -0,0 +1,108 @@ +package com.pingplusplus.net; + +import com.pingplusplus.Pingpp; +import com.pingplusplus.exception.APIConnectionException; +import com.pingplusplus.exception.AuthenticationException; +import com.pingplusplus.util.PingppSignature; +import com.pingplusplus.util.StreamUtils; +import com.pingplusplus.util.StringUtils; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.util.*; + +public class HttpURLConnectionClient extends HttpClient { + /** Initializes a new instance of the {@link HttpURLConnectionClient}. */ + public HttpURLConnectionClient() { + super(); + } + + /** + * Sends the given request to Pingpp's API. + * + * @param request the request + * @return the response + * @throws APIConnectionException if an error occurs when sending or receiving + */ + @Override + public PingppResponse request(PingppRequest request) throws APIConnectionException { + HttpURLConnection conn = null; + + try { + conn = createPingppConnection(request); + + // trigger the request + int responseCode = conn.getResponseCode(); + HttpHeaders headers = HttpHeaders.of(conn.getHeaderFields()); + String responseBody; + + if (responseCode >= 200 && responseCode < 300) { + responseBody = StreamUtils.readToEnd(conn.getInputStream(), APIResource.CHARSET); + boolean verified = PingppSignature.verify(headers, responseBody, request.options.getVerifyPublicKey(), APIResource.CHARSET.name()); + if (!verified) { + throw new AuthenticationException("响应签名验证失败,请检查验签公钥是否正确"); + } + } else { + responseBody = StreamUtils.readToEnd(conn.getErrorStream(), APIResource.CHARSET); + } + + return new PingppResponse(responseCode, responseBody, headers); + } catch (IOException e) { + throw new APIConnectionException( + String.format( + "IOException during API request to Pingpp (%s): %s " + + "Please check your internet connection and try again.", + Pingpp.getApiBase(), e.getMessage()), + e); + } catch (AuthenticationException e) { + throw new RuntimeException(e); + } finally { + if (conn != null) { + conn.disconnect(); + } + } + } + + static HttpHeaders getHeaders(PingppRequest request) { + Map> userAgentHeadersMap = new HashMap<>(); + + userAgentHeadersMap.put("User-Agent", Collections.singletonList(buildUserAgentString())); + userAgentHeadersMap.put( + "X-Pingpp-Client-User-Agent", Collections.singletonList(buildXPingppClientUserAgentString())); + + return request.getHeaders().withAdditionalHeaders(userAgentHeadersMap); + } + + private static HttpURLConnection createPingppConnection(PingppRequest request) + throws IOException { + HttpURLConnection conn = (HttpURLConnection) request.url.openConnection(); + + conn.setConnectTimeout(request.options.getConnectTimeout()); + conn.setReadTimeout(request.options.getReadTimeout()); + conn.setUseCaches(false); + for (Map.Entry> entry : getHeaders(request).map().entrySet()) { + conn.setRequestProperty(entry.getKey(), StringUtils.join(",", entry.getValue())); + } + + conn.setRequestMethod(request.method.name()); + + String requestTime = currentTimeString(); + conn.setRequestProperty("Pingplusplus-Request-Timestamp", requestTime); + String signature = buildPingppSignature(request, requestTime); + if (signature != null) { + conn.setRequestProperty("Pingplusplus-Signature", signature); + } + + if (request.content != null) { + conn.setDoOutput(true); + conn.setRequestProperty("Content-Type", request.content.contentType); + + try (OutputStream output = conn.getOutputStream()) { + output.write(request.content.byteArrayContent); + } + } + + return conn; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/net/PingppRequest.java b/pingpp-sdk/src/main/java/com/pingplusplus/net/PingppRequest.java new file mode 100644 index 0000000..91bab2a --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/net/PingppRequest.java @@ -0,0 +1,260 @@ +package com.pingplusplus.net; + +import com.pingplusplus.Pingpp; +import com.pingplusplus.exception.APIConnectionException; +import com.pingplusplus.exception.AuthenticationException; +import com.pingplusplus.exception.InvalidRequestException; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.util.StringUtils; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.*; + +public class PingppRequest { + /** + * The HTTP method for the request (GET, POST, DELETE or PUT). + * */ + APIResource.RequestMethod method; + + /** + * The URL for the request. + */ + URL url; + + /** + * The body of the request. + */ + HttpContent content; + + /** + * The HTTP headers of the request + */ + HttpHeaders headers; + + /** + * The parameters of the request. + */ + Map params; + + /** + * The options of the request. + */ + RequestOptions options; + + /** + * Initializes a new instance of the {@link PingppRequest} class. + * + * @param method the HTTP method + * @param url the URL + * @param params the parameters + * @param options the options + * @throws PingppException if the request cannot be initialized for any reason + */ + public PingppRequest( + APIResource.RequestMethod method, + String url, + Map params, + RequestOptions options) + throws PingppException { + try { + this.params = (params != null) ? Collections.unmodifiableMap(params) : null; + this.options = (options != null) ? options : RequestOptions.getDefault(); + this.method = method; + this.url = buildURL(method, url, params, this.options); + this.content = buildContent(method, params); + this.headers = buildHeaders(method, this.options); + } catch (IOException e) { + throw new APIConnectionException( + String.format( + "IOException during API request to Pingpp (%s): %s " + + "Please check your internet connection and try again.", + Pingpp.getApiBase(), e.getMessage()), + e); + } + } + + private static URL buildURL( + APIResource.RequestMethod method, String spec, Map params, RequestOptions options) + throws IOException, InvalidRequestException { + StringBuilder sb = new StringBuilder(); + + if (spec.contains(APIResource.URIAppIdHolder)) { + if (options.getAppId() == null) { + throw new InvalidRequestException( + "Please set app_id using Pingpp.appId = or ReqquestOptions", + "invalid_request_error", + "request_param_error", + "app_id", + 0, + null); + } + spec = spec.replaceFirst(APIResource.URIAppIdHolder, options.getAppId()); + } + sb.append(spec); + + if ((method != APIResource.RequestMethod.POST && method != APIResource.RequestMethod.PUT) && (params != null)) { + String queryString = createQuery(params); + if (!queryString.isEmpty()) { + sb.append("?"); + sb.append(queryString); + } + } + + return new URL(sb.toString()); + } + + private static HttpContent buildContent( + APIResource.RequestMethod method, Map params) { + if (method != APIResource.RequestMethod.POST && method != APIResource.RequestMethod.PUT) { + return null; + } + + if (params == null) { + return null; + } + + return HttpContent.buildJSONContent(params); + } + + /** + * @param params the parameters + * @return queryString + */ + private static String createQuery(Map params) { + if (params == null) { + return ""; + } + + Map flatParams = flattenParams(params); + StringBuilder queryStringBuffer = new StringBuilder(); + for (Map.Entry entry : flatParams.entrySet()) { + if (queryStringBuffer.length() > 0) { + queryStringBuffer.append("&"); + } + queryStringBuffer.append(urlEncodePair(entry.getKey(), + entry.getValue())); + } + return queryStringBuffer.toString(); + } + + /** + * @param k the key + * @param v the value + * @return urlEncodedString + */ + private static String urlEncodePair(String k, String v) { + return String.format("%s=%s", urlEncode(k), urlEncode(v)); + } + + /** + * @param str the string to encode + * @return urlEncodedString + */ + protected static String urlEncode(String str) { + if (str == null) { + return null; + } + + try { + return URLEncoder.encode(str, StandardCharsets.UTF_8.name()); + } catch (UnsupportedEncodingException e) { + throw new AssertionError("UTF-8 is unknown"); + } + } + + /** + * @param params the parameters + * @return flattenParams + */ + private static Map flattenParams(Map params) { + if (params == null) { + return new HashMap(); + } + Map flatParams = new HashMap(); + for (Map.Entry entry : params.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (value instanceof Map) { + Map flatNestedMap = new HashMap(); + Map nestedMap = (Map) value; + for (Map.Entry nestedEntry : nestedMap.entrySet()) { + flatNestedMap.put( + String.format("%s[%s]", key, nestedEntry.getKey()), + nestedEntry.getValue()); + } + flatParams.putAll(flattenParams(flatNestedMap)); + } else if (value instanceof ArrayList) { + ArrayList ar = (ArrayList) value; + Map flatNestedMap = new HashMap(); + int size = ar.size(); + for (int i = 0; i < size; i++) { + flatNestedMap.put(String.format("%s[%d]", key, i), ar.get(i)); + } + flatParams.putAll(flattenParams(flatNestedMap)); + } else if (value == null) { + flatParams.put(key, ""); + } else { + flatParams.put(key, value.toString()); + } + } + return flatParams; + } + + private static HttpHeaders buildHeaders(APIResource.RequestMethod method, RequestOptions options) + throws AuthenticationException { + Map> headerMap = new HashMap>(); + + // Accept + headerMap.put("Accept", Collections.singletonList("application/json")); + + // Accept-Charset + headerMap.put("Accept-Charset", Collections.singletonList(APIResource.CHARSET.name())); + + // Accept-Language + headerMap.put("Accept-Language", Collections.singletonList(options.getAcceptLanguage())); + + // Authorization + String apiKey = options.getApiKey(); + if (apiKey == null) { + throw new AuthenticationException( + "No API key provided. Set your API key using `Pingpp.apiKey = \"\"`."); + } else if (apiKey.isEmpty()) { + throw new AuthenticationException( + "Your API key is invalid, as it is an empty string."); + } else if (StringUtils.containsWhitespace(apiKey)) { + throw new AuthenticationException( + "Your API key is invalid, as it contains whitespace."); + } + headerMap.put("Authorization", Collections.singletonList(String.format("Bearer %s", apiKey))); + + return HttpHeaders.of(headerMap); + } + + public APIResource.RequestMethod getMethod() { + return method; + } + + public URL getUrl() { + return url; + } + + public HttpContent getContent() { + return content; + } + + public HttpHeaders getHeaders() { + return headers; + } + + public Map getParams() { + return params; + } + + public RequestOptions getOptions() { + return options; + } +} diff --git a/src/main/java/com/pingplusplus/net/PingppResponse.java b/pingpp-sdk/src/main/java/com/pingplusplus/net/PingppResponse.java similarity index 61% rename from src/main/java/com/pingplusplus/net/PingppResponse.java rename to pingpp-sdk/src/main/java/com/pingplusplus/net/PingppResponse.java index 58a5fe3..78ed7dd 100644 --- a/src/main/java/com/pingplusplus/net/PingppResponse.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/net/PingppResponse.java @@ -1,8 +1,5 @@ package com.pingplusplus.net; -import java.util.List; -import java.util.Map; - /** * Handler Pingpp response when you request charge from pingxx */ @@ -10,11 +7,13 @@ public class PingppResponse { private int responseCode; private String responseBody; - private Map> responseHeaders; + private HttpHeaders responseHeaders; + + private int numRetries; /** - * @param responseCode - * @param responseBody + * @param responseCode the HTTP Status Code + * @param responseBody the response body */ public PingppResponse(int responseCode, String responseBody) { this.responseCode = responseCode; @@ -23,11 +22,11 @@ public PingppResponse(int responseCode, String responseBody) { } /** - * @param responseCode - * @param responseBody - * @param responseHeaders + * @param responseCode the HTTP Status Code + * @param responseBody the response body + * @param responseHeaders the response headers */ - public PingppResponse(int responseCode, String responseBody, Map> responseHeaders) { + public PingppResponse(int responseCode, String responseBody, HttpHeaders responseHeaders) { this.responseCode = responseCode; this.responseBody = responseBody; this.responseHeaders = responseHeaders; @@ -35,7 +34,7 @@ public PingppResponse(int responseCode, String responseBody, Map> getResponseHeaders() { + public HttpHeaders getResponseHeaders() { return responseHeaders; } + + public int getNumRetries() { + return numRetries; + } + + public void setNumRetries(int numRetries) { + this.numRetries = numRetries; + } } diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/net/RequestOptions.java b/pingpp-sdk/src/main/java/com/pingplusplus/net/RequestOptions.java new file mode 100644 index 0000000..7a2b165 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/net/RequestOptions.java @@ -0,0 +1,271 @@ +package com.pingplusplus.net; + +import com.pingplusplus.Pingpp; + +public class RequestOptions { + private final String apiKey; + private final String appId; + private final String privateKey; + private final String verifyPublicKey; + + private final int connectTimeout; + private final int readTimeout; + + private final int maxNetworkRetries; + + private final String acceptLanguage; + + public static RequestOptions getDefault() { + return new RequestOptions( + Pingpp.apiKey, + Pingpp.appId, + Pingpp.privateKey, + Pingpp.verifyPublicKey, + Pingpp.getConnectTimeout(), + Pingpp.getReadTimeout(), + Pingpp.getMaxNetworkRetries(), + Pingpp.getAcceptLanguage()); + } + + private RequestOptions( + String apiKey, + String appId, + String privateKey, + String verifyPublicKey, + int connectTimeout, + int readTimeout, + int maxNetworkRetries, + String acceptLanguage) { + this.apiKey = apiKey; + this.appId = appId; + this.privateKey = privateKey; + this.verifyPublicKey = verifyPublicKey; + this.connectTimeout = connectTimeout; + this.readTimeout = readTimeout; + this.maxNetworkRetries = maxNetworkRetries; + this.acceptLanguage = acceptLanguage; + } + + public String getApiKey() { + return apiKey; + } + + public String getAppId() { + return appId; + } + + public String getPrivateKey() { + return privateKey; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public int getReadTimeout() { + return readTimeout; + } + + public int getMaxNetworkRetries() { + return maxNetworkRetries; + } + + public String getAcceptLanguage() { + return acceptLanguage; + } + + public String getVerifyPublicKey() {return verifyPublicKey;} + + public static RequestOptionsBuilder builder() { + return new RequestOptionsBuilder(); + } + + public static final class RequestOptionsBuilder { + private String apiKey; + private String appId; + private String privateKey; + private int connectTimeout; + private int readTimeout; + private int maxNetworkRetries; + private String acceptLanguage; + + public String getVerifyPublicKey() { + return verifyPublicKey; + } + + public RequestOptionsBuilder setVerifyPublicKey(String verifyPublicKey) { + this.verifyPublicKey = normalizePublicVerifyKey(verifyPublicKey); + return this; + } + + private String verifyPublicKey; + + public RequestOptionsBuilder() { + this.apiKey = Pingpp.apiKey; + this.appId = Pingpp.appId; + this.privateKey = Pingpp.privateKey; + this.verifyPublicKey = Pingpp.verifyPublicKey; + this.connectTimeout = Pingpp.getConnectTimeout(); + this.readTimeout = Pingpp.getReadTimeout(); + this.maxNetworkRetries = Pingpp.getMaxNetworkRetries(); + this.acceptLanguage = Pingpp.getAcceptLanguage(); + } + + public String getApiKey() { + return apiKey; + } + + public RequestOptionsBuilder setApiKey(String apiKey) { + this.apiKey = normalizeApiKey(apiKey); + return this; + } + + public RequestOptionsBuilder clearApiKey() { + this.apiKey = null; + return this; + } + + public String getAppId() { + return appId; + } + + public RequestOptionsBuilder setAppId(String appId) { + this.appId = normalizeAppId(appId); + return this; + } + + public String getPrivateKey() { + return privateKey; + } + + public RequestOptionsBuilder setPrivateKey(String privateKey) { + this.privateKey = privateKey; + return this; + } + + public RequestOptionsBuilder clearVerifyPublicKey() { + this.verifyPublicKey = null; + return this; + } + + public RequestOptionsBuilder clearAppId() { + this.appId = null; + return this; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public RequestOptionsBuilder setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + return this; + } + + public int getReadTimeout() { + return readTimeout; + } + + public RequestOptionsBuilder setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; + return this; + } + + public int getMaxNetworkRetries() { + return maxNetworkRetries; + } + + public RequestOptionsBuilder setMaxNetworkRetries(int maxNetworkRetries) { + this.maxNetworkRetries = maxNetworkRetries; + return this; + } + + public String getAcceptLanguage() { + return acceptLanguage; + } + + public RequestOptionsBuilder setAcceptLanguage(String acceptLanguage) { + this.acceptLanguage = normalizeAcceptLanguage(acceptLanguage); + return this; + } + + public RequestOptions build() { + return new RequestOptions( + normalizeApiKey(this.apiKey), + normalizeAppId(this.appId), + normalizePrivateKey(this.privateKey), + normalizePublicVerifyKey(this.verifyPublicKey), + connectTimeout, + readTimeout, + maxNetworkRetries, + acceptLanguage); + } + } + + private static String normalizeApiKey(String apiKey) { + // null apiKeys are considered "valid" + if (apiKey == null) { + return null; + } + String normalized = apiKey.trim(); + if (normalized.isEmpty()) { + throw new InvalidRequestOptionsException("Empty API key specified!"); + } + return normalized; + } + + private static String normalizeAppId(String appId) { + // null app_ids are considered "valid" + if (appId == null) { + return null; + } + String normalized = appId.trim(); + if (normalized.isEmpty()) { + throw new InvalidRequestOptionsException("Empty app_id specified!"); + } + return normalized; + } + + private static String normalizePrivateKey(String privateKey) { + // null privateKey are considered "valid" + if (privateKey == null) { + return null; + } + String normalized = privateKey.trim(); + if (normalized.isEmpty()) { + throw new InvalidRequestOptionsException("Empty privateKey specified!"); + } + return normalized; + } + + private static String normalizePublicVerifyKey(String verifyPublicKey) { + if (verifyPublicKey == null) { + return null; + } + String normalized = verifyPublicKey.trim(); + if (normalized.isEmpty()) { + throw new InvalidRequestOptionsException("Empty publicVerifyKey specified!"); + } + return normalized; + } + + private static String normalizeAcceptLanguage(String acceptLanguage) { + // null acceptLanguage are considered "valid" + if (acceptLanguage == null) { + return null; + } + String normalized = acceptLanguage.trim(); + if (normalized.isEmpty()) { + throw new InvalidRequestOptionsException("Empty Accept-Language specified!"); + } + return normalized; + } + + public static class InvalidRequestOptionsException extends RuntimeException { + private static final long serialVersionUID = 1L; + + public InvalidRequestOptionsException(String message) { + super(message); + } + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/net/SubAppBasedResource.java b/pingpp-sdk/src/main/java/com/pingplusplus/net/SubAppBasedResource.java new file mode 100644 index 0000000..c2f20ec --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/net/SubAppBasedResource.java @@ -0,0 +1,34 @@ +package com.pingplusplus.net; + +import com.pingplusplus.Pingpp; + +public abstract class SubAppBasedResource extends AppBasedResource { + + /** + * @param clazz the class of object + * @param subAppId the ID of sub_app + * @return singleClassURL + */ + protected static String singleClassURL(Class clazz, String subAppId) { + return String.format("%s/v1/apps/%s/sub_apps/%s/%s", Pingpp.getApiBase(), APIResource.URIAppIdHolder, subAppId, className(clazz)); + } + + /** + * @param clazz the class of object + * @param subAppId the ID of sub_app + * @return classURL + */ + protected static String classURL(Class clazz, String subAppId) { + return String.format("%ss", singleClassURL(clazz, subAppId)); + } + + /** + * @param clazz the class of object + * @param subAppId the ID of sub_app + * @param id the id of object + * @return instanceURL + */ + protected static String instanceURL(Class clazz, String subAppId, String id) { + return String.format("%s/%s", classURL(clazz, subAppId), urlEncode(id)); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/net/UserBasedResource.java b/pingpp-sdk/src/main/java/com/pingplusplus/net/UserBasedResource.java new file mode 100644 index 0000000..48d7ebc --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/net/UserBasedResource.java @@ -0,0 +1,34 @@ +package com.pingplusplus.net; + +import com.pingplusplus.Pingpp; + +public abstract class UserBasedResource extends AppBasedResource { + + /** + * @param clazz the class of object + * @param userId the id of user + * @return singleClassURL + */ + protected static String singleClassURL(Class clazz, String userId) { + return String.format("%s/v1/apps/%s/users/%s/%s", Pingpp.getApiBase(), APIResource.URIAppIdHolder, userId, className(clazz)); + } + + /** + * @param clazz the class of object + * @param userId the id of user + * @return classURL + */ + protected static String classURL(Class clazz, String userId) { + return String.format("%ss", singleClassURL(clazz, userId)); + } + + /** + * @param clazz the class of object + * @param userId the id of user + * @param id the id of object + * @return instanceURL + */ + protected static String instanceURL(Class clazz, String userId, String id) { + return String.format("%s/%s", classURL(clazz, userId), urlEncode(id)); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/serializer/BatchRefundChargesSerializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/BatchRefundChargesSerializer.java new file mode 100644 index 0000000..7541f45 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/BatchRefundChargesSerializer.java @@ -0,0 +1,22 @@ +package com.pingplusplus.serializer; + +import com.google.gson.*; +import com.pingplusplus.model.BatchRefundCharges; +import com.pingplusplus.model.BatchTransferRecipient; + +import java.lang.reflect.Type; + +/** + * Created by afon on 16/11/28. + */ +public class BatchRefundChargesSerializer implements JsonSerializer { + + @Override + public JsonElement serialize(BatchRefundCharges batchRefundCharges, Type type, JsonSerializationContext jsonSerializationContext) { + GsonBuilder gsonBuilder = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .disableHtmlEscaping(); + + return gsonBuilder.create().toJsonTree(batchRefundCharges, type); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/serializer/BatchTransferRecipientSerializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/BatchTransferRecipientSerializer.java new file mode 100644 index 0000000..8676b15 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/BatchTransferRecipientSerializer.java @@ -0,0 +1,21 @@ +package com.pingplusplus.serializer; + +import com.google.gson.*; +import com.pingplusplus.model.BatchTransferRecipient; + +import java.lang.reflect.Type; + +/** + * Created by afon on 16/11/28. + */ +public class BatchTransferRecipientSerializer implements JsonSerializer { + + @Override + public JsonElement serialize(BatchTransferRecipient batchTransferRecipient, Type type, JsonSerializationContext jsonSerializationContext) { + GsonBuilder gsonBuilder = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .disableHtmlEscaping(); + + return gsonBuilder.create().toJsonTree(batchTransferRecipient, type); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ChargeDeserializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ChargeDeserializer.java new file mode 100644 index 0000000..15ee2e3 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ChargeDeserializer.java @@ -0,0 +1,67 @@ +package com.pingplusplus.serializer; + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.pingplusplus.model.App; +import com.pingplusplus.model.Charge; +import com.pingplusplus.model.ChargeRefundCollection; +import com.pingplusplus.util.GsonUtils; + +import java.lang.reflect.Type; + +/** + * Created by afon on 14/11/25. + */ +public class ChargeDeserializer implements JsonDeserializer { + + @Override + public Charge deserialize(JsonElement jsonElement, + Type type, + JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + JsonObject chargeJson = jsonElement.getAsJsonObject(); + if (null != chargeJson.getAsJsonObject("credential")) { + JsonObject credentialJson = chargeJson.getAsJsonObject("credential"); + JsonObject channelCredential; + if (credentialJson.getAsJsonObject("wx") != null) { + JsonObject wx = credentialJson.getAsJsonObject("wx"); + long timeStamp = wx.get("timeStamp").getAsLong(); + wx.addProperty("timeStamp", Long.toString(timeStamp)); + } else if (credentialJson.getAsJsonObject("wx_pub") != null) { + JsonObject wxPub = credentialJson.getAsJsonObject("wx_pub"); + if (null == wxPub.get("signed_data") && wxPub.get("timeStamp") != null) { + long timeStamp = wxPub.get("timeStamp").getAsLong(); + wxPub.addProperty("timeStamp", Long.toString(timeStamp)); + } + } else if ((channelCredential = credentialJson.getAsJsonObject("bfb")) != null + || (channelCredential = credentialJson.getAsJsonObject("bfb_wap")) != null) { + if (channelCredential.has("total_amount")) { + long total_amount = channelCredential.get("total_amount").getAsLong(); + channelCredential.addProperty("total_amount", Long.toString(total_amount)); + } + } else if ((channelCredential = credentialJson.getAsJsonObject("alipay")) != null + || (channelCredential = credentialJson.getAsJsonObject("alipay_wap")) != null + || (channelCredential = credentialJson.getAsJsonObject("alipay_pc_direct")) != null) { + if (channelCredential.has("payment_type")) { + long paymentType = channelCredential.get("payment_type").getAsLong(); + channelCredential.addProperty("payment_type", Long.toString(paymentType)); + } + } + } + + Gson gson = GsonUtils.baseGsonBuilder() + .registerTypeAdapter(ChargeRefundCollection.class, new ChargeRefundCollectionDeserializer()) + .create(); + JsonElement appElement = chargeJson.get("app"); + Charge charge = gson.fromJson(jsonElement, Charge.class); + + if (null != appElement && appElement.isJsonObject()) { + App app = gson.fromJson(appElement, App.class); + charge.setApp(app); + } + return charge; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ChargeEssentialsSerializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ChargeEssentialsSerializer.java new file mode 100644 index 0000000..0ab140e --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ChargeEssentialsSerializer.java @@ -0,0 +1,26 @@ +package com.pingplusplus.serializer; + +import com.google.gson.*; +import com.pingplusplus.model.ChargeEssentials; + +import java.lang.reflect.Type; + +/** + * Created by afon on 16/11/06. + */ +public class ChargeEssentialsSerializer implements JsonSerializer { + + @Override + public JsonElement serialize(ChargeEssentials chargeEssentials, Type type, JsonSerializationContext jsonSerializationContext) { + GsonBuilder gsonBuilder = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .registerTypeAdapter(Double.class, new DoubleTypeSerializer()) + .disableHtmlEscaping(); + + if (chargeEssentials.getChannel() != null) { + gsonBuilder.serializeNulls(); + } + + return gsonBuilder.create().toJsonTree(chargeEssentials, type); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ChargeRefundCollectionDeserializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ChargeRefundCollectionDeserializer.java new file mode 100644 index 0000000..48616ac --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ChargeRefundCollectionDeserializer.java @@ -0,0 +1,21 @@ +package com.pingplusplus.serializer; + +import com.google.gson.Gson; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.pingplusplus.model.ChargeRefundCollection; +import com.pingplusplus.util.GsonUtils; + +import java.lang.reflect.Type; + +public class ChargeRefundCollectionDeserializer implements JsonDeserializer { + + public ChargeRefundCollection deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + Gson gson = GsonUtils.baseGsonBuilder().create(); + + return gson.fromJson(json, typeOfT); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/serializer/CouponTemplateExpirationSerializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/CouponTemplateExpirationSerializer.java new file mode 100644 index 0000000..00a9b35 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/CouponTemplateExpirationSerializer.java @@ -0,0 +1,21 @@ +package com.pingplusplus.serializer; + +import com.google.gson.*; +import com.pingplusplus.model.CouponTemplateExpiration; + +import java.lang.reflect.Type; + +/** + * Created by afon on 16/11/07. + */ +public class CouponTemplateExpirationSerializer implements JsonSerializer { + + @Override + public JsonElement serialize(CouponTemplateExpiration couponTemplateExpiration, Type type, JsonSerializationContext jsonSerializationContext) { + GsonBuilder gsonBuilder = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .disableHtmlEscaping(); + + return gsonBuilder.create().toJsonTree(couponTemplateExpiration, type); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/serializer/DoubleTypeSerializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/DoubleTypeSerializer.java new file mode 100644 index 0000000..510de29 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/DoubleTypeSerializer.java @@ -0,0 +1,21 @@ +package com.pingplusplus.serializer; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +import java.lang.reflect.Type; + +/** + * Created by afon on 17/03/27. + */ +public class DoubleTypeSerializer implements JsonSerializer { + + @Override + public JsonElement serialize(Double src, Type type, JsonSerializationContext jsonSerializationContext) { + if(src == src.longValue()) + return new JsonPrimitive(src.longValue()); + return new JsonPrimitive(src); + } +} diff --git a/src/main/java/com/pingplusplus/net/EventDataDeserializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/EventDataDeserializer.java similarity index 69% rename from src/main/java/com/pingplusplus/net/EventDataDeserializer.java rename to pingpp-sdk/src/main/java/com/pingplusplus/serializer/EventDataDeserializer.java index 319b723..2d24690 100644 --- a/src/main/java/com/pingplusplus/net/EventDataDeserializer.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/EventDataDeserializer.java @@ -1,7 +1,8 @@ -package com.pingplusplus.net; +package com.pingplusplus.serializer; import com.google.gson.*; import com.pingplusplus.model.*; +import com.pingplusplus.net.APIResource; import java.lang.reflect.Type; import java.util.HashMap; @@ -26,6 +27,34 @@ public class EventDataDeserializer implements JsonDeserializer { objectMap.put("app_monthly_summary", Summary.class); objectMap.put("app_daily_summary", Summary.class); objectMap.put("app_weekly_summary", Summary.class); + objectMap.put("batch_transfer", BatchTransfer.class); + objectMap.put("batch_refund", BatchRefund.class); + objectMap.put("customs", Customs.class); + objectMap.put("agreement", Agreement.class); + + objectMap.put("order", Order.class); + objectMap.put("order_refund", OrderRefund.class); + objectMap.put("user", User.class); + objectMap.put("settle_account", SettleAccount.class); + objectMap.put("withdrawal", Withdrawal.class); + objectMap.put("batch_withdrawal", BatchWithdrawal.class); + objectMap.put("balance_bonus", BalanceBonus.class); + objectMap.put("balance_transfer", BalanceTransfer.class); + objectMap.put("recharge", Recharge.class); + objectMap.put("balance_transaction", BalanceTransaction.class); + objectMap.put("balance_settlement", BalanceSettlement.class); + + objectMap.put("coupon", Coupon.class); + objectMap.put("coupon_template", CouponTemplate.class); + + objectMap.put("royalty", Royalty.class); + objectMap.put("royalty_settlement", RoyaltySettlement.class); + objectMap.put("royalty_transaction", RoyaltyTransaction.class); + objectMap.put("royalty_template", RoyaltyTemplate.class); + + objectMap.put("app", App.class); + objectMap.put("sub_app", SubApp.class); + objectMap.put("channel", Channel.class); } private Object deserializeJsonPrimitive(JsonPrimitive element) { @@ -86,7 +115,7 @@ public EventData deserialize(JsonElement json, Type typeOfT, JsonDeserialization if ("object".equals(key)) { String type = element.getAsJsonObject().get("object").getAsString(); Class cl = objectMap.get(type); - PingppObject object = APIResource.GSON.fromJson(entry.getValue(), cl != null ? cl : PingppRawJsonObject.class); + PingppObject object = APIResource.getGson().fromJson(entry.getValue(), cl != null ? cl : PingppRawJsonObject.class); eventData.setObject(object); } } diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ObjectListDeserializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ObjectListDeserializer.java new file mode 100644 index 0000000..134ba36 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/ObjectListDeserializer.java @@ -0,0 +1,49 @@ +package com.pingplusplus.serializer; + +import com.google.gson.*; +import com.pingplusplus.util.GsonUtils; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +public class ObjectListDeserializer implements JsonDeserializer> { + + @Override + public List deserialize(JsonElement elem, + Type type, + JsonDeserializationContext context) { + List list = new ArrayList<>(); + JsonArray jsonArray = elem.getAsJsonArray(); + + for (JsonElement element : jsonArray) { + if (element.isJsonNull()) { + list.add(null); + } else if (element.isJsonPrimitive()) { + JsonPrimitive primitive = element.getAsJsonPrimitive(); + if (primitive.isNumber()) { + String numStr = primitive.getAsString(); + if (numStr.contains(".")) { + list.add(primitive.getAsDouble()); + } else { + try { + list.add(primitive.getAsLong()); + } catch (NumberFormatException e) { + list.add(primitive.getAsBigDecimal()); + } + } + } else if (primitive.isString()) { + list.add(primitive.getAsString()); + } else if (primitive.isBoolean()) { + list.add(primitive.getAsBoolean()); + } + } else if (element.isJsonArray()) { + list.add(context.deserialize(element, GsonUtils.LIST_OBJ)); + } else if (element.isJsonObject()) { + list.add(context.deserialize(element, GsonUtils.MAP_STR_OBJ)); + } + } + + return list; + } +} \ No newline at end of file diff --git a/src/main/java/com/pingplusplus/net/PingppRawJsonObjectDeserializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/PingppRawJsonObjectDeserializer.java similarity index 94% rename from src/main/java/com/pingplusplus/net/PingppRawJsonObjectDeserializer.java rename to pingpp-sdk/src/main/java/com/pingplusplus/serializer/PingppRawJsonObjectDeserializer.java index 3af89a4..8d8287c 100644 --- a/src/main/java/com/pingplusplus/net/PingppRawJsonObjectDeserializer.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/PingppRawJsonObjectDeserializer.java @@ -1,4 +1,4 @@ -package com.pingplusplus.net; +package com.pingplusplus.serializer; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; diff --git a/src/main/java/com/pingplusplus/net/RedEnvelopeDeserializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/RedEnvelopeDeserializer.java similarity index 77% rename from src/main/java/com/pingplusplus/net/RedEnvelopeDeserializer.java rename to pingpp-sdk/src/main/java/com/pingplusplus/serializer/RedEnvelopeDeserializer.java index 9e20e73..251279b 100644 --- a/src/main/java/com/pingplusplus/net/RedEnvelopeDeserializer.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/RedEnvelopeDeserializer.java @@ -1,8 +1,6 @@ -package com.pingplusplus.net; +package com.pingplusplus.serializer; -import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; @@ -11,6 +9,7 @@ import com.pingplusplus.model.App; import com.pingplusplus.model.ChargeRefundCollection; import com.pingplusplus.model.RedEnvelope; +import com.pingplusplus.util.GsonUtils; import java.lang.reflect.Type; @@ -21,8 +20,8 @@ public class RedEnvelopeDeserializer implements JsonDeserializer { @Override public RedEnvelope deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject transFerJson = json.getAsJsonObject(); - Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES). - registerTypeAdapter(ChargeRefundCollection.class, new ChargeRefundCollectionDeserializer()) + Gson gson = GsonUtils.baseGsonBuilder() + .registerTypeAdapter(ChargeRefundCollection.class, new ChargeRefundCollectionDeserializer()) .create(); JsonElement appElement = transFerJson.get("app"); RedEnvelope redEnvelope = gson.fromJson(json, RedEnvelope.class); diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/serializer/SettleAccountRecipientSerializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/SettleAccountRecipientSerializer.java new file mode 100644 index 0000000..6831a02 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/SettleAccountRecipientSerializer.java @@ -0,0 +1,21 @@ +package com.pingplusplus.serializer; + +import com.google.gson.*; +import com.pingplusplus.model.SettleAccountRecipient; + +import java.lang.reflect.Type; + +/** + * Created by afon on 17/03/27. + */ +public class SettleAccountRecipientSerializer implements JsonSerializer { + + @Override + public JsonElement serialize(SettleAccountRecipient recipient, Type type, JsonSerializationContext jsonSerializationContext) { + GsonBuilder gsonBuilder = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .disableHtmlEscaping(); + + return gsonBuilder.create().toJsonTree(recipient, type); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/serializer/StringObjectMapDeserializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/StringObjectMapDeserializer.java new file mode 100644 index 0000000..42ad230 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/StringObjectMapDeserializer.java @@ -0,0 +1,52 @@ +package com.pingplusplus.serializer; + +import com.google.gson.*; +import com.pingplusplus.util.GsonUtils; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.Map; + +public class StringObjectMapDeserializer implements JsonDeserializer> { + + @Override + public Map deserialize(JsonElement elem, + Type type, + JsonDeserializationContext context) { + Map map = new HashMap<>(); + JsonObject jsonObject = elem.getAsJsonObject(); + + for (Map.Entry entry : jsonObject.entrySet()) { + String key = entry.getKey(); + JsonElement value = entry.getValue(); + + if (value.isJsonNull()) { + map.put(key, null); + } else if (value.isJsonPrimitive()) { + JsonPrimitive primitive = value.getAsJsonPrimitive(); + if (primitive.isNumber()) { + String numStr = primitive.getAsString(); + if (numStr.contains(".")) { + map.put(key, primitive.getAsDouble()); + } else { + try { + map.put(key, primitive.getAsLong()); + } catch (NumberFormatException e) { + map.put(key, primitive.getAsBigDecimal()); + } + } + } else if (primitive.isString()) { + map.put(key, primitive.getAsString()); + } else if (primitive.isBoolean()) { + map.put(key, primitive.getAsBoolean()); + } + } else if (value.isJsonArray()) { + map.put(key, context.deserialize(value, GsonUtils.LIST_OBJ)); + } else if (value.isJsonObject()) { + map.put(key, context.deserialize(value, GsonUtils.MAP_STR_OBJ)); + } + } + + return map; + } +} \ No newline at end of file diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/serializer/SubAppDeserializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/SubAppDeserializer.java new file mode 100644 index 0000000..a137464 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/SubAppDeserializer.java @@ -0,0 +1,31 @@ +package com.pingplusplus.serializer; + +import com.google.gson.*; +import com.pingplusplus.model.*; +import com.pingplusplus.util.GsonUtils; + +import java.lang.reflect.Type; + +/** + * Created by afon on 19/07/12. + */ +public class SubAppDeserializer implements JsonDeserializer { + + @Override + public SubApp deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + + JsonObject subAppJson = jsonElement.getAsJsonObject(); + + + Gson gson = GsonUtils.baseGsonBuilder().create(); + JsonElement userElement = subAppJson.get("user"); + SubApp subApp = gson.fromJson(jsonElement, SubApp.class); + + if (null != userElement && userElement.isJsonObject()) { + User user = gson.fromJson(userElement, User.class); + subApp.setUser(user); + } + + return subApp; + } +} diff --git a/src/main/java/com/pingplusplus/net/TransferDeserializer.java b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/TransferDeserializer.java similarity index 84% rename from src/main/java/com/pingplusplus/net/TransferDeserializer.java rename to pingpp-sdk/src/main/java/com/pingplusplus/serializer/TransferDeserializer.java index a78459e..c0ed8d9 100644 --- a/src/main/java/com/pingplusplus/net/TransferDeserializer.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/serializer/TransferDeserializer.java @@ -1,8 +1,6 @@ -package com.pingplusplus.net; +package com.pingplusplus.serializer; -import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; @@ -11,6 +9,7 @@ import com.pingplusplus.model.App; import com.pingplusplus.model.ChargeRefundCollection; import com.pingplusplus.model.Transfer; +import com.pingplusplus.util.GsonUtils; import java.lang.reflect.Type; @@ -22,7 +21,7 @@ public class TransferDeserializer implements JsonDeserializer { public Transfer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject transFerJson = json.getAsJsonObject(); - Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + Gson gson = GsonUtils.baseGsonBuilder() .registerTypeAdapter(ChargeRefundCollection.class, new ChargeRefundCollectionDeserializer()) .create(); JsonElement appElement = transFerJson.get("app"); diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/util/CaseInsensitiveMap.java b/pingpp-sdk/src/main/java/com/pingplusplus/util/CaseInsensitiveMap.java new file mode 100644 index 0000000..15f13cb --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/util/CaseInsensitiveMap.java @@ -0,0 +1,108 @@ +package com.pingplusplus.util; + +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; + +public class CaseInsensitiveMap extends AbstractMap + implements Map, Cloneable, Serializable { + private static final long serialVersionUID = 8157337634531724657L; + private Map> store; + + /** Instantiates a new instance of the {@link CaseInsensitiveMap} class. */ + public CaseInsensitiveMap() { + this.store = new HashMap>(); + } + + /** + * Returns an instance of {@link CaseInsensitiveMap} using the contents of another map. + * + * @param map the map to create the {@link CaseInsensitiveMap} from + * @return the {@link CaseInsensitiveMap} + */ + public static CaseInsensitiveMap of(Map map) { + if (map == null) { + return null; + } + CaseInsensitiveMap ciMap = new CaseInsensitiveMap<>(); + ciMap.putAll(map); + return ciMap; + } + + // Query Operations + + @Override + public boolean containsKey(Object key) { + String keyLower = convertKey(key); + return this.store.containsKey(keyLower); + } + + @Override + public boolean containsValue(Object value) { + return this.values().contains(value); + } + + @Override + public V get(Object key) { + String keyLower = convertKey(key); + Entry entry = this.store.get(keyLower); + if (entry == null) { + return null; + } + return entry.getValue(); + } + + // Modification Operations + + @Override + public V put(String key, V value) { + String keyLower = convertKey(key); + this.store.put(keyLower, new AbstractMap.SimpleEntry(key, value)); + return value; + } + + @Override + public V remove(Object key) { + String keyLower = convertKey(key); + Entry entry = this.store.remove(keyLower); + if (entry == null) { + return null; + } + return entry.getValue(); + } + + // Bulk Operations + + @Override + public void clear() { + this.store.clear(); + } + + // Views + + @Override + public Set keySet() { + return this.store.values().stream().map(Entry::getKey).collect(Collectors.toSet()); + } + + @Override + public Collection values() { + return this.store.values().stream().map(Entry::getValue).collect(Collectors.toList()); + } + + @Override + public Set> entrySet() { + return new HashSet<>(this.store.values()); + } + + // Utility + + private static String convertKey(Object key) { + if (key == null) { + return null; + } else if (key instanceof String) { + return ((String) key).toLowerCase(); + } + throw new IllegalArgumentException("key must be a String"); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/util/GsonUtils.java b/pingpp-sdk/src/main/java/com/pingplusplus/util/GsonUtils.java new file mode 100644 index 0000000..6187708 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/util/GsonUtils.java @@ -0,0 +1,25 @@ +package com.pingplusplus.util; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.pingplusplus.serializer.ObjectListDeserializer; +import com.pingplusplus.serializer.StringObjectMapDeserializer; + +public final class GsonUtils { + public static final Type MAP_STR_OBJ = new TypeToken>() {}.getType(); + public static final Type LIST_OBJ = new TypeToken>() {}.getType(); + + private GsonUtils() {} + + public static GsonBuilder baseGsonBuilder() { + return new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .registerTypeAdapter(GsonUtils.MAP_STR_OBJ, new StringObjectMapDeserializer()) + .registerTypeAdapter(GsonUtils.LIST_OBJ, new ObjectListDeserializer()); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/util/PingppSignature.java b/pingpp-sdk/src/main/java/com/pingplusplus/util/PingppSignature.java new file mode 100644 index 0000000..a1db312 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/util/PingppSignature.java @@ -0,0 +1,150 @@ +package com.pingplusplus.util; + +import com.pingplusplus.Pingpp; +import com.pingplusplus.exception.AuthenticationException; +import com.pingplusplus.net.HttpHeaders; +import org.apache.commons.codec.binary.Base64; + +import java.io.UnsupportedEncodingException; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +/** + * Created by Afon on 2016/12/16. + */ +public class PingppSignature { + public static String sign(String data, String PEMEncodedPrivateKey, String charset) { + PrivateKey privateKey = getPrivateKeyFromPEM(PEMEncodedPrivateKey); + if (privateKey == null) { + return null; + } + + try { + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initSign(privateKey); + signature.update(data.getBytes(charset)); + byte[] signBytes = signature.sign(); + + return Base64.encodeBase64String(signBytes).replaceAll("[\n\r]", ""); + } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException | UnsupportedEncodingException e) { + e.printStackTrace(); + } + + return null; + } + + /** + * webhook verify + * @param encodedSign + * @param data + * @param PEMEncodedPublicKey + * @param charset + * @return + * @throws AuthenticationException + */ + public static boolean verify(String encodedSign, String data, String PEMEncodedPublicKey, String charset) throws AuthenticationException { + if (StringUtils.isBlank(PEMEncodedPublicKey)) { + return true; + } + PublicKey publicKey = getPublicKeyFromPEM(PEMEncodedPublicKey); + if (publicKey == null) { + return true; + } + if (StringUtils.isBlank(encodedSign)) { + throw new AuthenticationException("响应签名 (X-Pingplusplus-Signature) 为空"); + } + try { + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initVerify(publicKey); + signature.update(data.getBytes(charset)); + return signature.verify(Base64.decodeBase64(encodedSign)); + } catch (InvalidKeyException | UnsupportedEncodingException | SignatureException | NoSuchAlgorithmException e) { + if (Pingpp.DEBUG) { + e.printStackTrace(); + } + return false; + } + } + + public static boolean verify(HttpHeaders headers, String data, String PEMEncodedPublicKey, String charset) throws AuthenticationException { + if (StringUtils.isBlank(PEMEncodedPublicKey)) { + return true; + } + PublicKey publicKey = getPublicKeyFromPEM(PEMEncodedPublicKey); + if (publicKey == null) { + return true; + } + if (!headers.firstValue("X-Pingplusplus-Signature").isPresent()) { + throw new AuthenticationException("响应签名 (X-Pingplusplus-Signature) 为空"); + } + String encodedSign = headers.firstValue("X-Pingplusplus-Signature").get(); + try { + Signature signature = Signature.getInstance("SHA256withRSA"); + signature.initVerify(publicKey); + signature.update(data.getBytes(charset)); + return signature.verify(Base64.decodeBase64(encodedSign)); + } catch (InvalidKeyException | UnsupportedEncodingException | SignatureException | NoSuchAlgorithmException e) { + if (Pingpp.DEBUG) { + e.printStackTrace(); + } + return false; + } + } + + + public static PrivateKey getPrivateKeyFromPEM(String PEMEncodedPrivateKey) { + PEMEncodedPrivateKey = PEMEncodedPrivateKey + .replaceAll("(-+BEGIN (RSA )?PRIVATE KEY-+\\r?\\n|-+END (RSA )?PRIVATE KEY-+\\r?\\n?)", ""); + byte[] privateKeyBytes = Base64.decodeBase64(PEMEncodedPrivateKey); + + try { + return generatePrivateKeyWithPKCS8(privateKeyBytes); + } catch (InvalidKeySpecException e) { + if (Pingpp.DEBUG) { + e.printStackTrace(); + } + return null; + } + } + + public static PrivateKey generatePrivateKeyWithPKCS8(byte[] privateKeyBytes) + throws InvalidKeySpecException { + try { + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); + KeyFactory kf = KeyFactory.getInstance("RSA"); + return kf.generatePrivate(keySpec); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return null; + } + + public static PublicKey getPublicKeyFromPEM(String PEMEncodedPublicKey) { + PEMEncodedPublicKey = PEMEncodedPublicKey + .replaceAll("(-+BEGIN (RSA )?PUBLIC KEY-+\\r?\\n|-+END (RSA )?PUBLIC KEY-+\\r?\\n?)", ""); + byte[] publicKeyBytes = Base64.decodeBase64(PEMEncodedPublicKey); + + try { + return generatePublicKey(publicKeyBytes); + } catch (InvalidKeySpecException e) { + if (Pingpp.DEBUG) { + e.printStackTrace(); + } + return null; + } + } + + public static PublicKey generatePublicKey(byte[] publicKeyBytes) + throws InvalidKeySpecException { + try { + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes); + KeyFactory kf = KeyFactory.getInstance("RSA"); + return kf.generatePublic(keySpec); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/util/StreamUtils.java b/pingpp-sdk/src/main/java/com/pingplusplus/util/StreamUtils.java new file mode 100644 index 0000000..84de632 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/util/StreamUtils.java @@ -0,0 +1,39 @@ +package com.pingplusplus.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +import static java.util.Objects.requireNonNull; + +public class StreamUtils { + private static final int DEFAULT_BUF_SIZE = 1024; + + /** + * Reads the provided stream until the end and returns a string encoded with the provided charset. + * + * @param stream the stream to read + * @param charset the charset to use + * @return a string with the contents of the input stream + * @throws NullPointerException if {@code stream} or {@code charset} is {@code null} + * @throws IOException if an I/O error occurs + */ + public static String readToEnd(InputStream stream, Charset charset) throws IOException { + requireNonNull(stream); + requireNonNull(charset); + + final StringBuilder sb = new StringBuilder(); + final char[] buffer = new char[DEFAULT_BUF_SIZE]; + + try (Reader in = new InputStreamReader(stream, charset)) { + int charsRead = 0; + while ((charsRead = in.read(buffer, 0, buffer.length)) > 0) { + sb.append(buffer, 0, charsRead); + } + } + + return sb.toString(); + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/util/StringUtils.java b/pingpp-sdk/src/main/java/com/pingplusplus/util/StringUtils.java new file mode 100644 index 0000000..ef6ce39 --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/util/StringUtils.java @@ -0,0 +1,59 @@ +package com.pingplusplus.util; + +import java.util.List; +import java.util.regex.Pattern; + +import static java.util.Objects.requireNonNull; + +public class StringUtils { + private static Pattern whitespacePattern = Pattern.compile("\\s"); + + /** + * Checks whether a string contains any whitespace characters or not. + * + * @param str the string to check. + * @return {@code true} if the string contains any whitespace characters; otherwise, {@code + * false}. + */ + public static boolean containsWhitespace(String str) { + requireNonNull(str); + return whitespacePattern.matcher(str).find(); + } + + public static String join(String separator, List input) { + if (input == null || input.size() <= 0) return ""; + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < input.size(); i++) { + sb.append(input.get(i)); + + // if not the last item + if (i != input.size() - 1) { + sb.append(separator); + } + } + + return sb.toString(); + } + + /** + * 是否为空 + * + * @param cs 字符串 + * @return 空 {@code true}; 非空 {@code false}. + */ + public static boolean isBlank(final CharSequence cs) { + if (cs == null) { + return true; + } + int l = cs.length(); + if (l > 0) { + for (int i = 0; i < l; i++) { + if (!Character.isWhitespace(cs.charAt(i))) { + return false; + } + } + } + return true; + } +} diff --git a/pingpp-sdk/src/main/java/com/pingplusplus/util/WxLiteOAuth.java b/pingpp-sdk/src/main/java/com/pingplusplus/util/WxLiteOAuth.java new file mode 100644 index 0000000..d7f612b --- /dev/null +++ b/pingpp-sdk/src/main/java/com/pingplusplus/util/WxLiteOAuth.java @@ -0,0 +1,95 @@ +package com.pingplusplus.util; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.GsonBuilder; +import com.pingplusplus.exception.ChannelException; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; + +/** + * 用于微信小程序用户授权后获取用户唯一标识 openid + * WxLiteOAuth 中的方法都是可选的,开发者也可根据实际情况自行开发相关功能, + * 详细内容可参考 https://developers.weixin.qq.com/miniprogram/dev/api/api-login.html + */ +public class WxLiteOAuth extends WxpubOAuth { + /** + * 获取微信小程序授权用户唯一标识 + * + * @param appId 微信小程序应用唯一标识 + * @param appSecret 微信小程序应用密钥(注意保密) + * @param code 授权 code, 登录时获取的 code + * @return openid 微信小程序授权用户唯一标识 + * @throws UnsupportedEncodingException if the encoding is not supported + */ + public static String getOpenId(String appId, String appSecret, String code) + throws UnsupportedEncodingException, ChannelException { + + AuthResult authResult = getSession(appId, appSecret, code); + if (authResult.getErrmsg() != null) { + throw new ChannelException( + authResult.getErrmsg(), + null, + null, + authResult.getErrcode().toString(), + 0, + null); + } + + return authResult.getOpenid(); + } + + /** + * 获取微信小程序授权用户唯一标识 + * + * @param appId 微信小程序应用唯一标识 + * @param appSecret 微信小程序应用密钥(注意保密) + * @param code 授权 code, 登录时获取的 code + * @return openid 微信小程序授权用户唯一标识 + * @throws UnsupportedEncodingException if the encoding is not supported + */ + public static AuthResult getSession(String appId, String appSecret, String code) + throws UnsupportedEncodingException { + Map params = new HashMap(); + params.put("appid", appId); + params.put("secret", appSecret); + params.put("js_code", code); + params.put("grant_type", "authorization_code"); + String url = "https://api.weixin.qq.com/sns/jscode2session?" + httpBuildQuery(params); + + String ret = httpGet(url); + + return new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .create().fromJson(ret, AuthResult.class); + } + + public static class AuthResult { + String sessionKey; + String openid; + String unionid; + Integer errcode; + String errmsg; + + public String getSessionKey() { + return sessionKey; + } + + public String getOpenid() { + return openid; + } + + public String getUnionid() { + return unionid; + } + + public Integer getErrcode() { + return errcode; + } + + public String getErrmsg() { + return errmsg; + } + } +} diff --git a/src/main/java/com/pingplusplus/util/WxpubOAuth.java b/pingpp-sdk/src/main/java/com/pingplusplus/util/WxpubOAuth.java similarity index 81% rename from src/main/java/com/pingplusplus/util/WxpubOAuth.java rename to pingpp-sdk/src/main/java/com/pingplusplus/util/WxpubOAuth.java index 40d0bb5..d6a7815 100644 --- a/src/main/java/com/pingplusplus/util/WxpubOAuth.java +++ b/pingpp-sdk/src/main/java/com/pingplusplus/util/WxpubOAuth.java @@ -1,9 +1,12 @@ package com.pingplusplus.util; -import com.google.gson.*; +import com.google.gson.FieldNamingPolicy; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.pingplusplus.exception.ChannelException; import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; @@ -17,8 +20,8 @@ /** * 用于微信公众号OAuth2.0鉴权,用户授权后获取授权用户唯一标识openid - * WxpubOAuth中的方法都是可选的,开发者也可根据实际情况自行开发相关功能, - * 详细内容可参考http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html + * WxpubOAuth中的方法都是可选的,开发者也可根据实际情况自行开发相关功能 + * 详细内容可参考微信官网文档 */ public class WxpubOAuth { @@ -34,9 +37,10 @@ public class WxpubOAuth { * @param appSecret 微信公众号应用密钥(注意保密) * @param code 授权code, 通过调用WxpubOAuth.createOauthUrlForCode来获取 * @return openid 微信公众号授权用户唯一标识, 可用于微信网页内支付 + * @throws UnsupportedEncodingException if the encoding is not supported */ public static String getOpenId(String appId, String appSecret, String code) - throws UnsupportedEncodingException { + throws UnsupportedEncodingException, ChannelException { String url = WxpubOAuth.createOauthUrlForOpenid(appId, appSecret, code); String ret = WxpubOAuth.httpGet(url); @@ -44,6 +48,16 @@ public static String getOpenId(String appId, String appSecret, String code) .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create().fromJson(ret, OAuthResult.class); + if (oAuthResult.getErrmsg() != null) { + throw new ChannelException( + oAuthResult.getErrmsg(), + null, + null, + oAuthResult.getErrcode().toString(), + 0, + null); + } + return oAuthResult.getOpenid(); } @@ -57,6 +71,7 @@ public static String getOpenId(String appId, String appSecret, String code) * @param moreInfo FALSE 不弹出授权页面,直接跳转,这个只能拿到用户openid * TRUE 弹出授权页面,这个可以通过 openid 拿到昵称、性别、所在地, * @return 用于获取授权code的URL地址 + * @throws UnsupportedEncodingException if the encoding is not supported */ public static String createOauthUrlForCode(String appId, String redirectUrl, boolean moreInfo) throws UnsupportedEncodingException { @@ -79,6 +94,7 @@ public static String createOauthUrlForCode(String appId, String redirectUrl, boo * @param appSecret 微信公众号应用密钥(注意保密) * @param code 授权code, 通过调用WxpubOAuth.createOauthUrlForCode来获取 * @return 获取openid的URL地址 + * @throws UnsupportedEncodingException if the encoding is not supported */ private static String createOauthUrlForOpenid(String appId, String appSecret, String code) throws UnsupportedEncodingException { @@ -92,7 +108,7 @@ private static String createOauthUrlForOpenid(String appId, String appSecret, St return "https://api.weixin.qq.com/sns/oauth2/access_token?" + queryString; } - private static String httpBuildQuery(Map queryString) throws UnsupportedEncodingException { + protected static String httpBuildQuery(Map queryString) throws UnsupportedEncodingException { StringBuilder sb = new StringBuilder(); for (Map.Entry e : queryString.entrySet()) { if (sb.length() > 0) { @@ -107,9 +123,9 @@ private static String httpBuildQuery(Map queryString) throws Uns /** * Http Get 请求 * @param urlString - * @return + * @return responseString */ - private static String httpGet(String urlString) { + protected static String httpGet(String urlString) { String result = ""; try { URL url = new URL(urlString); @@ -121,11 +137,10 @@ private static String httpGet(String urlString) { result += line; } rd.close(); - } catch (IOException e) { - e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } + return result; } @@ -133,8 +148,8 @@ private static String httpGet(String urlString) { * 获取微信公众号 jsapi_ticket * @param appId * @param appSecret - * @return - * @throws UnsupportedEncodingException + * @return JsapiTicket + * @throws UnsupportedEncodingException if the encoding is not supported */ public static String getJsapiTicket(String appId, String appSecret) throws UnsupportedEncodingException { Map data = new HashMap(); @@ -144,8 +159,7 @@ public static String getJsapiTicket(String appId, String appSecret) throws Unsup String queryString = WxpubOAuth.httpBuildQuery(data); String accessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?" + queryString; String resp = httpGet(accessTokenUrl); - JsonParser jp = new JsonParser(); - JsonObject respJson = jp.parse(resp).getAsJsonObject(); + JsonObject respJson = JsonParser.parseString(resp).getAsJsonObject(); if (respJson.has("errcode")) { return respJson.toString(); } @@ -156,22 +170,21 @@ public static String getJsapiTicket(String appId, String appSecret) throws Unsup queryString = WxpubOAuth.httpBuildQuery(data); String jsapiTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?" + queryString; resp = httpGet(jsapiTicketUrl); - JsonObject ticket = jp.parse(resp).getAsJsonObject(); + JsonObject ticket = JsonParser.parseString(resp).getAsJsonObject(); return ticket.get("ticket").getAsString(); } /** * 生成微信公众号 js sdk signature - * @param charge + * @param charge charge 对象JSON字符串 * @param jsapiTicket * @param url - * @return + * @return 签名 */ public static String getSignature(String charge, String jsapiTicket, String url) { if (null == charge || null == jsapiTicket || charge.isEmpty() || jsapiTicket.isEmpty()) return null; - JsonParser jp = new JsonParser(); - JsonObject chargeJson = jp.parse(charge).getAsJsonObject(); + JsonObject chargeJson = JsonParser.parseString(charge).getAsJsonObject(); if (!chargeJson.has("credential")) { return null; } @@ -193,9 +206,7 @@ public static String getSignature(String charge, String jsapiTicket, String url) crypt.reset(); crypt.update(string1.getBytes(CHARSET)); signature = byteToHex(crypt.digest()); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } catch (UnsupportedEncodingException e) { + } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { e.printStackTrace(); } @@ -218,6 +229,8 @@ class OAuthResult { String refreshToken; String openid; String scope; + Integer errcode; + String errmsg; public String getAccessToken() { return accessToken; @@ -238,5 +251,13 @@ public String getOpenid() { public String getScope() { return scope; } + + public Integer getErrcode() { + return errcode; + } + + public String getErrmsg() { + return errmsg; + } } } diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/CardInfoTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/CardInfoTest.java new file mode 100644 index 0000000..f2c383f --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/CardInfoTest.java @@ -0,0 +1,28 @@ +package com.pingplusplus; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.CardInfo; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class CardInfoTest extends PingppTestBase { + /** + * 通过卡号查询卡信息。 + */ + @Test public void testCardInfoQuery() throws PingppException { + Map params = new HashMap(); + params.put("app", PingppTestData.getAppID()); + params.put("bank_account", "6222280012469823"); + + CardInfo obj = CardInfo.query(params); + + assertEquals("622228", obj.getCardBin()); + assertEquals("0310", obj.getOpenBankCode()); + assertEquals("浦东发展银行", obj.getOpenBank()); + assertEquals(2, obj.getCardType().intValue()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/PingppTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/PingppTest.java new file mode 100644 index 0000000..368100a --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/PingppTest.java @@ -0,0 +1,274 @@ +package com.pingplusplus; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.*; +import com.pingplusplus.net.APIResource; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.*; + +/* + * This Java source file was auto generated by running 'gradle init --type java-library' + * by 'Afon' at '16-12-16 上午10:33' with Gradle 3.1 + * + * @author Afon, @date 16-12-16 上午10:33 + */ +public class PingppTest { + + @BeforeClass public static void initApiKey() { + Pingpp.overrideApiBase(PingppTestData.getApiBase()); + Pingpp.apiKey = PingppTestData.getApiKey(); + // 建议使用 PKCS8 编码的私钥,可以用 openssl 将 PKCS1 转成 PKCS8 + Pingpp.privateKey = PingppTestData.getPKCS8PrivateKey(); + Pingpp.DEBUG = true; + } + + @Test public void testDeserialize() { + String jsonStr = "{\n" + + " \"id\": \"ch_1234567890\",\n" + + " \"object\": \"charge\",\n" + + " \"livemode\": true,\n" + + " \"paid\": true,\n" + + " \"refunded\": true,\n" + + " \"extra\": {\n" + + " \"discount_code\": \"ABCD\",\n" + + " \"discount_amount\": 20,\n" + + " \"score\": 60.12\n" + + " },\n" + + " \"time_paid\": 1732609210,\n" + + " \"time_expire\": 1732610502,\n" + + " \"time_settle\": null,\n" + + " \"transaction_no\": \"6523236536624\",\n" + + " \"amount_refunded\": 0,\n" + + " \"failure_code\": null,\n" + + " \"failure_msg\": null,\n" + + " \"metadata\": {\n" + + " \"code\": \"10000\",\n" + + " \"type\": \"PAYMENT\",\n" + + " \"list\": [10, 100, 1000]" + + " },\n" + + " \"credential\": {},\n" + + " \"description\": \"DESC\"\n" + + "}"; + Charge ch = APIResource.getGson().fromJson(jsonStr, Charge.class); + Object discountAmount = ch.getExtra().get("discount_amount"); + assertEquals(Long.class, discountAmount.getClass()); + assertEquals(20L, discountAmount); + Object score = ch.getExtra().get("score"); + assertEquals(Double.class, score.getClass()); + System.out.println("score value: " + score); + + Object metaCode = ch.getMetadata().get("code"); + assertEquals(String.class, metaCode.getClass()); + Object metaList = ch.getMetadata().get("list"); + assertEquals(ArrayList.class, metaList.getClass()); + Object metaListEle = ((ArrayList) metaList).get(0); + assertEquals(Long.class, metaListEle.getClass()); + } + + @Test public void testSetApiKey() { + assertEquals("apiKey should be set", "sk_test_ibbTe5jLGCi5rzfH4OqPW9KC", Pingpp.apiKey); + } + + @Test public void testVerifyVersions() { + assertEquals("Pingpp.VERSION should match", "2.5.6", Pingpp.VERSION); + } + + @Test public void testCreateCharge() { + String appId = PingppTestData.getAppID(); + + Charge charge = null; + Map chargeMap = new HashMap(); + chargeMap.put("amount", 100);//订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100) + chargeMap.put("currency", "cny"); + chargeMap.put("subject", "Your Subject"); + chargeMap.put("body", "Your Body"); + String orderNo = "orderno" + new Date().getTime(); + chargeMap.put("order_no", orderNo);// 推荐使用 8-20 位,要求数字或字母,不允许其他字符 + chargeMap.put("channel", "alipay");// 支付使用的第三方支付渠道取值,请参考:https://www.pingxx.com/api#api-c-new + chargeMap.put("client_ip", "192.168.1.132"); // 发起支付请求客户端的 IP 地址,格式为 IPV4,如: 127.0.0.1 + Map app = new HashMap(); + app.put("id", appId); + chargeMap.put("app", app); + + Map extra = new HashMap(); +// extra.put("success_url", "http://127.0.0.1/succeeded"); + chargeMap.put("extra", extra); + try { + // 发起 charge 创建请求 + charge = Charge.create(chargeMap); + // 传到客户端请先转成字符串 .toString(), 调该方法,会自动转成正确的 JSON 字符串 + String chargeString = charge.toString(); + System.out.println(chargeString); + } catch (PingppException e) { + e.printStackTrace(); + } + + assertNotNull(charge); + assertEquals("charge object should be charge", "charge", charge.getObject()); + assertEquals("charge order_no", orderNo, charge.getOrderNo()); + } + + @Test public void testWebhooksParseCharge() { + String webhookData = PingppTestData.getChargeWebhooksData(); + + PingppObject obj = Webhooks.getObject(webhookData); + + assertTrue("object should be an instance of Charge", obj instanceof Charge); + assertEquals("object should be charge", "charge", ((Charge)obj).getObject()); + } + + @Test public void testWebhooksParseBatchTransfer() { + String webhookData = PingppTestData.getBatchTransferWebhooksData(); + + PingppObject obj = Webhooks.getObject(webhookData); + + assertTrue("object should be an instance of BatchTransfer", obj instanceof BatchTransfer); + assertEquals("object should be batch_transfer", "batch_transfer", ((BatchTransfer)obj).getObject()); + } + + @Test public void testGetChargeList() { + try { + Integer limit = 3; + Map params = new HashMap(); + params.put("app[id]", PingppTestData.getAppID()); + params.put("limit", limit); + ChargeCollection chs = Charge.list(params); + + System.out.println(chs); + assertEquals("object should be list", "list", chs.getObject()); + assertEquals("data count should be same with limit", limit.intValue(), chs.getData().size()); + } catch (PingppException e) { + e.printStackTrace(); + } + } + + @Test public void testGetBatchRefundList() { + try { + Integer limit = 3; + Map params = new HashMap(); + params.put("per_page", limit); + BatchRefundCollection objs = BatchRefund.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + assertEquals("data count should be same with per_page", limit.intValue(), objs.getData().size()); + } catch (PingppException e) { + e.printStackTrace(); + } + } + + @Test public void testCreateTransfer() { + try { + String orderNo = "2017" + new Date().getTime(); + Map params = new HashMap(); + params.put("amount", 1010); + params.put("currency", "cny"); + params.put("type", "b2c"); + params.put("order_no", orderNo); + params.put("channel", "wx_pub"); + params.put("recipient", "openid-kaoshrbgafsnrxxcsds"); + +// params.put("channel", "unionpay"); +// Map extra = new HashMap(); +// extra.put("open_bank_code", "0105"); +// extra.put("card_number", "6222001022020034"); +// extra.put("user_name", "USER NAME"); +// params.put("extra", extra); + + params.put("description", "Your description."); + Map app = new HashMap(); + app.put("id", PingppTestData.getAppID()); + params.put("app", app); + Transfer obj = Transfer.create(params); + + assertEquals("object should be transfer", "transfer", obj.getObject()); + assertEquals("amount should be same", params.get("amount"), obj.getAmount()); + assertEquals("order_no should be same", params.get("order_no"), obj.getOrderNo()); + assertEquals("description should be same", params.get("description"), obj.getDescription()); + assertEquals("channel should be same", params.get("channel"), obj.getChannel()); + } catch (PingppException e) { + e.printStackTrace(); + } + } + + @Test public void testCreateBatchTransfer() throws PingppException { + + String batchNo = "2017" + new Date().getTime(); + Map params = new HashMap(); + params.put("app", PingppTestData.getAppID()); + params.put("amount", 1000); + params.put("currency", "cny"); + params.put("type", "b2c"); + params.put("batch_no", batchNo); + params.put("channel", "alipay"); + params.put("description", "Batch transfer description."); + + List> recipients = new ArrayList<>(); + params.put("recipients", recipients); + + Map recipient1 = new HashMap(); + recipient1.put("account", "user001@gmail.com"); + recipient1.put("name", "user001"); + recipient1.put("amount", 600); + recipient1.put("description", "Recipient 1 description."); + recipients.add(recipient1); + + Map recipient2 = new HashMap(); + recipient2.put("account", "user002@gmail.com"); + recipient2.put("name", "user002"); + recipient2.put("amount", 400); + recipient2.put("description", "Recipient 2 description."); + recipients.add(recipient2); + + BatchTransfer obj = BatchTransfer.create(params); + + assertEquals("object should be batch_transfer", "batch_transfer", obj.getObject()); + assertEquals("amount should be same", params.get("amount"), obj.getAmount()); + assertEquals("batch_no should be same", params.get("batch_no"), obj.getBatchNo()); + assertEquals("description should be same", params.get("description"), obj.getDescription()); + assertEquals("channel should be same", params.get("channel"), obj.getChannel()); + for (int i = 0; i < obj.getRecipients().size(); i++) { + assertNotNull("order_no should not be null", obj.getRecipients().get(i).getOrderNo()); + assertNull("failure_msg should be null", obj.getRecipients().get(i).getFailureMsg()); + assertNull("transaction_no should be null", obj.getRecipients().get(i).getTransactionNo()); + assertTrue("fee should be greater than or equal to 0", obj.getRecipients().get(i).getFee() >= 0); + } + } + + @Test public void testReverseCharge() { + String appId = PingppTestData.getAppID(); + + String chargeId = "ch_Py5SC89OyT00W5K4uHPmLCSC"; + + Charge charge = null; + try { + // 发起 charge 撤销请求 + charge = Charge.reverse(chargeId); + System.out.println(charge); + + assertEquals("charge object should be charge", "charge", charge.getObject()); + assertNotNull("charge reversed not null", charge.getReversed()); + } catch (PingppException e) { + e.printStackTrace(); + } + } + + @Test public void testRetrieveRefund() { + String chargeId = "ch_Ti1eD0WP08eDPSSqnTOmLWHK"; + String refundId = "re_8avPmLWrPaH8TKmXDK5KubrL"; + + Refund refund = null; + try { + refund = Refund.retrieve(chargeId, refundId); + System.out.println(refund); + } catch (PingppException e) { + e.printStackTrace(); + } + + assertEquals("refund object should be charge", "refund", refund.getObject()); + assertNotNull("refund extra not null", refund.getExtra()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/PingppTestBase.java b/pingpp-sdk/src/test/java/com/pingplusplus/PingppTestBase.java new file mode 100644 index 0000000..aa2b831 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/PingppTestBase.java @@ -0,0 +1,21 @@ +package com.pingplusplus; + +import org.junit.BeforeClass; + +/* + * This Java source file was auto generated by running 'gradle init --type java-library' + * by 'Afon' at '16-12-16 上午10:33' with Gradle 3.1 + * + * @author Afon, @date 16-12-16 上午10:33 + */ +public class PingppTestBase { + + @BeforeClass public static void initApiKey() { + Pingpp.overrideApiBase(PingppTestData.getApiBase()); + Pingpp.apiKey = PingppTestData.getApiKey(); + Pingpp.appId = PingppTestData.getAppID(); + Pingpp.privateKey = PingppTestData.getPKCS8PrivateKey(); + + Pingpp.DEBUG = true; + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/PingppTestData.java b/pingpp-sdk/src/test/java/com/pingplusplus/PingppTestData.java new file mode 100644 index 0000000..815aa81 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/PingppTestData.java @@ -0,0 +1,47 @@ +package com.pingplusplus; + +/** + * Created by Afon on 2016/12/20. + */ +public class PingppTestData { + + public static String getApiBase() { + return "https://api.pingxx.com"; + } + + public static String getApiKey() { + return "sk_test_ibbTe5jLGCi5rzfH4OqPW9KC"; + } + + public static String getAppID() { + return "app_1Gqj58ynP0mHeX1q"; + } + + public static String getPKCS8PrivateKey() { + return "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDHYyS3FwoESp1hGLYiBhy6k9Ag3lzGCIEvm50IIEkE0Ftc9qq44TWqyl+EHUpTMdcBOcI42JLO5stwFOfCLa3PQStEJ4llIRFEKlsrHh67pvWd5RNaSBrvGlnFY40S+SZmjk2WF/h9dE9Ric79t0YI0alD8dIl9Yu3OaEKo7VonBWFwOYMxjPhtORlq+EUF1XJd//yftQrKWTTd7KaUonWzBCl4VzFop/OyTWYlTuZz3eYJaNpH5VaQ1vDgBAcPIeBvMf7NgBHMKW6LLmFd2LEYQ/6I7hkGTjysSzWEpO8bPWT6OEsJ2R2kFGOrSkr+G2MDcJ7ykXYAmz5+A3plS6ZAgMBAAECggEAVrgwR9GlcahiOtDcpn+yDxQq+aC9CQS561LrQZWJLKbSleRS7IZHKTlLwdJbeUO8F7RfXQoVEBghc2YkRrhHWFUn1ES95VY0hElHzcET7Nn5CeuQNzwVOtljIg7iVNY4dXJ/HEDguu/Tb8tYU9FajItj60FJ/WiGk/JksJPzWsOCVPVniy9fTbTLy1e+dCpCI6OXirtm7hvbodRNDjree0wSEzm7vL0wVzEZFo6kX+ABGUwaoO7pPyH+hgyI5Iuhc65NHsHzTJpf8yNFl9QGhkxvm2Ff2oEtDt1idOTBrHB6tg+ti9Ctb2+2yzBnk14hsSYJnKitR7wM6ZCFPX4eYQKBgQD+JAREeFkodec/SC+GX+4Q4Y68uMPkfUPrMKXM4cyY5wgXk64RBvRVxIxX7x6Y3tIKn9v8tWAprbsyVr15eb4RcAFEVwjuoZixhd9sIPsRhfdNolKn/fSPIsHL4ywcJMSIt7KVKHuQeqBNHy0o0PxQjNej1ozsmrAWqV55cbKHswKBgQDI2JQRTPIEC/2y6LdmBVhGJW9OKWTYdVNjq7rX+Yw4uxOtfd5hBqpvgZEklKEk72aazFdEcERlAm9SqoX09qk6zK/wcq4Xn5Q/qy8ecmjuyf2AK9X+HUdMerMVxhK9RpeevKYP/RO2F/wIN64anlQVYygVkXXgdOvWhBE4YABKgwKBgDRtmbPGYB5ItHwJmERQZfx1i8zDESaB8RED6DBsJJkmkDTM8ovws1c+RPWfDuDalto6QFfR0xTGEmhAHLaCtwNB6AEBM4aHL8jvpTfZVfI3gN0zL3oYmestcG1vYBouO504yE6dG2Ci6479b4OMGYFEjPfvuwLUpp8GMcc7/WihAoGANCp8mtm/ammq5VMof2kX+nAyrrx1ovsmQ5cRGpOIZhvBCqjMn6rZjci7aCLqj+tWXRKCABagzROK0o/T50JBxjHv6KYArcYW/Up7HI9ezdbM7wNzu2LjZ+veo+MkbuDs9J/PCgwTmJI2NfQwVl2VPVDZ0nBLi5cSwk7fIiNdL/0CgYEAtECmC1QDs53Di2MIsa/Fe4sWfJGSDqEWqhcA/aPwf1skM6VJJXBBMV1qFtwgO1AlLnu9dQYra6ylsUoubVYIXM9XK7EMhbqi57+Q75jHFTc0DnzOTyho5Gp4Ddi8dztmZGNWdWTGdeMqh+svqMXkD6VdJeddyGu/Zlgj7Wk6whU="; + } + + public static String getChargeWebhooksData() { + return "{\"id\":\"evt_c4qfbcefvIhsxKuES4CpqdUN\",\"created\":1482204769,\"livemode\":false,\"type\":\"charge.succeeded\",\"data\":{\"object\":{\"amount\":100,\"amount_refunded\":0,\"amount_settle\":100,\"app\":\"app_1Gqj58ynP0mHeX1q\",\"body\":\"Your body\",\"channel\":\"alipay\",\"client_ip\":\"210.28.41.51\",\"created\":1482204769,\"credential\":{},\"currency\":\"cny\",\"description\":\"Description.\",\"extra\":{},\"failure_code\":null,\"failure_msg\":null,\"id\":\"ch_1SiPqPDCuvj5S4OaTSX54KC0\",\"livemode\":false,\"metadata\":{},\"object\":\"charge\",\"order_no\":\"orderno1482210036043\",\"paid\":true,\"refunded\":false,\"refunds\":{\"data\":[],\"has_more\":false,\"object\":\"list\",\"url\":\"/v1/charges/ch_1SiPqPDCuvj5S4OaTSX54KC0/refunds\"},\"subject\":\"Your Subject\",\"time_expire\":1482207768,\"time_paid\":1482204769,\"time_settle\":null,\"transaction_no\":\"2016122028818332\"}},\"object\":\"event\",\"request\":\"iar_cfgO0GxCSs9CH0K4r1t5Whjk\",\"pending_webhooks\":0}"; + } + + public static String getBatchTransferWebhooksData() { + return "{\"id\":\"evt_cx1zsoQsiPfjagJKt5gydjsx\",\"created\":1475924802,\"livemode\":true,\"type\":\"batch_transfer.succeeded\",\"data\":{\"object\":{\"id\":\"181610081644346142\",\"amount\":2200,\"app\":\"app_1Gqj58ynP0mHeX1q\",\"batch_no\":\"battr1475916275\",\"channel\":\"alipay\",\"created\":1475916274,\"currency\":\"cny\",\"description\":\"Batch transfer description.\",\"extra\":{},\"failure_msg\":null,\"fee\":100,\"livemode\":true,\"metadata\":{},\"object\":\"batch_transfer\",\"recipients\":[{\"account\":\"test@gmail.com\",\"amount\":1100,\"description\":\"批量付款说明。\",\"name\":\"test\",\"status\":\"paid\",\"transfer\":\"tr_uj9GSfTK8G8mLeHu9KafK5WT\"},{\"account\":\"test@gmail.com\",\"amount\":1100,\"description\":\"批量付款说明。\",\"name\":\"test002\",\"status\":\"paid\",\"transfer\":\"tr_PiXiffX4mbevX5HDfT44DmjL\"}],\"status\":\"succeeded\",\"time_succeeded\":null,\"transaction_no\":null,\"type\":\"b2c\"}},\"object\":\"event\",\"request\":\"iar_23eD0xHi58zLfD5HKdnC2nDc\",\"pending_webhooks\":0}"; + } + + public static String getWithdrawalWebhooksData() { + return "{\"id\":\"evt_gJKt5gzsoQsiPfcx1Pfjajaw\",\"created\":1475924802,\"livemode\":true,\"type\":\"balance.withdrawal.succeeded\",\"data\":{\"object\":{\"id\":\"1701611150302360654\",\"object\":\"withdrawal\",\"app\":\"app_1Gqj58ynP0mHeX1q\",\"amount\":20000,\"asset_transaction\":\"\",\"balance_transaction\":\"\",\"channel\":\"unionpay\",\"created\":1472648887,\"description\":\"test232description\",\"extra\":{\"card_number\":\"6225210207073918\",\"user_name\":\"姓名\",\"open_bank_code\":\"0102\",\"prov\":\"上海\",\"city\":\"上海\"},\"fee\":200,\"livemode\":true,\"metadata\":{},\"order_no\":\"20160829133002\",\"source\":null,\"status\":\"pending\",\"time_canceled\":null,\"time_succeeded\":null,\"user\":\"user_001\",\"user_fee\":50}},\"object\":\"event\",\"request\":\"iar_23eD0xHi58zLfD5HKdnC2nDc\",\"pending_webhooks\":0}"; + } + + public static String getAgreementEventData() { + return "{\"created\":1526557545,\"livemode\":false,\"type\":\"agreement.succeeded\",\"data\":{\"object\":{\"id\":\"agr_19EEE7QdgGMCoY\",\"object\":\"agreement\",\"livemode\":false,\"app\":\"app_1Gqj58ynP0mHeX1q\",\"created\":1526557489,\"channel\":\"qpay\",\"contract_no\":\"2018051700001\",\"contract_id\":\"1413528914776620328305865065617065\",\"credential\":{},\"status\":\"succeeded\",\"time_succeeded\":1526557545,\"time_canceled\":null,\"failure_code\":null,\"failure_msg\":null,\"extra\":{\"display_account\":\"签约测试\"},\"metadata\":{}}},\"object\":\"event\",\"request\":\"iar_L08SS8iLCubTLi10yDrbP4a5\",\"scope\":\"app_1Gqj58ynP0mHeX1q\",\"acct_id\":\"acct_zjb1KS1i9C0CvzrL\"}"; + } + + public static String getRechargeSucceededEventData() { + return "{\"id\":\"evt_400180517202605018219403\",\"created\":1526559964,\"livemode\":false,\"type\":\"recharge.succeeded\",\"data\":{\"object\":{\"id\":\"220180517753149716480010\",\"object\":\"recharge\",\"app\":\"app_1Gqj58ynP0mHeX1q\",\"created\":1526559949,\"livemode\":false,\"amount\":90,\"succeeded\":true,\"time_succeeded\":1526559964,\"refunded\":false,\"user\":\"user_test_02\",\"from_user\":\"user_test_02\",\"user_fee\":10,\"charge\":{\"id\":\"ch_0u9erLv9WPeD48WX14i9SebP\",\"object\":\"charge\",\"created\":1526559949,\"livemode\":false,\"paid\":true,\"refunded\":false,\"reversed\":false,\"app\":\"app_1Gqj58ynP0mHeX1q\",\"channel\":\"alipay_wap\",\"order_no\":\"20171526559948047\",\"client_ip\":\"127.0.0.1\",\"amount\":100,\"amount_settle\":100,\"currency\":\"cny\",\"subject\":\"Recharge subject\",\"body\":\"Recharge body\",\"extra\":{\"success_url\":\"http://www.pingxx.com\",\"buyer_account\":\"alipay_account\"},\"time_paid\":1526559964,\"time_expire\":1526646349,\"time_settle\":null,\"transaction_no\":\"2018051714482272\",\"refunds\":{\"object\":\"list\",\"url\":\"/v1/charges/ch_0u9erLv9WPeD48WX14i9SebP/refunds\",\"has_more\":false,\"data\":[]},\"amount_refunded\":0,\"failure_code\":null,\"failure_msg\":null,\"metadata\":{},\"credential\":{},\"description\":\"Recharge description.\"},\"balance_bonus\":null,\"balance_transaction\":\"600180517753305323520001\",\"description\":\"Recharge description.\",\"metadata\":{}}},\"object\":\"event\",\"request\":\"iar_nbrfrD4en14GrbTirLnfHOC8\",\"pending_webhooks\":0}"; + } + + public static String getOrderSucceededEventData() { + return "{\"id\":\"evt_400180517202836018305903\",\"created\":1526560116,\"livemode\":false,\"type\":\"order.succeeded\",\"data\":{\"object\":{\"id\":\"2001805170000308581\",\"object\":\"order\",\"created\":1526560047,\"livemode\":false,\"paid\":true,\"refunded\":false,\"status\":\"paid\",\"app\":\"app_1Gqj58ynP0mHeX1q\",\"uid\":\"test_user_001\",\"available_balance\":4,\"merchant_order_no\":\"20171526560045673\",\"amount\":100,\"actual_amount\":100,\"amount_refunded\":0,\"amount_paid\":100,\"coupon_amount\":0,\"currency\":\"cny\",\"subject\":\"ORDER_SUBJECT\",\"body\":\"ORDER_BODY\",\"client_ip\":\"192.168.1.125\",\"time_paid\":1526560116,\"time_expire\":1526646447,\"charge\":\"ch_5iTOm1P8inv1L48iL4bTOyLS\",\"coupon\":null,\"description\":null,\"metadata\":{},\"charge_essentials\":{\"channel\":\"alipay_wap\",\"transaction_no\":\"2018051773981055\",\"failure_code\":null,\"failure_msg\":null,\"extra\":{\"success_url\":\"http://www.pingxx.com\",\"buyer_account\":\"alipay_account\"},\"credential\":{}},\"receipt_app\":\"app_1Gqj58ynP0mHeX1q\",\"service_app\":\"app_1Gqj58ynP0mHeX1q\",\"available_methods\":[],\"charges\":{\"object\":\"list\",\"url\":\"/v1/charges\",\"has_more\":false,\"data\":[{\"id\":\"ch_5iTOm1P8inv1L48iL4bTOyLS\",\"object\":\"charge\",\"created\":1526560093,\"livemode\":false,\"paid\":true,\"refunded\":false,\"reversed\":false,\"app\":\"app_1Gqj58ynP0mHeX1q\",\"channel\":\"alipay_wap\",\"order_no\":\"20171526560045673\",\"client_ip\":\"192.168.1.125\",\"amount\":100,\"amount_settle\":0,\"currency\":\"cny\",\"subject\":\"ORDER_SUBJECT\",\"body\":\"ORDER_BODY\",\"extra\":{\"success_url\":\"http://www.pingxx.com\",\"buyer_account\":\"alipay_account\"},\"time_paid\":1526560116,\"time_expire\":1526646447,\"time_settle\":null,\"transaction_no\":\"2018051773981055\",\"refunds\":null,\"amount_refunded\":0,\"failure_code\":null,\"failure_msg\":null,\"metadata\":{},\"credential\":{},\"description\":null}]}}},\"object\":\"event\",\"request\":\"iar_bXrXH0ib9yT4vLuDmLrDmb5K\",\"pending_webhooks\":0}"; + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/RequestOptionsTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/RequestOptionsTest.java new file mode 100644 index 0000000..8f9a135 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/RequestOptionsTest.java @@ -0,0 +1,87 @@ +package com.pingplusplus; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.User; +import com.pingplusplus.net.RequestOptions; +import com.pingplusplus.net.RequestOptions.RequestOptionsBuilder; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class RequestOptionsTest { + + @Before + public void clearConfigs() { + Pingpp.apiKey = null; + Pingpp.appId = null; + Pingpp.privateKey = null; + } + + @Test + public void testRequestOptionsBuild() { + String apiKey = "sk_test_ibbTe5jLGCi5rzfH4OqnzhGs"; + String appId = "app_1Gqj58ynP0mNgKsc"; + String privateKey = "-----BEGIN......END-----".trim(); + RequestOptions options = new RequestOptionsBuilder() + .setApiKey(apiKey) + .setAppId(appId) + .setPrivateKey(privateKey) + .setConnectTimeout(5000) + .setReadTimeout(20000) + .setAcceptLanguage("zh-CN") + .setMaxNetworkRetries(2) + .build(); + + assertEquals("API Key should be", apiKey, options.getApiKey()); + assertEquals("App ID should be", appId, options.getAppId()); + assertEquals("Private key should be", privateKey, options.getPrivateKey()); + assertEquals("Connect timeout should be", 5000, options.getConnectTimeout()); + assertEquals("Read timeout should be", 20000, options.getReadTimeout()); + } + + @Test + public void testDefaultRequestOptionsBuilder() { + Pingpp.apiKey = PingppTestData.getApiKey(); + Pingpp.appId = PingppTestData.getAppID(); + Pingpp.privateKey = PingppTestData.getPKCS8PrivateKey(); + + RequestOptions options = new RequestOptionsBuilder().build(); + + assertEquals("API Key should be", PingppTestData.getApiKey(), options.getApiKey()); + assertEquals("App ID should be", PingppTestData.getAppID(), options.getAppId()); + assertEquals("Private key should be", PingppTestData.getPKCS8PrivateKey(), options.getPrivateKey()); + } + + @Test + public void testDefaultRequestOptions() { + Pingpp.apiKey = PingppTestData.getApiKey(); + Pingpp.appId = PingppTestData.getAppID(); + Pingpp.privateKey = PingppTestData.getPKCS8PrivateKey(); + + RequestOptions options = RequestOptions.getDefault(); + + assertEquals("API Key should be", PingppTestData.getApiKey(), options.getApiKey()); + assertEquals("App ID should be", PingppTestData.getAppID(), options.getAppId()); + assertEquals("Private key should be", PingppTestData.getPKCS8PrivateKey(), options.getPrivateKey()); + } + + @Test + public void testRequestOptionsRequest() throws PingppException { + RequestOptions options = new RequestOptionsBuilder() + .setApiKey(PingppTestData.getApiKey()) + .setAppId(PingppTestData.getAppID()) + .setPrivateKey(PingppTestData.getPKCS8PrivateKey()) + .build(); + + String userId = "test_user_001"; + User obj = User.retrieve(userId, options); + + assertNull("Pingpp.apiKey should be null", Pingpp.apiKey); + assertNull("Pingpp.appId should be null", Pingpp.appId); + assertEquals("object should be user", "user", obj.getObject()); + assertEquals("id", userId, obj.getId()); + assertEquals("app", PingppTestData.getAppID(), obj.getApp()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/SubBankTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/SubBankTest.java new file mode 100644 index 0000000..1094a0e --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/SubBankTest.java @@ -0,0 +1,36 @@ +package com.pingplusplus; + +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.SubBank; +import com.pingplusplus.model.SubBankCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class SubBankTest extends PingppTestBase { + /** + * 银行支行列表查询 + */ + @Test public void testSubBankQuery() throws PingppException { + Map params = new HashMap<>(); + params.put("app", PingppTestData.getAppID()); + params.put("open_bank_code", "0308"); // 银行开户行编号 + params.put("prov", "浙江省"); // 省份 + params.put("city", "宁波市"); // 城市 + params.put("channel", "chanpay"); // 相关 transfer 渠道 + + SubBankCollection obj = SubBank.query(params); + + System.out.println(obj); + + SubBank subBank = obj.getData().get(0); + + assertEquals("list", obj.getObject()); + assertEquals("sub_bank", subBank.getObject()); + assertEquals("浙江省", subBank.getProv()); + assertEquals("宁波市", subBank.getCity()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/WebhookTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/WebhookTest.java new file mode 100644 index 0000000..660522b --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/WebhookTest.java @@ -0,0 +1,64 @@ +package com.pingplusplus; + +import com.pingplusplus.model.*; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/* + * @author Afon, @date 17-03-28 + */ +public class WebhookTest extends PingppTestBase { + /** + * 解析 webhooks 消息 (withdrawal) + */ + @Test + public void testWebhooksParseWithdrawal() { + String webhookData = PingppTestData.getWithdrawalWebhooksData(); + + PingppObject obj = Webhooks.getObject(webhookData); + + assertTrue("object should be an instance of Withdrawal", obj instanceof Withdrawal); + assertEquals("object should be withdrawal", "withdrawal", ((Withdrawal) obj).getObject()); + } + + /** + * 解析 webhooks 消息 (recharge) + */ + @Test + public void testWebhooksParseRecharge() { + String webhookData = PingppTestData.getRechargeSucceededEventData(); + + PingppObject obj = Webhooks.getObject(webhookData); + + assertTrue("object should be an instance of Recharge", obj instanceof Recharge); + assertEquals("object should be recharge", "recharge", ((Recharge) obj).getObject()); + } + + /** + * 解析 webhooks 消息 (order) + */ + @Test + public void testWebhooksParseOrder() { + String webhookData = PingppTestData.getOrderSucceededEventData(); + + PingppObject obj = Webhooks.getObject(webhookData); + + assertTrue("object should be an instance of Order", obj instanceof Order); + assertEquals("object should be order", "order", ((Order) obj).getObject()); + } + + /** + * 解析 webhooks 消息 (agreement) + */ + @Test + public void testWebhooksParseAgreement() { + String webhookData = PingppTestData.getAgreementEventData(); + + PingppObject obj = Webhooks.getObject(webhookData); + + assertTrue("object should be an instance of Agreement", obj instanceof Agreement); + assertEquals("object should be agreement", "agreement", ((Agreement) obj).getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/WeixinOpenidTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/WeixinOpenidTest.java new file mode 100644 index 0000000..9cb6c92 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/WeixinOpenidTest.java @@ -0,0 +1,49 @@ +package com.pingplusplus; + +import com.pingplusplus.exception.ChannelException; +import com.pingplusplus.util.WxLiteOAuth; +import com.pingplusplus.util.WxLiteOAuth.AuthResult; +import com.pingplusplus.util.WxpubOAuth; +import org.junit.Test; + +import java.io.UnsupportedEncodingException; + +public class WeixinOpenidTest extends PingppTestBase { + /** + * 通过 appId, secret, code 获取微信公众号 openid 信息。 + */ + @Test + public void testWxPubOpenid() throws UnsupportedEncodingException { + try { + String openid = WxpubOAuth.getOpenId("wx262681902838", "piOgk852569gKXpRLjhh38J6O14H7ejb", "ZkJfiPkzQAFCxc4vxRE4"); + System.out.println(openid); + } catch (ChannelException e) { + System.out.println(e.getMessage()); + System.out.println(e.getParam()); + } + } + + /** + * 通过 appId, secret, code 获取微信小程序 openid 信息。 + */ + @Test + public void testWxLiteOpenid() throws UnsupportedEncodingException { + try { + String openid = WxLiteOAuth.getOpenId("wx283881926260", "piOgk852569gKXpRLjhh38J6O14H7ejb", "vNnPjvqD0BT3snbxVLjY"); + System.out.println(openid); + } catch (ChannelException e) { + System.out.println(e.getMessage()); + System.out.println(e.getParam()); + } + } + + /** + * 通过 appId, secret, code 获取微信小程序 session_key。 + */ + @Test + public void testWxLiteSession() throws UnsupportedEncodingException { + AuthResult result = WxLiteOAuth.getSession("wx283881926260", "piOgk852569gKXpRLjhh38J6O14H7ejb", "vNnPjvqD0BT3snbxVLjY"); + System.out.println(result.getOpenid()); + System.out.println(result.getSessionKey()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/agreement/AgreenmentTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/agreement/AgreenmentTest.java new file mode 100644 index 0000000..b92c8c7 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/agreement/AgreenmentTest.java @@ -0,0 +1,77 @@ +package com.pingplusplus.agreement; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.InvalidRequestException; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.Agreement; +import com.pingplusplus.model.AgreementCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class AgreenmentTest extends PingppTestBase { + + @Test + public void testCreate() throws PingppException { + Map params = new HashMap<>(); + params.put("app", PingppTestData.getAppID()); // App ID + params.put("contract_no", "2018051700001"); // 签约协议号 + params.put("channel", "qpay"); // 签约渠道 + Map extra = new HashMap<>(); + extra.put("display_account", "签约测试"); // 可选,签约用户的名称,用于页面展示,如商户侧账号,昵称。 + params.put("extra", extra); + Map metadata = new HashMap<>(); + params.put("metadata", metadata); // metadata 元数据 + + Agreement agreement; + try { + agreement = Agreement.create(params); + + assertEquals("object should be agreement", "agreement", agreement.getObject()); + } catch (InvalidRequestException e) { + assertTrue("error message should be", e.getMessage().contains("该签约协议号 2018051700001 在 qpay 渠道下已使用。请用新的签约协议号发起签约。")); + } + } + + @Test + public void testRetrieve() throws PingppException { + String id = "agr_19EEE7QdgGMCoY"; + Agreement agreement = Agreement.retrieve(id); + + assertEquals("object should be agreement", "agreement", agreement.getObject()); + assertEquals("object id should be", id, agreement.getId()); + } + + @Test + public void testList() throws PingppException { + Map params = new HashMap<>(); + params.put("per_page", 3); // 每页数量 + params.put("app", PingppTestData.getAppID()); // App ID 此参数必填 + + AgreementCollection objs = Agreement.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + @Test + public void testCancel() throws PingppException { + String id = "agr_19EEE7QdgGMCoY"; + + Agreement agreement; + + try { + agreement = Agreement.cancel(id); + + assertEquals("object should be agreement", "agreement", agreement.getObject()); + assertEquals("object id should be", id, agreement.getId()); + assertEquals("object status should be", "canceled", agreement.getStatus()); + } catch (InvalidRequestException e) { + assertTrue("error message should be", e.getMessage().contains("该签约对象不能被更新状态。") && e.getMessage().contains("当前的状态为:canceled。")); + } + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceBonusTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceBonusTest.java new file mode 100644 index 0000000..bad9bb2 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceBonusTest.java @@ -0,0 +1,57 @@ +package com.pingplusplus.balance; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.BalanceBonus; +import com.pingplusplus.model.BalanceBonusCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class BalanceBonusTest extends PingppTestBase { + /** + * 余额赠送 balance-bonus + */ + @Test + public void testBalanceBonusCreate() throws PingppException { + Map params = new HashMap<>(); + params.put("user", "user_test_02"); // 受赠的用户 ID, 必传 + params.put("amount", 10); // 支付受赠余额,单位:分, 必传 + params.put("order_no", "2017" + System.currentTimeMillis()); // 商户订单号,必须在商户系统内唯一, 必传 + params.put("description", "Balance bonus description."); // 描述, 可选 + // 创建 balance-bonus 方法 + // 参数: params + BalanceBonus obj = BalanceBonus.create(params); + + assertEquals("object should be balance_bonus", "balance_bonus", obj.getObject()); + } + + /** + * 查询单个 balance-bonus + */ + @Test public void testBalanceBonusRetrieve() throws PingppException { + // 查询单个 balance-bonus 方法 + // 参数: balance-bonus id + BalanceBonus obj = BalanceBonus.retrieve("650170821521710018560001"); + + assertEquals("object should be balance_bonus", "balance_bonus", obj.getObject()); + } + + /** + * 查询 balance-bonus 列表 + */ + @Test public void testBalanceBonusList() throws PingppException { + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 10); + + // 查询 balance-bonus 列表方法 + // 参数: params + BalanceBonusCollection objs = BalanceBonus.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceSettlementTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceSettlementTest.java new file mode 100644 index 0000000..8a74b4e --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceSettlementTest.java @@ -0,0 +1,43 @@ +package com.pingplusplus.balance; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.BalanceSettlement; +import com.pingplusplus.model.BalanceSettlementCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class BalanceSettlementTest extends PingppTestBase { + /** + * 查询单个结算到余额 + */ + @Test + public void testRetrieve() throws PingppException { + + // 查询单个 balance_settlement 方法 + // 参数: balance_settlement id + BalanceSettlement obj = BalanceSettlement.retrieve("670180130750711562240001"); + + assertEquals("object should be balance_settlement", "balance_settlement", obj.getObject()); + } + + /** + * 查询结算到余额列表 + */ + @Test + public void testList() throws PingppException { + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 3); + params.put("user", "user_test_01"); + // 查询 balance_settlement 列表方法 + // 参数: params + BalanceSettlementCollection objs = BalanceSettlement.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceTransactionTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceTransactionTest.java new file mode 100644 index 0000000..cb31df0 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceTransactionTest.java @@ -0,0 +1,41 @@ +package com.pingplusplus.balance; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.BalanceTransaction; +import com.pingplusplus.model.BalanceTransactionCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class BalanceTransactionTest extends PingppTestBase { + /** + * 查询单个余额明细 (balance_transaction) + */ + @Test + public void testBalanceTransactionRetrieve() throws PingppException { + + // 查询单个 balance_transaction 方法 + // 参数: balance_transaction id + BalanceTransaction obj = BalanceTransaction.retrieve("600170822661998110720001"); + + assertEquals("object should be balance_transaction", "balance_transaction", obj.getObject()); + } + + /** + * 查询余额明细 (balance_transaction) 列表 + */ + @Test public void testBalanceTransactionList() throws PingppException { + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 3); + // 查询 balance_transaction 列表方法 + // 参数: params + BalanceTransactionCollection objs = BalanceTransaction.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceTransferTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceTransferTest.java new file mode 100644 index 0000000..f6277c9 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/balance/BalanceTransferTest.java @@ -0,0 +1,59 @@ +package com.pingplusplus.balance; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.BalanceTransfer; +import com.pingplusplus.model.BalanceTransferCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class BalanceTransferTest extends PingppTestBase { + /** + * 创建 balance_transfer + */ + @Test + public void testBalanceTransfer() throws PingppException { + Map params = new HashMap(); + params.put("user", "test_user_001"); + params.put("recipient", "test_user_003"); + params.put("amount", 10); + params.put("order_no", "2017" + System.currentTimeMillis()); + params.put("description", "Balance transfer description."); + + // 创建 balance_transfer 方法 + // 参数: params + BalanceTransfer obj = BalanceTransfer.create(params); + + assertEquals("object should be balance_transfer", "balance_transfer", obj.getObject()); + } + + /** + * 查询单个 balance_transfer + */ + @Test public void testBalanceTransferRetrieve() throws PingppException { + + // 查询单个 balance_transfer 方法 + // 参数: balance_transfer id + BalanceTransfer obj = BalanceTransfer.retrieve("660170821690361139200002"); + + assertEquals("object should be balance_transfer", "balance_transfer", obj.getObject()); + } + + /** + * 查询 balance_transfer 列表 + */ + @Test public void testBalanceTransferList() throws PingppException { + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 10); + // 查询 balance_transfer 列表方法 + // 参数: params + BalanceTransferCollection objs = BalanceTransfer.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/coupon/CouponTemplateTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/coupon/CouponTemplateTest.java new file mode 100644 index 0000000..ccacace --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/coupon/CouponTemplateTest.java @@ -0,0 +1,101 @@ +package com.pingplusplus.coupon; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.CouponTemplate; +import com.pingplusplus.model.CouponTemplateCollection; +import com.pingplusplus.model.DeletedCouponTemplate; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class CouponTemplateTest extends PingppTestBase { + /** + * 创建优惠券模板 + */ + @Test + public void testCouponTemplateCreate() throws PingppException { + Map params = new HashMap(); + params.put("name", "25%OFF"); // 优惠券模板名称, 可选 + params.put("type", 2); // 优惠券模板的类型 1:现金券;2:折扣券, 必传 + params.put("percent_off", 25); // 折扣百分比, 如 20 表示 8 折, 100 表示免费。当 type 为 2 时,必传。 + params.put("amount_available", 1000); // 订单金额大于等于该值时,优惠券有效(适用于满减);0 表示无限制, 可选 + params.put("max_circulation", 1000); // 优惠券最大生成数量,当已生成数量达到最大值时,不能再生成优惠券;默认 null,表示可以无限生成, 可选 + Map metadata = new HashMap(); + metadata.put("custom_key", "custom_value"); + params.put("metadata", metadata); + Map expiration = new HashMap(); + Long duration = new Long(2592000); + expiration.put("duration", duration); + params.put("expiration", expiration); // 优惠券模板过期策略 + + CouponTemplate obj = CouponTemplate.create(params); + + assertEquals("object should be coupon_template", "coupon_template", obj.getObject()); + assertEquals("amount_available", params.get("amount_available"), obj.getAmountAvailable()); + assertEquals("max_circulation", params.get("max_circulation"), obj.getMaxCirculation()); + assertEquals("type", params.get("type"), obj.getType()); + assertEquals("name", params.get("name"), obj.getName()); + assertEquals("percent_off", params.get("percent_off"), obj.getPercentOff()); + assertEquals("expiration duration", expiration.get("duration"), obj.getExpiration().getDuration()); + assertEquals("times_circulated", 0, obj.getTimesCirculated().intValue()); + assertEquals("times_redeemed", 0, obj.getTimesRedeemed().intValue()); + } + + /** + * 查询优惠券模板 + */ + @Test public void testCouponTemplateRetrieve() throws PingppException { + String couponTemplateId = "300117082315262900016402"; + // 查询优惠券模板方法 + // 参数: couponTemplateId (优惠券模板 id) + CouponTemplate obj = CouponTemplate.retrieve(couponTemplateId); + + assertEquals("object should be coupon_template", "coupon_template", obj.getObject()); + } + + /** + * 查询优惠券模板列表 + */ + @Test public void testCouponTemplateList() throws PingppException { + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 3); + // 查询优惠券模板列表 + // 参数: params + CouponTemplateCollection objs = CouponTemplate.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 更新优惠券模板 + */ + @Test public void testCouponTemplateUpdate() throws PingppException { + String couponTemplateId = "300117082315262900016402"; + Map params = new HashMap<>(); + Map metadata = new HashMap<>(); + metadata.put("key1", "value1"); + params.put("metadata", metadata); + // 更新优惠券模板方法 + // 参数: couponTemplateId (优惠券模板 id) + CouponTemplate obj = CouponTemplate.update(couponTemplateId, params); + + assertEquals("object should be coupon_template", "coupon_template", obj.getObject()); + } + + /** + * 删除优惠券模板 + */ + @Test public void testCouponTemplateDelete() throws PingppException { + String couponTemplateId = "300117082315262900016402"; + // 删除优惠券模板方法 + // 参数: couponTemplateId (优惠券模板 id) + DeletedCouponTemplate obj = CouponTemplate.delete(couponTemplateId); + + assertEquals("id", couponTemplateId, obj.getId()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/coupon/CouponTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/coupon/CouponTest.java new file mode 100644 index 0000000..63d9423 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/coupon/CouponTest.java @@ -0,0 +1,128 @@ +package com.pingplusplus.coupon; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.Coupon; +import com.pingplusplus.model.CouponCollection; +import com.pingplusplus.model.CouponTemplate; +import com.pingplusplus.model.DeletedCoupon; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class CouponTest extends PingppTestBase { + /** + * 创建单个优惠券 Coupon + */ + @Test + public void testCouponCreate() throws PingppException { + String userId = "test_user_001"; // 用户 ID, 必传 + Map params = new HashMap<>(); + params.put("coupon_template", "300117082315262900016402"); // 优惠券模板 id, 必传 + // 创建优惠券 Coupon 方法 + // 参数一: userId + // 参数二: params + Coupon obj = Coupon.create(userId, params); + + assertEquals("object should be coupon", "coupon", obj.getObject()); + } + + /** + * 批量创建优惠券 + */ + @Test public void testCouponBatchCreate() throws PingppException { + String couponId = "300117082315262900016402"; // 优惠券模板 id + Map params = new HashMap<>(); + List users = new ArrayList<>(); // 用户 ID 列表 + users.add("test_user_002"); + params.put("users", users); + CouponCollection objs = CouponTemplate.createCoupons(couponId, params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 查询单个优惠券 Coupon + */ + @Test public void testCouponRetrieve() throws PingppException { + String userId = "test_user_001"; + String couponId = "300317082315265100025202"; + // 查询单个优惠券 Coupon + // 参数一: userId + // 参数二: couponId (优惠券 id) + Coupon obj = Coupon.retrieve(userId, couponId); + + assertEquals("object should be coupon", "coupon", obj.getObject()); + } + + /** + * 查询用户优惠券 Coupon 列表 + */ + @Test public void testUserCouponList() throws PingppException { + String userId = "test_user_001"; + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 3); + // 查询用户优惠券 Coupon 列表方法 + // 参数一: userId + // 参数二: params + CouponCollection objs = Coupon.list(userId, params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 查询优惠券模板下的优惠券列表 + */ + @Test public void testCouponList() throws PingppException { + String couponId = "300117082315262900016402"; + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 3); + // 查询优惠券模板下的优惠券列表 + // 参数一: userId + // 参数二: params + CouponCollection objs = CouponTemplate.listCoupons(couponId, params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 更新优惠券 Coupon + */ + @Test public void testCouponUpdate() throws PingppException { + String userId = "test_user_001"; + String couponId = "300317082315265100025202"; + Map params = new HashMap<>(); + Map metadata = new HashMap<>(); + metadata.put("key1", "value1"); + params.put("metadata", metadata); + + // 更新优惠券 Coupon 方法 + // 参数一: userId + // 参数二: couponId (优惠券 id) + // 参数三: params + Coupon obj = Coupon.update(userId, couponId, params); + + assertEquals("object should be coupon", "coupon", obj.getObject()); + } + + /** + * 删除优惠券 Coupon + */ + @Test public void testCouponDelete() throws PingppException { + String userId = "test_user_001"; + String couponId = "300317022810293600038701"; + // 删除优惠券 Coupon + // 参数一: userId + // 参数二: couponId (优惠券 id) + DeletedCoupon obj = Coupon.delete(userId, couponId); + + assertEquals("id", couponId, obj.getId()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/order/OrderTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/order/OrderTest.java new file mode 100644 index 0000000..a5a9f58 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/order/OrderTest.java @@ -0,0 +1,164 @@ +package com.pingplusplus.order; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.*; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/* + * @author Afon, @date 17-03-28 + */ +public class OrderTest extends PingppTestBase { + + /** + * 创建 order + */ + @Test public void testCreateOrder() throws PingppException { + Map params = new HashMap(); + params.put("uid", "test_user_001"); // 用户在当前 app 下的 User ID, 可选 + params.put("app", PingppTestData.getAppID()); // App ID, 必传 + params.put("merchant_order_no", "2017" + System.currentTimeMillis()); // 商户订单号, 必传 + params.put("subject", "ORDER_SUBJECT"); // 商品的标题, 必传 + params.put("body", "ORDER_BODY"); // 商品的描述信息, 必传 + params.put("amount", 100); // 订单总金额,单位:分, 必传 + params.put("currency", "cny"); // 仅支持人民币 cny, 必传 + params.put("client_ip", "192.168.1.125"); // 客户端的 IP 地址 (IPv4 格式,要求商户上传真实的,渠道可能会判断), 必传 + + Order obj = Order.create(params); // 创建 Order 对象 方法 + + assertEquals("object should be order", "order", obj.getObject()); + assertEquals("amount", ((Integer)params.get("amount")).intValue(), obj.getAmount().intValue()); + assertEquals("app", params.get("app"), obj.getApp()); + assertEquals("user ID", params.get("uid"), obj.getUid()); + assertEquals("merchant_order_no", params.get("merchant_order_no"), obj.getMerchantOrderNo()); + assertEquals("subject", params.get("subject"), obj.getSubject()); + assertEquals("body", params.get("body"), obj.getBody()); + } + + /** + * 支付 order + */ + @Test public void testPayOrder() { + Map params = new HashMap<>(); + params.put("channel", "alipay_wap"); + params.put("charge_amount", 100); + Map extra = new HashMap<>(); // extra: 根据各个渠道传入相应的参数 + extra.put("success_url", "http://www.pingxx.com"); + params.put("extra", extra); + Order order; // 创建支付 Order 对象 方法 + try { + order = Order.pay("2001708220000281981", params); + assertEquals("object should be order", "order", order.getObject()); + } catch (PingppException e) { + System.out.println(e.toString()); + } + } + + /** + * 取消 order + */ + @Test public void testCancelOrder() throws PingppException { + Order order = Order.cancel("2001708220000280391"); // 取消 Order 对象方法 + + assertEquals("object should be order", "order", order.getObject()); + } + + /** + * 查询单个 order + */ + @Test public void testOrderRetrieve() throws PingppException { + Order obj = Order.retrieve("2001708220000281981"); // 查询单个 order 方法 参数: orderId + + assertNotNull(obj); + assertEquals("object should be order", "order", obj.getObject()); + } + + /** + * 获取 order 列表 + */ + @Test public void testGetOrderList() throws PingppException { + Map params = new HashMap(); + params.put("page", 1); + params.put("per_page", 3); + params.put("paid", false); + params.put("app", PingppTestData.getAppID()); + params.put("refunded", false); + + OrderCollection objs = Order.list(params); //查询 order 列表方法 + + assertEquals("object should be list", "list", objs.getObject()); + assertEquals("data count should be same with limit", ((Integer)params.get("per_page")).intValue(), objs.getData().size()); + } + + /** + * 查询订单中 Charge 对象 + */ + @Test public void testOrderChargeRetrieve() throws PingppException { + // 查询订单中 Charge 对象 + // 参数一: order id + // 参数二: charge id + Charge obj = Order.retrieveCharge("2001708220000221911", "ch_88mbTKu9mbn9mfT4KSCiHiX5"); + assertEquals("object should be charge", "charge", obj.getObject()); + } + + /** + * 查询订单中 Charge 列表 + */ + @Test public void testOrderChargeList() throws PingppException { + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 10); + + // 查询订单中 Charge 列表 + // 参数一: orderId + // 参数二: params + ChargeCollection objs = Order.chargeList("2001708220000221911", params); + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 创建 order 退款 + */ + @Test public void testOrderRefundCreate() throws PingppException { + + Map params = new HashMap(); + params.put("description", "Order refund test."); // 必传 + params.put("refund_mode", "to_source"); + + // 创建 order 退款方法 + // 参数一: orderId + // 参数二: params + OrderRefundCollection objs = OrderRefund.create("2001708220000281981", params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 查询 order 退款 + */ + @Test public void testOrderRefundRetrieve() throws PingppException { + // 查询 order 退款方法 + // 参数一: orderId + // 参数二: refundId + Refund obj = OrderRefund.retrieve("2001708220000258501", "re_5GefjD14GW50qrT40Gq9KmPS"); + assertEquals("object should be refund", "refund", obj.getObject()); + } + + /** + * 查询 order 退款列表 + */ + @Test public void testOrderRefundList() throws PingppException { + + // 查询 order 退款列表 + // 参数: orderId + OrderRefundCollection objs = OrderRefund.list("2001708220000258501"); + assertEquals("object should be list", "list", objs.getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltySettlementTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltySettlementTest.java new file mode 100644 index 0000000..9730b03 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltySettlementTest.java @@ -0,0 +1,69 @@ +package com.pingplusplus.order; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.RoyaltySettlement; +import com.pingplusplus.model.RoyaltySettlementCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class RoyaltySettlementTest extends PingppTestBase { + /** + * 创建 royalty_settlement + */ + @Test + public void testRoyaltySettlementCreate() throws PingppException { + Map params = new HashMap<>(); + params.put("payer_app", PingppTestData.getAppID()); // 分润发起方所在应用的 id, 必传 + params.put("method", "alipay"); // 分润的方式,余额 balance 或渠道名称,例如 alipay, 必传 + params.put("recipient_app", PingppTestData.getAppID()); // 分润接收方的应用 id,即分润用户关联的应用 id。可选 + params.put("is_preview", false); // 是否预览,选择预览不会真实创建分润结算对象,也不会修改分润对象的状态, 可选 + // 创建 royalty_settlement 方法 + // 参数: params + RoyaltySettlement obj = RoyaltySettlement.create(params); + + assertEquals("object should be royalty_settlement", "royalty_settlement", obj.getObject()); + } + + /** + * 查询单个 royalty_settlement + */ + @Test public void testRoyaltySettlementRetrieve() throws PingppException { + // 查询单个 royalty_settlement 方法 + // 参数: royalty_settlement id + RoyaltySettlement obj = RoyaltySettlement.retrieve("170302171104000011"); + + assertEquals("object should be royalty_settlement", "royalty_settlement", obj.getObject()); + } + + /** + * 查询 royalty_settlement list + */ + @Test public void testRoyaltySettlementList() throws PingppException { + Map params = new HashMap(); + params.put("payer_app", PingppTestData.getAppID()); + params.put("per_page", 3); + params.put("page", 1); + // 查询 royalty_settlement list 列表方法 + // 参数: params + RoyaltySettlementCollection objs = RoyaltySettlement.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 更新 royalty_settlement + */ + @Test public void testRoyaltySettlementUpdate() throws PingppException { + Map params = new HashMap<>(); + params.put("status", "canceled"); // 需要更新的状态 [pending, canceled] + // 更新 royalty_settlement 方法 + // 参数: params + RoyaltySettlement.update("170302171104000011", params); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltyTemplateTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltyTemplateTest.java new file mode 100644 index 0000000..a78101a --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltyTemplateTest.java @@ -0,0 +1,123 @@ +package com.pingplusplus.order; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.DeleteRoyaltyTemplate; +import com.pingplusplus.model.RoyaltyTemplate; +import com.pingplusplus.model.RoyaltyTemplateCollection; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class RoyaltyTemplateTest extends PingppTestBase { + /** + * 创建 royalty_template + */ + @Test + public void testRoyaltyTemplateCreate() throws PingppException { + Map params = new HashMap<>(); + params.put("app", PingppTestData.getAppID()); // App ID, 必传 + params.put("name", "royalty_templates name"); // 模板名称,允许中英文等常用字符, 可选 + + Map rule = new HashMap<>(); + rule.put("royalty_mode", "rate"); // 分润模式。分为按订单金额(包含优惠券金额)的比例 rate 和固定金额 fixed, 必传 + rule.put("refund_mode", "no_refund"); // 退分润模式。分为退款时不退分润 no_refund、按比例退分润 proportional 和一旦退款分润全退 full_refund, 必传 + // 分配模式。指当订单确定的层级如果少于模板配置层级时,模板中多余的分润金额是归属于收款方 receipt_reserved 还是服务方 service_reserved。 + // 必传 + rule.put("allocation_mode", "receipt_reserved"); + + List data = new ArrayList<>(); // 分润数据列表, 必传 + Map data1 = new HashMap<>(); + data1.put("level", 0); // 子商户层级值,0 表示平台, 1 表示一级子商户,取值范围 >=0 + data1.put("value", 11); // 分润数值。rate 下取值为 0 - 10000,单位为 0.01 %,fixed 下取值为 0 - 1000000,单位为分 + Map data2 = new HashMap<>(); + data2.put("level", 1); + data2.put("value", 12); + data.add(data1); + data.add(data2); + + rule.put("data", data); + params.put("rule", rule); + + // 创建 royalty_template 方法 + // 参数: params + RoyaltyTemplate obj = RoyaltyTemplate.create(params); + + assertEquals("object should be royalty_template", "royalty_template", obj.getObject()); + assertEquals("name", params.get("name"), obj.getName()); + } + + /** + * 查询单个 royalty_template + */ + @Test public void testRoyaltyTemplateRetrieve() throws PingppException { + String id = "450170822152200001"; + // 查询单个 royalty_template 方法 + // 参数: royalty_template id + RoyaltyTemplate obj = RoyaltyTemplate.retrieve(id); + + assertEquals("object should be royalty_template", "royalty_template", obj.getObject()); + assertEquals("id", id, obj.getId()); + } + + /** + * 查询 royalty_template 列表 + */ + @Test public void testRoyaltyTemplateList() throws PingppException { + Map params = new HashMap<>(); + params.put("per_page", 3); + params.put("page", 1); + // 查询 royalty_template list 列表方法 + // 参数: params + RoyaltyTemplateCollection objs = RoyaltyTemplate.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 删除 royalty_template + */ + @Test public void testRoyaltyTemplateDelete() throws PingppException { + String id = "450170822185800001"; + // 删除 royalty_template 方法 + // 参数: royalty_template id + DeleteRoyaltyTemplate obj = RoyaltyTemplate.delete(id); + + assertEquals("id", id, obj.getId()); + } + + /** + * 更新 royalty_template + */ + @Test public void testRoyaltyTemplateUpdate() throws PingppException { + Map params = new HashMap<>(); + params.put("name", "royalty_templates name new"); + + Map rule = new HashMap<>(); + rule.put("royalty_mode", "rate"); + rule.put("refund_mode", "no_refund"); + rule.put("allocation_mode", "receipt_reserved"); + + List data = new ArrayList<>(); + Map data1 = new HashMap<>(); + data1.put("level", 0); + data1.put("value", 11); + Map data2 = new HashMap<>(); + data2.put("level", 1); + data2.put("value", 12); + data.add(data1); + data.add(data2); + + rule.put("data", data); + params.put("rule", rule); + RoyaltyTemplate obj = RoyaltyTemplate.update("450170822152200001", params); + + assertEquals("object should be royalty_template", "royalty_template", obj.getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltyTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltyTest.java new file mode 100644 index 0000000..8d33932 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltyTest.java @@ -0,0 +1,86 @@ +package com.pingplusplus.order; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.Royalty; +import com.pingplusplus.model.RoyaltyCollection; +import com.pingplusplus.model.RoyaltyDataResult; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class RoyaltyTest extends PingppTestBase { + /** + * 批量更新 royalty + */ + @Test + public void testRoyaltyBatchUpdate() throws PingppException { + Map params = new HashMap<>(); + List ids = new ArrayList<>(); // 分润 ID 列表, 必传 + ids.add("170301124238000111"); + params.put("ids", ids); + params.put("method", "manual"); // 手动标记结算: manual 或 取消手动标记结算:null, 可选 + params.put("description", "royalty batch update description"); // 描述, 可选 + // 批量更新 royalty 方法 + // 参数: params + RoyaltyCollection objs = Royalty.batchUpdate(params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 查询 royalty + */ + @Test public void testRoyaltyRetrieve() throws PingppException { + // 查询 royalty 方法 + // 参数: royalty id + Royalty obj = Royalty.retrieve("421170321093600003"); + + assertEquals("object should be royalty", "royalty", obj.getObject()); + } + + /** + * 查询 royalty list + */ + @Test public void testRoyaltyList() throws PingppException { + Map params = new HashMap(); + params.put("per_page", 3); // 可选 + params.put("page", 1); // 可选 +// params.put("royalty_settlement", null); // 可选 关联的分润结算 ID +// params.put("royalty_transaction", null); // 可选 关联的分润结算明细 ID + // 查询 royalty list 列表方法 + // 参数: params + RoyaltyCollection objs = Royalty.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 创建分润 + */ + @Test public void testRoyaltyDataCreate() throws PingppException { + Map params = new HashMap(); + params.put("app", PingppTestData.getAppID()); // 必传 +// params.put("charge", ""); // 条件可选,对于已经成功的 order 必传该字段 + List> royaltyUsers = new ArrayList<>(); + Map user = new HashMap(); + user.put("user", "U201908030002"); + user.put("amount", 100); + royaltyUsers.add(user); + params.put("royalty_users", royaltyUsers); // 可选 分润的用户信息列表,默认为[],不分润。 + + String orderId = "2011909040000002881"; + RoyaltyDataResult result = Royalty.createData(orderId, params); + + assertTrue("succeeded", result.getSucceeded()); + assertEquals("app should be the same", PingppTestData.getAppID(), result.getApp()); + assertEquals("order ID should returned as the same", orderId, result.getOrder()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltyTransactionTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltyTransactionTest.java new file mode 100644 index 0000000..5a2d0f4 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/order/RoyaltyTransactionTest.java @@ -0,0 +1,41 @@ +package com.pingplusplus.order; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.RoyaltyTransaction; +import com.pingplusplus.model.RoyaltyTransactionCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class RoyaltyTransactionTest extends PingppTestBase { + /** + * 查询单个 royalty_transaction + */ + @Test + public void testRoyaltyTransactionRetrieve() throws PingppException { + // 查询单个 royalty_transaction 方法 + // 参数: royalty_transaction id + RoyaltyTransaction obj = RoyaltyTransaction.retrieve("170302171104000011"); + + assertEquals("object should be royalty_transaction", "royalty_transaction", obj.getObject()); + } + + /** + * 查询 royalty_transaction list + */ + @Test public void testRoyaltyTransactionList() throws PingppException { + Map params = new HashMap(); + params.put("per_page", 3); + params.put("page", 1); + + // 查询 royalty_transaction list 列表方法 + // 参数: params + RoyaltyTransactionCollection objs = RoyaltyTransaction.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/recharge/RechargeTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/recharge/RechargeTest.java new file mode 100644 index 0000000..0cf376d --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/recharge/RechargeTest.java @@ -0,0 +1,104 @@ +package com.pingplusplus.recharge; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.*; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class RechargeTest extends PingppTestBase { + /** + * 创建 recharge + */ + @Test + public void testRechargeCreate() throws PingppException { + Map params = new HashMap<>(); + params.put("user", "user_test_02"); // 充值目标用户 ID, 必传 + params.put("user_fee", 10); // 用户充值收取的手续费,单位分,不得大于 amount,不可和 balance_bonus[amount] 同时传,默认 0。可选 + params.put("description", "Recharge description."); // 描述, 可选 + Map charge = new HashMap<>(); + charge.put("amount", 100); // 用户实际支付金额,单位分, 必传 + charge.put("channel", "alipay_wap"); // 支付使用的第三方支付渠道, 必传 + charge.put("order_no", "2017" + System.currentTimeMillis()); // 商户订单号,适配每个渠道对此参数的要求,必须在商户系统内唯一, 必传 + charge.put("client_ip", "127.0.0.1"); // 客户端的 IP,IPv4,默认 127.0.0.1, 可选 + charge.put("subject", "Recharge subject"); // 充值标题,该参数最长为 32 个 Unicode 字符, 必传 + charge.put("body", "Recharge body"); // 充值描述信息,该参数最长为 128 个 Unicode 字符, 必传 + Map extra = new HashMap<>(); // extra: 根据不同渠道传入相应的参数 + extra.put("success_url", "http://www.pingxx.com"); + charge.put("extra", extra); + params.put("charge", charge); + Recharge obj = Recharge.create(params); // 创建 recharge 方法 + assertEquals("object should be recharge", "recharge", obj.getObject()); + } + + /** + * 查询单个 recharge + */ + @Test public void testRechargeRetrieve() throws PingppException { + // 查询单个 recharge 方法 + // 参数: rechargeId + Recharge obj = Recharge.retrieve("220170822678080532480001"); + + assertEquals("object should be recharge", "recharge", obj.getObject()); + } + + /** + * 查询 recharge 列表 + */ + @Test public void testRechargeList() throws PingppException { + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 10); + params.put("succeeded", true); // 是否已充值成功 + params.put("refunded", true); // 是否存在退款 (跟是否退款成功没有关系) + // 查询 recharge 列表方法 + // 参数: params + RechargeCollection objs = Recharge.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 创建 recharge_refund + */ + @Test public void testRechargeRefundCreate() throws PingppException { + Map params = new HashMap<>(); + params.put("description", "Recharge Refund Description"); // 必传 + // 创建 recharge_refund 方法 + // 参数一: rechargeId + // 参数二: params + Refund obj = RechargeRefund.create("220170822678080532480001", params); + + assertEquals("object should be refund", "refund", obj.getObject()); + } + + /** + * 查询单个 recharge_refund + */ + @Test public void testRechargeRefundRetrieve() throws PingppException { + // 查询单个 recharge_refund 方法 + // 参数一: rechargeId + // 参数二: refundId + Refund obj = RechargeRefund.retrieve("220170822360378572800001", "re_q5CmjDb1Ge9Sr580K4W10CaP"); + + assertEquals("object should be refund", "refund", obj.getObject()); + } + + /** + * 查询 recharge_refund 列表 + */ + @Test public void testRechargeRefundList() throws PingppException { + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 3); + // 查询 recharge_refund 列表方法 + // 参数一: rechargeId + // 参数二: params + RechargeRefundCollection objs = RechargeRefund.list("220170822360378572800001", params); + assertEquals("object should be list", "list", objs.getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/settle_account/SettleAccountTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/settle_account/SettleAccountTest.java new file mode 100644 index 0000000..f4a0e4e --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/settle_account/SettleAccountTest.java @@ -0,0 +1,159 @@ +package com.pingplusplus.settle_account; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.DeletedSettleAccount; +import com.pingplusplus.model.SettleAccount; +import com.pingplusplus.model.SettleAccountCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class SettleAccountTest extends PingppTestBase { + /** + * 创建结算账户 SettleAccount + */ + @Test + public void testSettleAccountCreate() throws PingppException { + String userId = "U2019053010510001"; + Map params = new HashMap(); + params.put("channel", "bank_account"); // [wx_pub, wx, alipay, bank_account] 其中一种 + Map recipient = new HashMap(); // recipient 参数请参考各个渠道,以下是 alipay 参数 + recipient.put("account", "6222987656770001"); // 接收者银行账号/卡号 + recipient.put("name", "USER NAME"); // 接收者姓名 + recipient.put("type", "b2c"); // 转账类型 + recipient.put("open_bank_code", "0102"); // 户银行编号 + recipient.put("open_bank", "工商银行"); + recipient.put("card_type", 0); + recipient.put("sub_bank", "招商银行股份有限公司上海陆家嘴支行"); + recipient.put("sub_bank_code", "308290003773"); + recipient.put("prov", "上海市"); + recipient.put("city", "上海市"); + + params.put("recipient", recipient); + + SettleAccount obj = SettleAccount.create(userId, params); // 创建 SettleAccount 方法 + + System.out.println(obj); + assertEquals("object should be settle_account", "settle_account", obj.getObject()); + assertEquals("channel", params.get("channel"), obj.getChannel()); + assertEquals("type", recipient.get("type"), obj.getRecipient().getType()); + assertEquals("open_bank_code", recipient.get("open_bank_code"), obj.getRecipient().getOpenBankCode()); + assertEquals("sub_bank_code", recipient.get("sub_bank_code"), obj.getRecipient().getSubBankCode()); + } + + /** + * 查询结算账户 + */ + @Test public void testSettleAccountRetrieve() throws PingppException { + String userId = "U2019053010510001"; + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 3); + SettleAccountCollection list = SettleAccount.list(userId, params); + if (list.getData().size() > 0) { + String settleAccountId = list.getData().get(0).getId(); // 结算账户对象 ID + + SettleAccount obj = SettleAccount.retrieve(userId, settleAccountId); // 查询结算账户方法 + + assertEquals("object should be settle_account", "settle_account", obj.getObject()); + assertEquals("id should be same", settleAccountId, obj.getId()); + } else { + System.out.println("结算账户列表为空"); + } + } + + /** + * 查询结算账户列表 + */ + @Test public void testSettleAccountList() throws PingppException { + String userId = "U2019053010510001"; + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 3); + SettleAccountCollection list = SettleAccount.list(userId, params); // 查询结算账户列表方法 userId:必传 params:可选 + + System.out.println(list); + assertEquals("object should be list", "list", list.getObject()); + } + + /** + * 删除结算账户 + */ + @Test public void testSettleAccountDelete() throws PingppException { + String userId = "U2019053010510001"; + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 3); + SettleAccountCollection list = SettleAccount.list(userId, params); + if (list.getData().size() > 0) { + String settleAccountId = list.getData().get(0).getId(); // 结算账户对象 ID + + DeletedSettleAccount deleted = SettleAccount.delete(userId, settleAccountId); // 删除结算账户方法 + + assertTrue("deleted should be true", deleted.getDeleted()); + assertEquals("id should be same", settleAccountId, deleted.getId()); + } else { + System.out.println("结算账户列表为空"); + } + } + + /** + * 结算账户更新(存管相关) + */ + @Test public void testSettleAccountUpdate() throws PingppException { + String userId = "U2019053010510001"; + String id = "320119071220443300000101"; + Map params = new HashMap<>(); + Map recipient = new HashMap<>(); + recipient.put("account", "6214888888888865"); // 银行卡号。 + recipient.put("name", "张三"); // 接收者姓名。 + recipient.put("type", "b2c"); // 转账类型。b2c:企业向个人付款,b2b:企业向企业付款。 + recipient.put("open_bank_code", "0308"); // 开户银行编号 + recipient.put("open_bank", "工商银行"); + recipient.put("sub_bank", "招商银行股份有限公司上海陆家嘴支行"); + recipient.put("sub_bank_code", "308290003773"); + recipient.put("card_type", 0); // 银行卡号类型,0:银行卡;1:存折。 + recipient.put("mobile", "13822334557"); // 手机号 + recipient.put("city", "上海市"); + recipient.put("prov", "上海市"); + + params.put("recipient", recipient); + SettleAccount obj = SettleAccount.update(userId, id, params); + + assertEquals("object should be settle_account", "settle_account", obj.getObject()); + assertEquals("account should be updated", "621488***8865", obj.getRecipient().getAccount()); + } + + /** + * 结算账户更新手机号(存管相关) + */ + @Test public void testSettleAccountUpdateMobile() throws PingppException { + String userId = "U2019053010510001"; + String id = "320119071220443300000101"; + Map params = new HashMap<>(); + params.put("mobile", "13822334557"); + SettleAccount obj = SettleAccount.updateMobile(userId, id, params); + + assertEquals("object should be settle_account", "settle_account", obj.getObject()); + assertEquals("mobile should be updated", "138****4557", obj.getRecipient().getMobile()); + } + + /** + * 结算账号打款验证接口(存管相关) + */ + @Test public void testSettleAccountVerify() throws PingppException { + String userId = "U2019053010510001"; + String id = "320119071220443300000101"; + Map params = new HashMap<>(); + params.put("receive_amount", 2); + SettleAccount obj = SettleAccount.verify(userId, id, params); + + assertEquals("object should be settle_account", "settle_account", obj.getObject()); + assertEquals("id", id, obj.getId()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/split/ProfitTransactionTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/split/ProfitTransactionTest.java new file mode 100644 index 0000000..4b82e2e --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/split/ProfitTransactionTest.java @@ -0,0 +1,37 @@ +package com.pingplusplus.split; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.ProfitTransaction; +import com.pingplusplus.model.ProfitTransactionCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class ProfitTransactionTest extends PingppTestBase { + + @Test public void testListAll() throws PingppException { + Map params = new HashMap<>(); + params.put("app", PingppTestData.getAppID()); + params.put("page", 1); + params.put("per_page", 3); + ProfitTransactionCollection obj = ProfitTransaction.list(params); + + System.out.println(obj); + + assertEquals("list", obj.getObject()); + assertEquals("profit_transaction", obj.getData().get(0).getObject()); + } + + @Test public void testRetrieve() throws PingppException { + ProfitTransaction obj = ProfitTransaction.retrieve("ptxn_1m3xtoBMRqu2qC"); + + System.out.println(obj); + + assertEquals("profit_transaction", obj.getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/split/SplitProfitTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/split/SplitProfitTest.java new file mode 100644 index 0000000..14ed828 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/split/SplitProfitTest.java @@ -0,0 +1,58 @@ +package com.pingplusplus.split; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.*; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class SplitProfitTest extends PingppTestBase { + @Test public void testCreate() throws PingppException { + Map params = new HashMap<>(); + params.put("app", PingppTestData.getAppID()); + params.put("charge", "ch_KiT4ePn9SyXDfvfPyDevn1G0"); // 交易成功的 Ping++ Charge ID + params.put("order_no", "2019" + System.currentTimeMillis()); // 分账单号,由商家自行生成,规则参照微信分账参数规则 + params.put("type", "split_normal"); // 分账类型: split_normal 为普通分账, split_return 为完结分账 + List> recipients = new ArrayList<>(); + Map recipient = new HashMap<>(); + recipient.put("split_receiver", "recv_1fRc57XpIehmFI"); + recipient.put("amount", 6); + recipient.put("name", "示例商户全称"); // 可选参数 + recipient.put("description", "Your Description"); + recipients.add(recipient); + params.put("recipients", recipients); + SplitProfit obj = SplitProfit.create(params); + + System.out.println(obj); + + assertEquals("split_profit", obj.getObject()); + } + + @Test public void testListAll() throws PingppException { + Map params = new HashMap<>(); + params.put("app", PingppTestData.getAppID()); + params.put("page", 1); + params.put("per_page", 3); + SplitProfitCollection obj = SplitProfit.list(params); + + System.out.println(obj); + + assertEquals("list", obj.getObject()); + assertEquals("split_profit", obj.getData().get(0).getObject()); + } + + @Test public void testRetrieve() throws PingppException { + SplitProfit obj = SplitProfit.retrieve("sp_1iXmM0w3VaE77Y"); + + System.out.println(obj); + + assertEquals("split_profit", obj.getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/split/SplitReceiverTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/split/SplitReceiverTest.java new file mode 100644 index 0000000..377931a --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/split/SplitReceiverTest.java @@ -0,0 +1,60 @@ +package com.pingplusplus.split; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.*; +import com.pingplusplus.model.DeletedSplitReceiver; +import com.pingplusplus.model.SplitReceiver; +import com.pingplusplus.model.SplitReceiverCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class SplitReceiverTest extends PingppTestBase { + @Test public void testCreate() throws PingppException { + Map params = new HashMap<>(); + params.put("app", PingppTestData.getAppID()); + params.put("type", "MERCHANT_ID"); // 分账接收方类型 + params.put("name", "示例商户全称"); // 分账接收方全称 + params.put("account", "190001001"); // 分账接收方帐号 + params.put("channel", "wx_pub"); // 创建分账接收方使用的渠道(参数) + SplitReceiver obj = SplitReceiver.create(params); + + System.out.println(obj); + + assertEquals("split_receiver", obj.getObject()); + } + + @Test public void testListAll() throws PingppException { + Map params = new HashMap<>(); + params.put("app", PingppTestData.getAppID()); + params.put("page", 1); + params.put("per_page", 3); + SplitReceiverCollection obj = SplitReceiver.list(params); + + System.out.println(obj); + + assertEquals("list", obj.getObject()); + assertEquals("split_receiver", obj.getData().get(0).getObject()); + } + + @Test public void testRetrieve() throws PingppException { + SplitReceiver obj = SplitReceiver.retrieve("recv_1fRc57XpIehmFI"); + + System.out.println(obj); + + assertEquals("split_receiver", obj.getObject()); + } + + @Test public void testDelete() throws PingppException { + DeletedSplitReceiver obj = SplitReceiver.delete("recv_1fRc57XpIehmFI"); + + System.out.println(obj); + + assertEquals(true, obj.getDeleted()); + assertEquals("recv_1fRc57XpIehmFI", obj.getId()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/sub_app/ContactTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/sub_app/ContactTest.java new file mode 100644 index 0000000..174a0a4 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/sub_app/ContactTest.java @@ -0,0 +1,40 @@ +package com.pingplusplus.sub_app; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.Contact; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/* + * @author Afon, @date 19-07-12 + */ +public class ContactTest extends PingppTestBase { + + /** + * 证件上传 + */ + @Test public void testAddContact() throws PingppException { + Map params = new HashMap<>(); + params.put("user", "test_user_001"); // 用户 ID + params.put("acc_no", "2019057929311601000631"); // 壹账通用户编号。此编号可在证件上传接口的返回获得 + params.put("contact_type", 1); // 联系人类型,1:第一紧急联系人、2:第二紧急联系人、3:第三紧急联系人、4、法人、5、财务人员(4、5必传) + params.put("contact_name", "杨真探"); // 联系人名称 + params.put("contact_cert_type", "01"); // 证件类型:01:身份证、02:企业营业执照、03:护照、04:港澳通行证、05:台湾往来通行证、06:临时身份证 + params.put("contact_cert_no", "310181201402149201"); // 联系人证件号 + params.put("contact_cert_valid_from", "2019-01-01"); // 联系人证件起始日,格式:“2018-12-21” + params.put("contact_cert_valid_until", "2028-12-31"); // 联系人证件截止日,格式:“2019-12-21”,长期填写:“9999-12-31” + params.put("contact_cert_mobile", "13500127654"); // 联系人手机号 + params.put("contact_job_type", 1); // 联系人工作类型,1:企业主 2:个体工商户 3:全职上班 4:兼职 5: 学生 6:退休 7:无固定职业 8:其他 +// params.put("contact_relation_ship", 1); // 联系人与本人关系,1:父母 2:配偶 3:子女 4:兄弟 5:姐妹 6:其他亲属 7:朋友 8:同事 + + Contact obj = Contact.create(params); + + assertEquals("user should be same as param", params.get("user"), obj.getUser()); + assertEquals("acc_no should be same as param", params.get("acc_no"), obj.getAccNo()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/sub_app/SubAppChannelTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/sub_app/SubAppChannelTest.java new file mode 100644 index 0000000..c209f4d --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/sub_app/SubAppChannelTest.java @@ -0,0 +1,93 @@ +package com.pingplusplus.sub_app; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.Channel; +import com.pingplusplus.model.DeletedChannel; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class SubAppChannelTest extends PingppTestBase { + /** + * 配置子商户 app 渠道参数 + */ + @Test + public void testSubAppChannelCreate() throws PingppException { + String subAppId = "app_rbDmXLHmLqbTLKm9"; + + Map params = new HashMap<>(); + params.put("channel", "bfb"); + params.put("description", "Channel params description."); + Map channelParams = new HashMap<>(); + channelParams.put("fee_rate", 60); + channelParams.put("bfb_sp", "1600200213"); + channelParams.put("bfb_key", "A9lUEVtdrrQobDHgzkzM2rThSNpXVELt"); + params.put("params", channelParams); + + // 创建子商户 channel 对象 + // 参数一: SubApp id + // 参数二: params + Channel obj = Channel.create(subAppId, params); + + assertEquals("object should be channel", "channel", obj.getObject()); + assertEquals("description", params.get("description"), obj.getDescription()); + } + + /** + * 查询子商户 app 渠道参数 + */ + @Test public void testSubAppChannelRetrieve() throws PingppException { + String subAppId = "app_rbDmXLHmLqbTLKm9"; + String channel = "bfb"; + + // 查询子商户 app 渠道参数方法 + // 参数一: subAppId + // 参数二: channel 需要查询的渠道名 + Channel obj = Channel.retrieve(subAppId, channel); + + assertEquals("object should be channel", "channel", obj.getObject()); + } + + /** + * 更新子商户 app 渠道参数 + */ + @Test public void testSubAppChannelUpdate() throws PingppException { + String subAppId = "app_rbDmXLHmLqbTLKm9"; + String channel = "bfb"; + + Map params = new HashMap<>(); + params.put("description", "Channel params update description."); + Map channelParams = new HashMap<>(); // 需要更新的渠道参数 + channelParams.put("fee_rate", 60); + channelParams.put("bfb_sp", "1600200213"); + channelParams.put("bfb_key", "A9lUEVtdrrQobDHgzkzM2rThSNpXVELt"); + params.put("params", channelParams); + + // 更新子商户 app 渠道参数方法 + // 参数一: SubApp id + // 参数二: channel 需要更新的渠道 + // 参数三: params + Channel obj = Channel.update(subAppId, channel, params); + + assertEquals("object should be channel", "channel", obj.getObject()); + } + + /** + * 删除子商户 app 渠道参数 + */ + @Test public void testSubAppChannelDelete() throws PingppException { + String subAppId = "app_rbDmXLHmLqbTLKm9"; + String channel = "bfb"; + + // 删除子商户 app 渠道参数方法 + // 参数一: subAppId + // 参数二: channel 需要删除的渠道名 + DeletedChannel obj = Channel.delete(subAppId, channel); + + assertEquals("channel", channel, obj.getChannel()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/sub_app/SubAppTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/sub_app/SubAppTest.java new file mode 100644 index 0000000..430aee2 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/sub_app/SubAppTest.java @@ -0,0 +1,91 @@ +package com.pingplusplus.sub_app; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.DeletedSubApp; +import com.pingplusplus.model.SubApp; +import com.pingplusplus.model.SubAppCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +public class SubAppTest extends PingppTestBase { + /** + * 创建子商户 app + */ + @Test + public void testSubAppCreate() throws PingppException { + String userId = "sub_app_user_" + System.currentTimeMillis(); + String displayName = "sub_app_" + System.currentTimeMillis(); + + Map params = new HashMap<>(); + params.put("user", userId); + params.put("display_name", displayName); + params.put("parent_app", PingppTestData.getAppID()); //父商户应用 ID,必须为平台或者平台下其他的子商户,默认值为平台 + + // 创建子商户 app 方法 + // 参数: params + SubApp obj = SubApp.create(params); + + assertEquals("object should be sub_app", "sub_app", obj.getObject()); + assertEquals("user", userId, obj.getUser()); + assertEquals("display_name", displayName, obj.getDisplayName()); + } + + /** + * 查询子商户 app + */ + @Test public void testSubAppRetrieve() throws PingppException { + String subAppId = "app_rbDmXLHmLqbTLKm9"; + // 查询子商户 app + // 参数: SubApp id + SubApp obj = SubApp.retrieve(subAppId); + + assertEquals("object should be sub_app", "sub_app", obj.getObject()); + assertEquals("id", subAppId, obj.getId()); + } + + /** + * 查询子商户 app 列表 + */ + @Test public void testSubAppList() throws PingppException { + Map params = new HashMap<>(); + params.put("page", 1); + params.put("per_page", 3); + // 查询子商户 app 列表方法 + // 参数: params + SubAppCollection objs = SubApp.list(params); + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 更新子商户 app + */ + @Test public void testSubAppUpdate() throws PingppException { + String subAppId = "app_rbDmXLHmLqbTLKm9"; + Map params = new HashMap<>(); + // 更新子商户 app 方法 + // 参数一: SubApp id + // 参数二: params + SubApp obj = SubApp.update(subAppId, params); + + assertEquals("object should be sub_app", "sub_app", obj.getObject()); + } + + /** + * 删除子商户 app + */ + @Test public void testSubAppDelete() throws PingppException { + String subAppId = "app_rbDmXLHmLqbTLKm9"; + // 删除子商户 app 方法 + // 参数: SubApp id + DeletedSubApp obj = SubApp.delete(subAppId); + + assertEquals("id", subAppId, obj.getId()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/transfer/TransferTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/transfer/TransferTest.java new file mode 100644 index 0000000..8818ea2 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/transfer/TransferTest.java @@ -0,0 +1,254 @@ +package com.pingplusplus.transfer; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.Transfer; +import com.pingplusplus.model.TransferCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * Transfers 企业付款 示例 + */ +public class TransferTest extends PingppTestBase { + /** + * 创建 Transfer 对象- alipay 渠道 + */ + @Test public void testAlipayTransferCreate() throws PingppException { + + Map params = new HashMap<>(); + // 付款使用的商户内部订单号。 alipay 为 1 ~ 64 位不能重复的数字字母组合; + params.put("order_no", "2017" + System.currentTimeMillis()); + // 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100,企业付款最小发送金额为1 元) + params.put("amount", 100); + // 目前支持 支付宝:alipay,银联:unionpay,微信公众号:wx_pub,通联:allinpay,京东:jdpay 余额:balance + params.put("channel", "alipay"); + params.put("currency", "cny"); + // 付款类型,支持 b2c 、b2b + params.put("type", "b2c"); + // 接收者 id, 渠道为 alipay 时,若 type 为 b2c,为个人支付宝账号,若 type 为 b2b,为企业支付宝账号。 + params.put("recipient", "13000000001"); + // 备注信息。渠道为 alipay 时,最多 100 个 Unicode 字符。 + params.put("description", "alipay transfer description"); + + Map app = new HashMap<>(); + app.put("id", PingppTestData.getAppID()); + params.put("app", app); + + Map extra = new HashMap<>(); + // 必须,收款人姓名,1~50位。 + extra.put("recipient_name", "张三"); + // 可选,收款方账户类型。可取值:1、 ALIPAY_USERID :支付宝账号对应的支付宝唯一用户号。以2088开头的16位纯数字组成。 + // 2、 ALIPAY_LOGONID (默认值):支付宝登录号,支持邮箱和手机号格式。 + extra.put("recipient_account_type", "ALIPAY_LOGONID"); + params.put("extra", extra); + + Transfer obj = Transfer.create(params); + assertEquals("object should be transfer", "transfer", obj.getObject()); + } + + /** + * 创建 Transfer 对象- allinpay 渠道 + */ + @Test public void testAllinpayTransferCreate() throws PingppException { + Map params = new HashMap<>(); + // 付款使用的商户内部订单号。 allinpay 限长20-40位不能重复的数字字母组合,必须以签约的通联的商户号开头(建议组合格式:通联商户号 + 时间戳 + 固定位数顺序流水号,不包含+号) + params.put("order_no", "099002017" + System.currentTimeMillis()); + // 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100,企业付款最小发送金额为1 元) + params.put("amount", 100); + // 目前支持 支付宝:alipay,银联:unionpay,微信公众号:wx_pub,通联:allinpay,京东:jdpay 余额:balance + params.put("channel", "allinpay"); + params.put("currency", "cny"); + // 付款类型,支持 b2c 、b2b + params.put("type", "b2c"); + params.put("description", "allinpay transfer description"); + + Map app = new HashMap<>(); + app.put("id", PingppTestData.getAppID()); + params.put("app", app); + + Map extra = new HashMap<>(); + // 必须,1~32位,收款人银行卡号或者存折号。 + extra.put("card_number", "6220888888888888"); + // 必须,1~100位,收款人姓名。 + extra.put("user_name", "张三"); + // 必须,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:必须,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:https://www.pingxx.com/api#银行编号说明 + extra.put("open_bank_code", "0103"); + // 可选,5位,业务代码,根据通联业务人员提供,不填使用通联提供默认值09900。 + // extra.put("business_code", "09900"); + // 可选,1位,银行卡号类型,0:银行卡、1:存折,不填默认使用银行卡。 + // extra.put("card_type", 0); + + params.put("extra", extra); + + Transfer obj = Transfer.create(params); + assertEquals("object should be transfer", "transfer", obj.getObject()); + } + + /** + * 创建 Transfer 对象- jdpay 渠道 + */ + @Test public void testJdpayTransferCreate() throws PingppException { + Map params = new HashMap<>(); + // 付款使用的商户内部订单号。 jdpay 限长1-64位不能重复的数字字母组合; + params.put("order_no", "2017" + System.currentTimeMillis()); + // 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100,企业付款最小发送金额为1 元) + params.put("amount", 100); + // 目前支持 支付宝:alipay,银联:unionpay,微信公众号:wx_pub,通联:allinpay,京东:jdpay 余额:balance + params.put("channel", "jdpay"); + params.put("currency", "cny"); + // 付款类型,支持 b2c 、b2b + params.put("type", "b2c"); + params.put("description", "jdpay transfer description"); + + Map app = new HashMap<>(); + app.put("id", PingppTestData.getAppID()); + params.put("app", app); + + Map extra = new HashMap<>(); + // 必须,1~32位,收款人银行卡号或者存折号。 + extra.put("card_number", "6220888888888888"); + // 必须,1~100位,收款人姓名。 + extra.put("user_name", "张三"); + // 必须,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:必须,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:https://www.pingxx.com/api#银行编号说明 + extra.put("open_bank_code", "0103"); + params.put("extra", extra); + + Transfer obj = Transfer.create(params); + assertEquals("object should be transfer", "transfer", obj.getObject()); + } + + /** + * 创建 Transfer 对象- unionpay 渠道 + */ + @Test public void testUnionpayTransferCreate() throws PingppException { + Map params = new HashMap<>(); + // 付款使用的商户内部订单号。 unionpay 为1~16位的纯数字。 + params.put("order_no", "17" + System.currentTimeMillis()); + // 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100,企业付款最小发送金额为1 元) + params.put("amount", 100); + // 目前支持 支付宝:alipay,银联:unionpay,微信公众号:wx_pub,通联:allinpay,京东:jdpay 余额:balance + params.put("channel", "unionpay"); + params.put("currency", "cny"); + // 付款类型,支持 b2c 、b2b + params.put("type", "b2c"); + // 备注信息。渠道为 unionpay 时,最多 99 个 Unicode 字符 + params.put("description", "unionpay transfer description"); + + Map app = new HashMap<>(); + app.put("id", PingppTestData.getAppID()); + params.put("app", app); + + Map extra = new HashMap<>(); + // 必须,1~32位,收款人银行卡号或者存折号。 + extra.put("card_number", "6220888888888888"); + // 必须,1~100位,收款人姓名。 + extra.put("user_name", "张三"); + // open_bank_code 和 open_bank 两个参数必传一个,建议使用 open_bank_code , + /// 若都传参则优先使用 open_bank_code 读取规则; + /// prov 和 city 均为可选参数,如果不传参,则使用默认值 "上海" 给渠道接口。 + // 条件可选,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:必须,4位,开户银行编号,详情请参考 企业付款(银行卡)银行编号说明:https://www.pingxx.com/api#银行编号说明 + extra.put("open_bank_code", "0103"); + // 条件可选,1~50位,开户银行 + extra.put("open_bank", "农业银行"); + // 可选,1~20位,省份。 + // extra.put("prov", "上海"); + // 可选,1~40位,城市。 + // extra.put("city", "上海"); + // 可选,1~80位,开户支行名称。 + // extra.put("sub_bank", "上海沪东支行"); + params.put("extra", extra); + + Transfer obj = Transfer.create(params); + assertEquals("object should be transfer", "transfer", obj.getObject()); + } + + /** + * 创建 Transfer 对象- wx_pub 渠道 + */ + @Test public void testWxPubTransferCreate() throws PingppException { + Map params = new HashMap<>(); + // 付款使用的商户内部订单号。 wx_pub 规定为 1 ~ 50 位不能重复的数字字母组合; + params.put("order_no", "2017" + System.currentTimeMillis()); + // 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100,企业付款最小发送金额为1 元) + params.put("amount", 100); + // 目前支持 支付宝:alipay,银联:unionpay,微信公众号:wx_pub,通联:allinpay,京东:jdpay 余额:balance + params.put("channel", "wx_pub"); + params.put("currency", "cny"); + // 付款类型,支持 b2c 、b2b + params.put("type", "b2c"); + // 备注信息。渠道为 wx_pub 时,最多 99 个英文和数字的组合或最多 33 个中文字符,不可以包含特殊字符; + params.put("description", "wx_pub transfer description"); + // 接收者 id, 微信企业付款时为用户在 wx_pub 下的 open_id ; + params.put("recipient", "o9zPms1OLVHU1r701mOHP0s-uK9c"); + + Map app = new HashMap<>(); + app.put("id", PingppTestData.getAppID()); + params.put("app", app); + + Map extra = new HashMap<>(); + // 可选,收款人姓名。当该参数为空,则不校验收款人姓名。 + extra.put("user_name", "张三"); + // 可选,是否强制校验收款人姓名。仅当 user_name 参数不为空时该参数生效。 + extra.put("force_check", true); + params.put("extra", extra); + + Transfer obj = Transfer.create(params); + assertEquals("object should be transfer", "transfer", obj.getObject()); + } + + /** + * 创建 Transfer 对象- balance 渠道 + */ + @Test public void testBalanceTransferCreate() throws PingppException { + Map params = new HashMap<>(); + // 付款使用的商户内部订单号。 wx_pub 规定为 1 ~ 50 位不能重复的数字字母组合; + params.put("order_no", "2017" + System.currentTimeMillis()); + // 订单总金额, 人民币单位:分(如订单总金额为 1 元,此处请填 100,企业付款最小发送金额为1 元) + params.put("amount", 100); + // 目前支持 支付宝:alipay,银联:unionpay,微信公众号:wx_pub,通联:allinpay,京东:jdpay 余额:balance + params.put("channel", "balance"); + params.put("currency", "cny"); + // 付款类型,支持 b2c 、b2b + params.put("type", "b2c"); + params.put("description", "wx_pub transfer description"); + // 接收者 id, 渠道为 balance 时,为用户在当前 app 下的用户 id。 + params.put("recipient", "user_test_02"); + + Map app = new HashMap<>(); + app.put("id", PingppTestData.getAppID()); + params.put("app", app); + + Transfer obj = Transfer.create(params); + assertEquals("object should be transfer", "transfer", obj.getObject()); + } + + /** + * 查询指定 Transfer 对象 + */ + @Test public void testTransferRetrieve() throws PingppException { + // 参数: transfer id + Transfer obj = Transfer.retrieve("tr_WTarz1Ga9q90X1O4q91Oevv1"); + assertEquals("object should be transfer", "transfer", obj.getObject()); + } + + /** + * 查询 Transfer 对象列表 + */ + @Test public void testTransferList() throws PingppException { + Map params = new HashMap<>(); + params.put("limit", 5); + Map app = new HashMap<>(); + app.put("id", PingppTestData.getAppID()); + params.put("app", app); + + TransferCollection objs = Transfer.list(params); + assertEquals("object should be list", "list", objs.getObject()); + } + +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/user/UserPicTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/user/UserPicTest.java new file mode 100644 index 0000000..38ba083 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/user/UserPicTest.java @@ -0,0 +1,36 @@ +package com.pingplusplus.user; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.UserPic; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/* + * @author Afon, @date 19-07-12 + */ +public class UserPicTest extends PingppTestBase { + + /** + * 证件上传 + */ + @Test public void testUploadPic() throws PingppException { + Map params = new HashMap(); + params.put("user", "test_user_001"); // 用户 ID,首字母必须是英文数字或者 _-@, 必传 + params.put("type", "customer"); // 用户类型,customer: 对私,business: 对公 +// params.put("acc_no", "2019057929311601000631"); // 壹账通用户编号。覆盖的时候使用,新用户不需要该字段 + params.put("operate_type", "00"); // 操作类型,00: 新增,01: 修改,02: 增开户。不传默认为新增 + // 图片内容,base64 编码 + params.put("pic", "/9j/4AAQSkZJRgABAQAASABIAAD/2wCEAAEBAQEBAQIBAQIDAgICAwQDAwMDBAUEBAQEBAUGBQUFBQUFBgYGBgYGBgYHBwcHBwcICAgICAkJCQkJCQkJCQkBAQEBAgICBAICBAkGBQYJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCf/CABEIARsBkAMBIgACEQEDEQH/xAAfAAEAAgEFAQEBAAAAAAAAAAAACQoIAQIDBAcFBgv/2gAIAQEAAAAAvQPi/jPifD+dw8LTk1110373Nv5ubn5ubsc3Lz7+Tk1113bt27fv37t+u7j/AGGpULyA+H+P6u3aajXVru137+59Tt9vm5OTl37+Tfu37tePY5+fd2UdVkyRorGWcdwAAAAAAEG+RUnxWLs5bgAAAAAAIM8iJRCsLZ43Brjngj6bI39EAAAAAgyyJlEKvloHcMLq42ZkhHlkXHtlmHeAAAABBlkTKIVcrRe4xBgTtTcgwfgDtuAAAAAQZ5ESiFWm0puKqNq4CHjqzIgAAAAg0yIlDKrtqDcxriwnjAVK7agAAAAINcipQCqxal3IRJF8pAFTi2LuAAAACDbIqT8qu2oNyIf3eQEBU8tg7gAAAAg2yKk/KrdqLc/KVqLQQH5erTa+AAAABBxkTJ8VWLUu516Xlg303tdrt9jsVrbF2cwAAAAIOMipPSqrao3PBKymE8lUhvJyfLq8z3eEWogAAAAQc5FydlU61fueCxfzdQJYafQ6fyrF2TVaeyyAAAACEXICToqiWudzxKpFIb0vnfP+dwdfT49qQAAAAEJ/u8nJU4tjanKNNumjdtAAAABC97XJsVLLaWoAAAAAAENXsEmpUdtw6gAAAAAAQ3+vSZFQ+3gAAAAAAAhz9dkvKgdvwAAAAAABDv67JWU9bhQAeVfS9C+J9weU+aYYS4DzToetYw5E/VbtoAh59ekoKctxvQAwIjd/eSVYdesZ9YeZ04J19LeHOMMoFLXFJySjJ2CT9rNBNLoAh89eklKaNy/QA/K138wvOMAcusjoyZcO15/LB+hCjxlVBLhB15BP6H1WOa+F2SOcgEP3sEkJTDue6AGsA35GwVVhyHzcq3SBfgcnLNf3RhdQS/ol0dZUrSFTCz1Rvmvkmi1s6gh+9kkdKWd03QAdbt7cPYwJt8IJB4WMrflSYiF3O75VYy57pT1uFUbLuX8/a1h1JhQh99pkZKV91HQAAGzeAGlP63/v6sGH7qWP94a6Q9+4SKFKm6voAAaa7PKPW2LOTXbfIjZk9dH8JEdKj7SHhGKkkNVS1XDt7zIiUpbregBjH+z9h6kS8jOBcq1bToWX66vx5rIbuSwDiRiv6pzxmWWYQZucbo+5lUFXuUsFO24nDv75IcUnrsWgBjbW58s/Z5hS24sS41q+ayjWu+vY66bzKFCUmMb9T+HnmhumuhA4pwt0LXemUp33Eoeve5Cyk9di0AMcqqkun7nDmffzfAOSr7WFPr2ZvKYT4OZM/mvn4FTD+P5e/uPJ/wANzZE4n5xeE+7Q/wDushZSeuxaADTV5H6401a6ADTUNWgQ+e9SElKu6poAAAamo10NdGug00Q9e3yLkCHnOnz/AJHy+r0ui2cfDwcXF1+n0un8z43U6nV6vW6/U4ePr6cfDu007HP3/t/f/b/d/FWbsiwAAAAAAAAAAAAAAAA//8QAFwEBAQEBAAAAAAAAAAAAAAAAAAECBf/aAAgBAhAAAADn6lAQAok1kAAAqayqyAAFTWaioAAqWWCwABUs1kWAAKllsWQABUstayyAAmpYAAALLAAABZYALAAsAtS5NEIWWAtMqsELNZAALAmprIahUlsJrNTWQqWCiCpqLAKAIQAAAD//xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQT/2gAIAQMQAAAA0SpZUoAgqUAAAlSgAAAlAAAAAlAAAlAAAAligAAJUKAAAAAAAAAABKAAAAAAJQEoAAAAAAAAAJQAJQAAASpQEUhQAAAA/8QAOBAAAQMDAgMFBwQCAAcAAAAABgQFBwABAwIIGCA3ERUWFzgQEhMwMUBBFCEyUCg2IiQlJjRRYP/aAAgBAQABCAL2Z1KdNp99Td6ZtP8ALUSDuj+dy0U0/wArmYfb6+NQ2vG4ZXjcMrxwF142DK8bBteNg2vGobXjYNrxqHV40D68Zh9eMRGvGIlevFwnXiwVrxUL14oGa8TDd6sRj1/p4hH/AMd/sNd+sdd+Mld9M1d8s9d8s9d8NFd8NFd7tNd7tNd7NVd6tdd6Nld5ttd5Ntd5N1d4t9d4N9fr0Fd4t/LOI+iMZoEBN5vtNjC/017SI11fxvtBj/t/bhAA64QASuEAFrhABa4QAWuEAErhBBa4QAWuEAFrhABK4QAOuEEErhAA64QAKuEABrhAAK4QY/rTtCjy314RY57a4R42rhJjSuEqM64S4yrhMjKuEyMa4TYwrhNjCuE6L64T4trhOiyuE+K64ToprhOieuEyJfzwlRF+eEqIa4S4frhMh6uE2Hq4TodrhOh2pV29RiDg6omZogU5lkWD6lT7ZH9RYH/W7jek6y1Qr0kHeSR/UWB/1u43pSrqE+kg7ySP6jQT5D4Xiozo+IQ5J6iPHq7LN0yRY65bJ0eLNiz47ZsH9DuN6UqqhPpIO8kj+o4E5jg/Go9aLu5HodZxm+3xGBi2vx4g1XVP+KF4mw6Pc0ucAxG56L6bqYALwfJ3lDYZPefC8WC5atft/e33+43pSqqE+kg7ySRf/JAFtynRqzR+NZyV7j2L3Y6efNSXLWta3ZbkPI+HJEZ7tL/GhaQxYWWh+Rfv9xvShXUJ9JB3kkj1JA3Ll0ec825EmfnmyPMZ+HZNKWCz3KfAeFSv++3G9KFdQn0kHeSSPUoD8hk/aBcTciLXtvH9TNFiNwU/IjzR4G3Dv4Xh++3G9KFdQp0kHeSR/UoEcm41VrSQy968YOlxIQxpR4fkHP8AyO6QUUYfvtxvSdZUKdJB3kkb1IhfJPTdd0iB+wWil2s9xqxudvkPXY/7r2tPj++3GdJ1lQp0kHeSRfUiGci5FgckOZuVbbnDOxYXiJXfnWrUrajyuC7bymVFhMQy64/fbjOk62oV6SDvJIvqRDeTVq06NN9euWSUaaTJBLUctczxe6IsKu1pSjW/0tJ8cX+lpLju/wBLSPH1/wBrWkUBv9PMIDqc5NSlmtPGIXHicRahrAOB/wB9uN6TLahXpKO8kiepIP5Cv/V3LthKHo1KYwan1/keFNMevHi5nAw7bdIiO2Zg8gIdryBh2vIOHqUQbCyPBqVKzJNGpO52BoUC9twIzMehOWww0tzBMxwxs3324zpKuqFeko7ySJf/ACTEOQq/1hxrbl0ZZfYa7egsnW9+MtmvdCFduJt82dwCa3uK7m251/v8Bp0QOfHGfSql8VDRkKbu7Bmox6+SB9/uJ0+9Ey/thbpKO8ki3/yTEeQlw5VA44J8EUTKiBABuFXW+5RiriWZK4mWar7nGjTf9uJ9priiaK4pGeuKRnqDF6kjk0vM/v8AcP0mcKhbpKO8kjX/AMlBHl7b126q7b123rtvXbf+j3B9J3GoX6SjvJJHqUEv63cB0ncqhfpMO8klepUT/rZ+t2xO51DHSYd5JM9Son/Wz70ndKhnpOO8km+pYU/rZ96TOtQ10nHeST/23LivzMT21KWvI8omh0SvjSmekFJlKZZhspScj653ZGVW8WbzFgXiOE3uAGBWfOeYjxcjy8Ng+153p5Yn1pJmjA+sVFBmLhabGrJ8GfCqw6FKb5s+dJnWob6TjvJJ/wC25oW+XJrm9s4UuXsUSYEyIcuBZB1gZ4pTtSsoPHzCNhTq+5w3JgjSE0K12wyU2eKkQw4LcmfEjy5UsZlmY4A2wpU0cn4kEIf+444jB6e2JtbJQ06dOjTbRo5JBFNRuILBrHARk5s7pnhoqrdUp1+I2NNp23v+q8Z68Ts/T/FzF26NBNumfVWjVjFIjbphMTFGbEJfLWQQkhrDF3yZ86TO1Q50oHOST7/5OjGn5a7Uo0IsupJkKpoObqhxgEhwjZk2kLeZ1SvTiytbWglGSSR/FtQYk0g8qEvd2AtdZoHkS5Q0pYPLSFuQKRzMES8Kna7u1uKIcADF6uQvqOGYhFs2l8ukWJXBLjXoeUeIG4lnB0k93eNyTs9OGtji2QsEpPpO3YJBIBUhHFGNtLlefCvS49TLGxZFgkvxqiphfGslZ078y7psX6JYNEeksmUADsl0rrn3XJVd9WkXiWY8kjr1rM5c099JXeod6UDnJKF7cTwzb5hUWhsVEt8beKSA5XVKHNbrz2wprqcyhiLZIdtUvZI2MJDJDpS25pWM3Aea8A8Mt2kwj1IcgGrCNOiSEhM2ajuXFxkWsYzG4IFx4eq1eopTJkyJPoRo+SRiC4qCOz/oiOLV8iLu7Ljw2xCbZpaR+cTVuJZFbVIUF7dtStXcmllMmTok+lIj3MrlTi4sUfNQ2PNwmxJh1p3ImVnw1sPpIz29jLM3YXY0kIzZYtFdbni22CK5M1rJCeuae+kjxUPdKRzklD1QDfzL6NF7+9f2HAhjOmO48ryx8Wxsuu6xA26865AmXuSUD941IH92SJEyBJjQopCb0djMMaG4wi4aMVuh6yjQaZML1oVL+SdBMuNRHEwiQOIoAcYSjbfITE7E4U5MDECbaX9G/JHcu9hre7hunYUWq3/umqHStXNOvK/LFeFElyrlTW/scuyLqKZLXzpErVi93FHE0D0mu61qZeWfOkbzUQdKhzklD1QDf2nZb6/Nd9WnHu0Q3y2+ns16NGXRfHkW7cIqV5759Dbt+iluv72tua2xnTWRNPLPvSJ6qIelQ5ySl6oBv7O97W/e7q/MrHdPpefYYGTCCs/fhFo16cmi2TT7FGfClwa1SkYmWNy5fZrZvZly48OPVmzNDu2v7ZheGcohvETSegkDK2EbG9LFaBq5ScibxIeWEjpFp/lkcb1P2anUpJdW5xCwJan/APaHny9RF0rHOSUfU+OfLIjQSEfhWKGIjHydJ+vHdWrTo03168ObCp0fETg8iOZscv7YjIXLUzMC130Qm7kBBGbY+E9bk82ZQ1Do1W5HFpxoxL3dX8r0KubiQ7hiS2fcpf8A6Aw6aMCbAHsCgiU8TUf/AJ4mY/v/ABw5catNozWL4+Fjdo7neYWInZ6F1DW/GEmNos5Yh1CJnDPIOJewrtaN+ghYks22/bVUCaNHg9bn0U7FTUyvTYwLX7Pm0TiO4dHs3H6uyKlOmoK0W0REwdl/pWT1X6fZuA6OvtRH0rHOSUvU+OfLIA4TK/hXJl7ePxVPTNjF1bwzT9KWQRyaBJsiOZxphj3bT/rD12yJr+GAvWuoH0+7EDB7NyGnVgwijvW5X/wBbXbV9b0NXxMm5ghbde5LDlyMTBqx3+te5pr3dNPT6zDjfrdX5dIpjINtTTEQMGIAMcxD7evSJ8m4tBpwq/hW3Eov0Us6kiQ+EHUoU5PhJsma+3nHrtEzcqyVI3VEDoty/pZyEMmv2bhEeRXEzlrx7f1+FbE7VhxX+lZr2x7r9Hv1P/R1+qJOlg5ySl6nxz5ZcrIUI0sViYvApWbvGQrmAxhdO5Z211AQCJMYo9ZDAjhK1mA7NgjW/NGF/Y1jGoChjEGCiEWwtiU4b5rclCoiGWEtbLsxG6MLI+Y8OF4lcmJxEXs+C2oWHSF8a5AzXta/19ptHwzIKXAkJccAhODHpw4BeLh8Rde9203AnZ7fEJiJCAK7C+V0LHkhc5YPh3OKrmRkdGUCTjqqH2hwYYyZmd2bnnvBxXt9KG9ArUYFap3Fmh7dW15Xnr2+DgkseRsDe3sjEkT0RuLeidkGZrcQOPmCOmzM1sFahgd1v+kq11PvR1+qJOlg5ySj6nx35+NgZcL1kI8X3s/dHX6ok6WDnJKOjt3Pjf8AWz7/AMUQvWiogv70VDl+STokfi4wbjUV8DbiK8DbiKuCbi/xcB3H/jwBuU/F4/3K/i8f7l/xePtzNeX25f8APl9uUry93J15e7k68vNydeXm5OvLvcnXl3uUry83LV5e7ma8vdzdXj/dB+PAG6avL7dLXl5ukq8d7o71eOd0V6vG+6G9eWu6CvLPc/V4y3P3ryx3PV5X7na8r9ztXi7c7evK3c5Xlbudryt3OV5WbnKtF2521eWG56rRnuftWmON0Wn6aY+3S2rRH25y/wDK0eblvy6xFPz+g1tL4ID+gTFm8Zx//S//xABaEAABAgMDAwsMDggFAgcAAAABAgMABBEFEiETMUEGFCAiUVJUYZPR0xAjMDJCcZGSlKGxshUzQFBTVWKBo6SztNLkQ2NygqLC1OEWNYPBw0TEJWBkc4Tw8f/aAAgBAQAJPwLqOJbHyiB6YnGOUTzxPyw/1Uc8WnK8sjni1ZTlkc8WtJ8ujni15Pl0c8WvJ8ujni15Pl0c8WtJ8ujni1pPl0c8WtJ8ujni1pPl0c8WtJ8ujni1pPlkc8WrJ8sjni1ZPlkc8WpKcsjni1JTlkc8WnKcsjni05Xlkc8WlK8qjni0ZblUc8WhLcqjnifl+VRzxPS/Ko54nZflU88TrHKp54nGOUTzxOMconnibY5RPPE2xyieeJtnlE88TbPKJ54mmeUTzxNM8onniaZ5RPPEyzyieeJlrx088TLXjp54mGvHTzxMNeOnniYa8dPPD7fjiH2/HETDXjp2NVSc4zMJUBnHdVTXMdqIXND52ujiYm08h0UT86P3ZboYtGd8SW6KLRnPEluii0ZzxJbootGc8SW6KLSnPEluii0ZzxJbootGc5OW6KLRnOTluii0ZzxJbootGc8SW6KLRnPEluii0ZzxJbootGd8SW6KLRnfEluii0J3xZboYtCd8WW6GLQnvFluhienT80v0MTc54GOiiZnPoOih+b+h6KHpv6Hoodm/oejh2a+h6OHJr6Lo4XNfRdHCprwtdHBmvC3+CDM+Fv8Ea58ZH4I1z4yPwQJnx0/hhMz44/DCJrlf7Q3Nct/aGprljDM1y5hiZ5cwxM8uYlpnl1RLTPLqhh0TLCmUoyjhWnrjiUYg9+FlxapBmqlYk7XYbya9VXvbwiT+8IjgLXo2G8mvVV728Jk/vCI4E3sN5M+qrsFpS0kP1ziUxbTS+NAUoeECLek8orMlblw/wAVIUFoOZSTUe8XCZP7wiOBN7D4OZ9VWyeuA1ybScXHCNCR6TmGmKambBczPfpHE8RG3XX5NwbilQqZtaZXitbrhQD3wil4ftlRjU7IHvsg+mLGalie6lipk/wERbz0uUGus5k0QriqBc8ZBUd9En7DWoMzp2rS6mgqKm7XQoFSDvq4e8PCZP7wiOBN7D4OY9VWxPW2sEoHbOLPaoHf3cwGJhOWdmKLlJBfaNN50XknQO5R+8vbUCdGxaxFck8mmUaJ0pPpScDph2/LL/y2bOahNEpqe4VmSDihW0zFHvBwmT+8IjgTew+Df9VWx65qf1IZx3L04T4DdI74pTMo9gR/4jI1elVZjUds3XcWPAaHOIVen5I62mScCpSQClf76CCePD3fwmT+8IjgLew+De9Cth/0Us4786Rh54201a6lzzy9Ki6dqT+7TsIuytqNGbaToz5Qedbg7yR7v4TJ/eERwFrYfBu+hew7pDaPmU4BAohuTZSKfsDsOeblyhfeQl4fze7+ESf3hEcBa2G8X6rmwxuS2V5IhX+0Z3JNqv7SRQ+fsJqLIksoeI3HLw+kR7v4RJ/eERwFr0bDeK9V3YCrb6FNqHEoUMGk1YU0st1zqZWa18O24godgWG2WEFxajoSkVMN3fZB4sS9c4TnV4EhtB40H3fwiT+8IjgLXo2G9Pqu7A0AxJMWrJTtoS9GZuVZfSVPN5tGjuVHRtVdzSLck2FOpvZF51KHUbqVJOII0xb9n8ujni3pDl0Rbkjy6OeLbkeXRzxbUly6OeLakuXRzxNsuNzi069m8oMihNahBXmp3TnELvdRNszbFnpDa1NLSs3ztipd3ulnbe7+ESf3hEcBa9Gw3v8AK9sOCveoYslqZm3kKvuKKqm6ogadwRZYt2wAavSLl4qZB3Cmqro7lWN3MRTFNlS+XABXLOEh1FeK9iPlJqDFgy/8XPFgy/8AFzxYMv5+eLElGm0CqlrqAO+SY1NsTs49gqeSDdbG+brhT9arajubxwiVbtaeVtnHF1uJ+Q2NCR4TnhlMvKSolEtNIzJFCr0k+7/h5P7y3HAWvRsN7/s9sOCu+oY3i/XPUK7EtOpWH5TapKjnJRunSpN1XHE1Kao5ZGbK+2kbm2KCPnWqNQJUrdS9h5qxqXl7Jr+kmFBY86x6DGqFb7Na60ljVPerRKB8zd75USiJVs4qpitZ3y1HFR4z1P8A0fq+7/hpT7wiOAtejYb0eh/YC8tcs6lIGklBiw7XcmJVKgstSpu4qrppGp+2/JY1O235N/eNTdt+Tf3jUzbnk4541MW55On8UamLc5BP4o1M23yCfxRqZtvkE/iiSmZOWtJMqpsTLZQapBBTuE4aK+7/AIWV+3RHAGvRsN6n0P7EwYMGD7yb+W+3RHAGvRsN6j/n97d9L/bIjgDPo2G9b/5/e3dY+2RHAGfRsN61/wA/vb+p+2RHAGfV2G9Z9L/vb+p+1RHxez6uw3rHpf7I8mYlmw5VbRvDrVQsYaQQR34vZCbaS83eF03VioqDm6jiXW1ZlINQfnGxZXM61aU7km6Xl3RWgrph8M2e7LiZyjmASgiu270SqZLU0UlMnlUnXMyfhvkN7g07F0MSssm+4tWYCHhMSkym824nSOpOIlEPKuIvaTpzbgxJ0QoLbcAUlScQQcxHZv1X2qY+L2PV2G9l/TMdjyQcQ0ordeNEtN3Tecp3RAzCHLT17rEJUmcYUlhsXKdaWEhFNtu3jE/NTsy7SQ1zfXrRmo2qcnW4hOAQlRFa6cYO1lpV1eGet3ACGiE2XZoffbb7aoTfUBWgqTDDkp7KSyZiSecpceJFVN8S07mmAFOJQopBzVAwhKUvTbIU4EdqFjBVK1wr1Jjrj6SGpZvbvvaKIbGJz580Phqx7OWdY2SpSQt3bVQqaumij8jw7kCgGAA2L2t1zABQ5oC0G8mvyajHihvJTVn39b/u0K2691goKQrSk44jqKICZWYX85cbEOBtiz5pxlpxxVBk8F0BOhF67xUi0NfuDC7JpL2O4VjaD5zFntyCKe3TZyix+4khA8eJ6dRZsuoqJfVk0vgpIuIYF0FNTW8U94nRIjWVoJRWbK8QpxRQLqaYgKuhWPdDsW419qmPi9j1dhvJX0zHY2g+6Em42o3QpWgV0ViRlLKRtmnZ4rdWlo5iEVSi8rjApFi2cuxlhV91l5SypRxJdadRtio5zeMWc/aMkuebcnm5ZIUstM7cJoadsoCNTE9IOW6RIsrmy2nFecBKSo5tOYDEw7Y8pKWc+y82y2wqZcTkaZnFkUURpAizbVnpplxTSmmJNzEg0wUQE0O7WkWOZaybKmpxU3NvuhJlrxLyWskKlSgFY6OOEzEs8pvLsiZbuZdn4Rs6R5xEs6qbUlKCtuYdaqEdrghQGEWayhxhQdD8y4pZCk4hV5xRxEOJeZeSFocQbyVJOYgjODsphuQsmwrwyqjdCqXpdoHdKzlDu9rFiuTro/SOpUo45jkUYgf+4pENBFoziCiUZ2iKIUsClEFQTVVM6lRZ70vXbIafKSDulIClp+ekWOploChdRl5xSjpo8U3Uj5KR88WPOTs+nbX1ltaGuNEvUHDdKSqHctKzSAttWbDvHN3oNFS7zifFKH/+KJzKTQAKpeXSXXE1Fdtd7X96kWBMTlNKnEnzMh0+aLP9jpyUQl26FFQKFEpxvJQoKBGIps9639omPi9j1NhvJT1pjsllren55lTq1Ic0qXgFXjmUamqRhSE2nbU9NAXZOTlVNybCQczbrwbSo47ZZXjoAgFN1N5QzkUFdGeJ46m2rJ/ygTbYIDI9udfSrFIdGGggRPylrWLItkPzcvLlpsvnM22q8b5HdUwEG9bttr1tIo3u/dPE2nGJb2VZyOUmp5Dlwsh1jB4pcNVDA3tteqOOGFey2pppucQgDbrYV7c3u7ZBrSLcyMjaJZDzks31xp1RqApxWHag7SmjHPDloWvatnPqbmJW13MWlDMoMI63dUMQQIQlpppIShCRRKQMwA2Pby0s4UDdWRRI8MOLYsmRKVTLqdK7t1KUaMoU913Ke/EsiUl0aE6eNRzk7pMPa4es4a3Q4gC6qYU8koDZOCqKFK9rX54mFWjPPG8uXvlSK/rV4Ff7Ao2M1IQlppAolCBRIHEIAS7Pu5RSroJqVpab0ZgVFf7sJusSiLia4k7pJ3ScYqpmxU3DdxvTDgBVTjCaJHfMS6bQtJ3rqm3dsy0VY0Ccyl7q1Y13IabDyutyjCAE5R3Rm7kZ1HQIqqZts1bJwKmqlZcpoyi1Ej5NNnvW/tEx8XS/qDYbyT9aZ7IBXqzj8pLuqGXyFAXW9LSiQdqeLGLkxIu4zNkTThCSaduw4a3V7oOBiV1rMqbClNKKVqaUobZN4YeCMk/I21Ky8tkKVqG79+/oxvQgNMspCEITmSkYACJdLZXabk0vJooKNMLqpVBxiC9IWm2m6iek15J8DcJHbDiVWNVEzacgEKSZaYZaqVHtTlEAHDYpaWVTKFvpdVdqlGKceJdCeKMQynri9LjisVrPGTD4lpuaZKG1qqB3iRiAcxIiZl2peTdQ8JeWJcKy2byBeIQEpqBo4urillDGH+nMr/2HUlXFWe3aDk8uZ/RuIvFxoA7t66KfJMG620krWeJOJi0pazrHlxVmVmXQ2VN50sgHQe2eVpNE4iLXZmbowbkwXzTvNgxLTDWs0hd925RQJp3JN08Ssdl8Gj7RMfF0v6g2G9k/WmPeHC80yE9/IP8AVF5KhQg6REq/L3u4ZmXEIHeTWgHEIs4zfFNPOPJ8VRpEu3LMpzIaSEDwDZfBJ9dMfF0v6g2G9k/WmPck01K67dDDOUVdvuKzJTx9VxTbN9LYuJK1KUrMAkYmMyhXw9VQQ22kqUo5gBiTFpJ1yv2tt5KmVODdRfpeHe6pCUIFSTmAEPB+WmE3m3E5lCJy41LBrKS9zFamCot0XXDFWOGiJpuYekF5OYSg1yajoOyNGJNsuKpnNNA4zmiRMgpD62bl/KJNzSlWFdw4ZwepOOpkEoS2tgK62QWHHFVTm7a5jn6nwI9cR8Wy32Y2G9kvWmOx2lLyGXrk8usJvXc9O9E6zPM1pfZWFivzQaAZyYWlxO6k1Hmhhv2GshSZduYFb65ge2DcoP8A7nwFVSrDjoHGlNYmteTk2lbinLoTgVG6MMMB1FqSxatsS7D900JRWucbhxjuLflUjwHqTDiZexJRmWaYCjkzldsVFOavHGm2pb0xLPzaJelWpZF9w1NMB6YlrS8lVEtaR/8AiqgbR1IVRQpgoaQYlUUT7S4gXXGVDMptQzUh3XM7Yk49Zzr/AMLkTtVd+7SvHEpMWtaz6b6ZOUFVBG+Wo7VA78SbslOSwyc5IzQF8JXhXDBSVboiZNoalJuZbltavmr8mp5V1OSX3SKntT1AOu2rPmu7149S/l7WWttigqKtpvmp0YQtQQ5Zs7eTXA0UjR1e6mpMfTojupUKPfUSSepu/wDbdT4D+YR8Wy32Y2G5JetMdjs2Xn8hXJ5dsLu3s9K7sBuQkLUk39fspN1ptKAVJcOhIqMPnpni1V/4elWMo0wxVGulo9svH5xSujFO7Dr7MtbGW13KKcLiLiUmisePH5sNNe39mZq936xoknvVjgo9PU7SUtyXUs7iTGb/ABBLHzK6mBtez2JpHHk9qYSVBNtStaCuc06gEARNNyksjtnHVXR54kHG2V7VdsTqC2y2NJaQds4qmbRClu3SVuvOdu66s1WtXGTHWT7FOTLpb2pdUlQbRlKduAFGgMe2GxHddU3uVGSr56Qm9YjL7oUT7W3OKAyC3OLPQ7sdyhSvNGeaXMTHKvKV1OFzX3cxmmJWfYH7VEq9A6v/AEymJg/stOpUrzCDUyYXKr/aaWU9TC+aDyU83U4P/MI+LZb7MbDckvWmOxyyZy0UNnINLzKV4R4Kiu7Dy0F41WwFDLOUzAlBKWkDQlBJ4waxO/4bnrKbUyythoKRk1aCnDw178Wi7bdtuoyZmXRdCE6QhOiv/wCRUFu0Net10pfFcO9hCihE4ytlSk5wFilYeL6ZFoNhxQoVU4hDb79h2hKIyTl/rLK2tF2uCia5h/aWRNyylJWW15qpNREo1NJlnEvNBxIVccR2qk7hESuu3G5hvLJDZdIZJ2xCU482eGHET0qz1kkqQQl0ZnEaaVzHNsW1rEssrbLbimykkUOKeKJq1EITmCZ54AeeJmfdcuFF2YmnHUUV8lRpFo+xlrSKFshS28q060uhKHE4HOMCDE0LYt+0E7ZdMk1dbrk2WxjdTXTGoluXbnGsm6ubnEXEk6U3Lytqcxh/Xk5LSWQLvwiwilcYZVLzMvLhLja86VVMSr7GsXEt5R1NEO3khV5o90BWh44YQ47LKKmVqSCpskXSUnQSMISTMWU6p2XUk0oVJumu6KRJeyE4wkFDOONSATROJujGgxMSXsfOPpJcYNcMaA0OIvDGhxGmGw7LzCFNuIVmUlQoRGVKH3cstTyr6iaBI8CQB1JJk2khGTEzd64E7lepwf8AmEfFst9mNhuSXrTHZ5VtM882Glv025QMwr7u4P8AzCPi2W+zGw0pk/MqY97e6bSnwrTHxdL+oNhaTVnzkg3cCnWy5ikm6oY07o56xq0l/I0xq1l/I080atmPJE80auGPJEfhjVyz5I3+CNXDPkrf4I1bseTI/BGrZjydHRxq1Z5FHRxqza5NPRRqyb8VPQxqxb8CehjVg3/D0Ear0eboI1Xo8I6CNVqPGHQRqsR44/p41VI5Qf08aqEcsP6aNUzfLj+mjVG15T+VjVE35V+VjVE35V+VjVCjyv8ALRqhT5X+WjVCnyz8tGqAeWfl41QDy38vGqAeW/l41QfXvy8aoPrx/p41QfXj/Txqg+vHoI1QfXz0EaoPr56CNUH189BGqD6+egjVB9ePQRqg+vfl41QDy38vGqFPlf5aNUTflX5WNVCB/rA/9tGqxHjj+njVOzMyrtL7a8UmhqK3WknPxiHMsJCXQxfOF64KV/8AM3//xAArEAEAAgIBAgUEAgMBAQAAAAABABEhMUEgURBhcZHwMFCBobHBQNHx4WD/2gAIAQEAAT8h8AyPgTf2Jlges37hINY/WHSvw8NPfivWLG147dg7teA3Yuug7fv/ADSlxteMJIS7UYAshNs4BsL8BSs1FCa+h7N2DbtXolbBW68ZbNl2vGgRANr5vnPkv9zLXwPWWOTowxTxhzoIqS1rEL9pT+VP0BW/mHW8ush4frjOvXq075cvXp3+jBnu5PHPBIX8r4gGyp2jPAAYA/sh/wBqP/Zj/wBGZzJ+fGYM+9GnJePvnjhu8r/SH8TZsez+IDcr8u0+Q/1AClfj26LUks2iKy7Tpw685dIsigBauVx0yjX2z8sXVyajX21R8326MI8a6vInrdJX0Fv9T4D71GM7JQjvat0zd9Ab0Sz7H4+b7PQ8EI104oIVB1tsutpR5QEvCnnW3zXocs9mzEhoIj7LXqBysCGDlv3szAlD9t4Hk4ly4Kkd6tXrrFMsV9UAmUG58IrFJgBLHIn2Fx8326PQEE10KNpFDuZxa2thAFircZMnBCsSgW4rRgjoFAcHTfYOmoVWBw6uHgJLIdBLqi63Ug5Zbn2AR8326EUkU14+kAlfDO6o8FB7nQPWe5PbAXQyAq+y4Iouq2wTKKQI0nY+wERXycdCj5rx0Nh+aUfpETsW/lAp9BdZ7Q9sflGiHFvoQ19gI/AdujejGvFqkWa7r/TANFUUAaPo3bJRDsAfy/BDX+eL+A7dPU14mWpCEE2xRVboJ/gfRHBL+zYHDk9u8NfZJYEA143QvLl36GJlEvNbtbevL5+gxwlKLgX0JZK0HsnpUGfZJrkUpNeJ9jqFAG1ZavQxeLTbQ4XJsuCNtLxMm4MMRpDIhSPl3mEXArbQYNfgFAFxwwRZtI5MluaQasAj5oCr3f2Unpaa8QJaQOZ0ghFQMAQIzXLf5Dwos1SBF+ZZ5cdtOEz/AKniEXOYMgOc0BBJRSN3ZajN0cCRyN1QVOX6py5QDzUUykflZ7/ZJCm57ZmuppXdmHMAxqBtlIP0Pa0NEwTFvvN8QB5Tpez+2PSWhR7k9fxQkYs5xZad50eMZYuVpwdZZ/KMZ+//AC/55C4N7dLps5xrxZjvhAAPNiEdibtUbsXTjcAWN+X+534zpfZRVEnclTz4YKITFmJAtnhnRylTJuKTP+eFo6bCwHb9/See955z3nnveeenmp5jLe/ja7fsgitYu38f3KSZ0/tv9It7dMbpfO/ts35b0x54x+3SV8L2dC+o5dLJnJAclQ7Kl0xkWgbgqcjkmtzS6HKzWMDnpUOerCmC1cxg3py6GWnRO8rCVUtmtgmbhTnpVrnXPnGXyDczBcQGjTSI4RyO/C0c0upF0AtdgDLEo5NTrQYRPGlLNfT/AFZxXxMehKOPp8IyqkdKmdEpamZhwrSgylVcXozkZZ0LynNnPIBsG0JmNIWsLGLVAhM84FZiLJyhczx7sUx04KZeibHJ2moa4uAu0dGkykUYFa7vgvwGzYTZOJhS8srxcGFr1AVRx2QbQ4BQBoDgOlztbViavKAMFc87oNQAA2/UFlzRouWqE/ioSVMV4FjcgcKcTcNqeBwNvowJFtVNy/nBXpHTI4NMmgEOqMm4yrCCBALLPIS7QykafpORXysei9Wj9n09BuQoRlYgWLRqVUQdIyLeMpst6usipGnqQMly+WIL/SPqKEVxRLOiwVDu37RlJiHsiuhURYCaN8xwaods/JmzDN1Cw016kAEYoc0tRlfEzMraO+X3CZ3v6o5bA3UWPgY3mYF3Ax+bC3bgGROn1xBPstcXNrEuxULhEOovnzQvl1geHSudYHvubMkt1pqjuLhzSbN8xQfjidYGFKa474RIbgrVzr/DOaKMQXQBjZ8NCjSixxAfsC9iX3p+Zr64gkrYuO1DoB0BPyLjSDI+E2yhqnmHXHFfDw6Ek2Wfn6bpuOqTYBYI1ZUOxkgSmcHY9JmL2EIaOQqWALWOxviNvWuBs7gDJBN8OS6F7yrAxtlwrhOVxs517xdESZQL0Gn08RWUGkW/2AYx05IDKhCd2Kzm6G6EPPUW2jhYhAb1hTu4ZkCRKgMAGjpynNZr9pmS+usKQIHq6y2MmBunXStrcraFXLHPDpmiQaJbavFKG4Kxa61nOG5lC4U9RArgMBB0yCBcRkqpZeLi41wSwo2pltJ7sdxcGSibnCu0oQfiw3acLjLtVMS8i10QwwxwzCsbwEe2OFw+632jdMAVfUwBrDSgpLaq8eDwKg6mjELctcN1EGwxH1qk1HcDK5+ECNuq0qpmYGVqnFLkGhXEPbFlE0XAGJVWOvNkIuyzu5ZANnicEfYExxFlIwmxcU3fTTotjEudgl2hrMLzJf2ELWLFXqy7vScBYNkERMGEkoMQahShY5befBSb+PQiP5PxHSL1i9CNVGytuWqUWYS/I4nhKexAGpWSp0L0byEwXSgVFYAqA12JcvdzC5j7jFSOMPV7BOk9ZeV/iaoiMn1XpMkd1P8Ac0eBn0ALEKROyQfer9FF0XFAT2SdLz/6wzeADQ8kOjz8Nvt0teX+GKDZR5xOIELu22+DwzVxJRIqXgqm1rQXNToFlYFmHxXy5tD2HsBc9RbEACbwWNr8U6oeoC1XsEzxuRwbLphoXt5dYjWpzLgbYPsNiCs479NOOpgw/wCAx3loebG7QUMFZygvMKIWUsdLbCwXaUI1VhBYaj8immvr4oHmG8q4sbvIv1lJ1tEOx4PrD7Z6AD1XBDChgF71iXB8lZGz2BWAG3CDlshpUL/Mvr0i9ck4V14AoPLYsqhGkpyEKjtDloHf4J+6zEGkCZdMLel67Rz4ipa4xgv7pgu0tBlhXhPaOgp22xu9EtMitJpyMwxEp+KRXxDHE/CjQkrbaW3leblZhAXsDgmsLL4lTelw6MqFYJMKqARVbJ5MgTAvhlVpVJnHFefBvRv3b6MYlfQlV1FdLPHzHj3v6i0afMzA813Nkzv+bw1P0/V0Z3P0lUulNGlWMFC+9ExaEG+CtjawPIrdJTkMBcrBehmsRlYyylkqKKLkcwJj/wBUcG55xP8AeVfunumU7lH/ACtch9qjvTLXFbJl6zO+j64f4H2jNZG1MDXdweeJsruz/iE/5hNAbWFdF7LwGWZL+gzp5kL1lLfhYWwV3X4MQzUXmr48tOK6dhBqrPcI+re7i6jaKcbQEeGOgUHKj2hsK2vx0O/w14MomhuVP4P3H8Q14AhfoNS96BH77BVfqZ9JsiPqbeVQD8L2hqC/SdL/AOJE5+k2ohwapd21vgKpdwOS/wDdJ8PDuMqNDKi55SsdxoypnAytZt0G1oxQWBiK4Fo82VvUlSXgLSheLL5gDuId40HpH6k1UQu2yVtmG3MXKyAtecI4fcw4hmijmBa9EkexsuVJCdF5ytgikJeUoZYutpYNRGs5zroWjZ5uwhdqswym0bHYCpDBD3R43rYw8Q6YaS+yMAIH8VVGPgQJFz2clcsxbRh9x0clAmGKCJddr5kuXFrfeVeUuMwGljO+ei9S7QxgnEWt5JOiLZUnDUTLJG7GDYtR+pF2pSY37XaKMxqFaBi6KGATAaygGtuuzI7Ixg1fKRqjATlq223wvwhx8q3rKen0LP8AUd/WKQTzf2vYdQpk+nR1ek9epVbArXo9DdzDZLJiWSyWSyWSyWSyWTExMTExMTEsmOvMplMplMplMplMplMpmfGyYhP/AA+09Fv2Low5WAGSgsBoRmfDP6j23xC/s74xJJafCkOJHoEut9hl/wDF4XhVf9EL5ysWx27hJmqxGdpsiKDYeJVv9WVf9aVM/oxtvbSPUcamA01P/wCslC33s+S90XxKYm06VxBxR0UULh7o1X5rS1f5N51J+oZpPnjsnCX5YyPZfBqi9Acaop0SK1HBxfb/AOm//8QAKxABAAICAAQFAwUBAQAAAAAAAQARITEgQVFhEHGBkbEwofBAUMHR8eFg/9oACAEBAAE/EPBaY2dO6EC9iEUPsZHGx6KX0o+jhJGjdlGO8cCVBYuf4OPbRQDOIBHcwTMINIQbOyCtDSZqlEtyG6tdIFKV5T47gki3LObBnvnnUhyflUqNg6EvO1RhLTeY0aY9vD7xNQYmpMfXjsYUE1GGo8AylQC4J7mwxsHygFaJATJCIUt8OzTGYtBuZACCORMnBea490qdsCVl8mwUQMEjXJwPcjY4rVMZ1m/bc5HebT0fe+A2bJuhLB78ZMmxzvb4qijnxNm/avCV6MoU2l7B9otWz0viRYUKpG++FhDrgE9y0BtPSYc6uKvX/FANr+PKa4k6pID4a+PGb7hFJ70/Eg39B+BC7KOlPxaW7gVN2T7UPb4SHpH0PUvgy+AdGUugBCbrEHtvz6THUGuCE3JVgiluY1RMhFtE3phZoZKq8+C0W1+X7Ysr/tP8Rqr/AILgpRudr8v2x0XUZq/ysuBnkP3nr8uIFQLXQQQ6tF5dLe9iK5e6R96KresLBBhHluPUcoHAAEbpWh5P7Gdtm4IW7oo9Y6/LhDCECqG+AFMFfkp9UnylEiUCpOHoqyC/Bazm9IUNiGdOj1TJPVhUGw2OlM2pQUhY1DTiCa2xLHSgV8Q7u7sFajrcl1QOQBAREsRMImRMJ+w3aYvyXADzaff+qa/LgJOI8wlkDIYCMYqyidVNeC3qMVAGYMIAAoAMAGgwcIKXVm4jRJoE14kMBtqtvF6mVkIpGkpMI/rzl6LPL8rLgvFku8mGvy8aVoWuA7w9zEoaWi0EcAy5A4zMx1R69FDw4z2wi+8F4DAmKvVlfr9zAer7vgGk2W+s9fl45pzI2CXVaAlcCBU0Uc8o6tUM/QEg7VnpKw0I4Nyqb6sIKFfr135Lr4L0uRPrPX5ePVwPQVezkhh5iUsAYD6LOpjQK0Gxbr59LGvy/XKo5j+NnwYOaqhr8vEB5sWtr7CfSJiD9S5XmpH6DjM1BSbRZjGh7LSUGBAPI/X3Pw3VwYrvD7x1+Xiak5lgqTzIIgu0zIuW0LgSbLxkAFc7PMANKfRxQpouyQIZjy/Xb0fEfwtwWWcq/W34Jr8vEhFQB1oYABVcBEd4oaD3aWFcZA38icjA9QQMJep2TwNFil0IUbN2kv5uhAlbqvHgIALZXKBYMm9RiyLCLJVDqhkgW39eM3R50/N24LZXA69Ya/LxDYUSOkmV3YpVsYiNGiKhpCuBl2IPKWSq+tONYiiRCMW5Asao8FfdjXOCjRFq0KAZyxINKKSIGGyIAvy2rgisUz5lsrbRZ4Mh9Btu4S2s1j9e4YKE/FcFXJFfrf8AxNflwd7MMS5SJzGzJbUNW6axM4KQ1XM5uaQtDLPC6PagHrhwbcto0KtumnPGFWorTRAAAc1Uqya9/PgQkhQWZ7TR/YATQJT11eel8N4Aqgr9Y6PLxPHCVlLG0QDrG7DEmdopuIKNKUxErOVV5mksD08ngIvXEsCZrqXn9o3RqLtwQhpGBCkvOLWXuIgnmhtZdGIS+FT9eEXwrXQu9OvDSVyj8Z9IaPHWSf7if7Cf7if6jF/7Gf607r89JnrM9ftEQIhq39ekUakgKOBE3zK9/wCiGj9spnkhAeCJeg+9/wAQ0fthW/7IzW/CvAxrZPvf0ftvnA+0vznRwVZVlDkPy5/bQtHSYhXwMqTo+5/T21BrmSZeUgJ8iLJGbVTWuUUSlZhzFBeAdYJzlBxEsaAjThE4cdGXid4ZFVgmRz4tWFSr3EUFyv0h8qigIDaFw3wWCRyw9oCioAVIArB0jEsyhMeRwCATw6Tv/wASQzSqqALDKsRAkJSCI0niKEo2hj3+ngpym1E63vwDgyiPNB+Y4a+krvkxojrFKFEAsqYh39okhKGpvTR2enpXuN44KAHfbgTohXxQVMxxeirJqCJkHahmP3QaoVl6qOToC3TKfNuSsAazUuPdOzBqdzGGi2OQsO3lyoQkKSRFPMUk5bA+b5AoCFEA/QFACgMBjhvNtlUd0SQIqaRzB3QhZh5YFJUhEDeY+pgBBQhiwgaul6wRMo6PCAPmgEAEevajkA2hPrHQ0mvFGhyiVVVY7dUp10vXHcBYGYIbNT288j4IIQKGJGnzPpB6h3ffg1U5Qxz5r0I7fpPGPg4a6oRQbphLDeF7fv7xi4iamF31L7Dqb0JtjdSoU3tXxRBpRK0e+LCcUaKSgolyoaG1ZxaFlAtMzNBuAwm4oKncqcmL6NcuoVPBI5OOSCvDKVZFEiGZmgQTJ6ygHN3cLG8TalCiLVEGEZCRScFAQRGzhacIHNdBzfSFqshS8Fw12LUA4bD0CxPYInSqati3sotVe/TA0hpQgFSVDniAlTIxFRkukBqgCg7Bh9NF3RuSFiakQhojVfFpl4nhKBJ1gfbhRTaETG7yJgBdMdXx2AKkecu6AAOmWY2XrunZfrfvwFrZTWLvjFbXkvtJgPX9+BvE8saHwx2/SFAbGz0mdlwO07iqIRmDYiapArhepikSoKg2cGwhC2xVrii2KeG13BQzrq7JS5WUq7Rs1BNEo2ZgpC0BeMGhKu4Yt7iGYeEmYgApkorwKcVgaJMrdYM+7FIBVphn8uPC7Koq1uxsFvBgweDgAoOEAhki1jQWyihb0S+se1SDYzCb8ih/Y8PqSz22BS1ZRP8AiJrt7EAExZFAC4YGjfIoRASBc3fyoLAHIJXsomLsqJg5gQIi/FiqipSbUhIrlRZY7di5HSKaWajrPauUrOhyzvd3a7ymWEgtCOcc5GsXIe1Vhxxksf6RYENK4Cv50veTt+niRL5CCinpF7VTlePaGNQzrzbUI6nMxWQXebi96k6V2xGwIKReYkyhfLXtIplo1CotEk27WHMJ9pycTgcB0IRFXqYAjljtAJVWkKTeWRkK6pFIGBE0AjuYrBZKb4LbKRsqBHXebQQmFnQ3XADpgAoAAA3cEfWgw5YOgpB85C7krSuKWCU3JX1z4KYzSGTDu+eLyg5NSL3ths2fJk5PV8DYScCJ9vEtzpKOsf1GmgJhgUtrVyK2C7EoVVWawCkQHHFEsd9XLxogcJt/6IXhyMs8l9+O366CUwKweIEGylCy8NOy+db46vfC6YGNQsBowuLaAc3BPsDwCJbxSWYUIjsZcuz6Kg6AADABCqoRzKrHJTrvzuD80+ZQGAGscFNYNdeXv4euB8hIAq4PoQxOdv6ARyeCERbUBnu4iiDlVzKmLg245xEUdkrQa68phhOhwp4gQbWhHHVnRILAEaSxBNPjb2F4LyEsnoRuZbVsNnxFaBTTWTD4A5D0iPsAFXoQdHs6iivRYmQg2TUWwZcUiFguu1M9mYDSIiaFUicVUKOXXd5KeYRTuIDyA0IcDJiWhYUZTy4FW6A4xCqwxxuY9o0I6nunBV7cV2/SHtQIlCyQjQUIHZFbwCrbdLi0CHj6hP1QB3WLGGyxdF1nrD+ncBG46VCGRpqVIai9lC+0QtYKiFfYKhYHgEV+lKCrYoI7lGWU1ESwrKuZdpbFSdPmYcL2V8saWuQIWhAM0Fe9JLr11msKxWlBqAXGlRGVePRrpAiFihNpyLot5F5cS9NYtMJl4A1jYk0ysiKjD6lAi0Uyp+OFCp4IwhNBQAIvB34pqyG1WjTFsLszeLdxjk0y3qTL0JpgsHsVtQCWBt1phgg0gAcF0Ci1o14Wl3fcwNArZ3b2FibUQbqSj5Cl+Kcg8lfzIDwmTbIOarTlcs+wYuaUA8v+00eUJbzFPMohQ3g4uGC7eb9InV5MRBOLxpImCVy1ZtA8IylyQc15LsnCJVsgekqQ3hEd1GYq7BNBCueQdszzVU9Ye7eGqdUFhp01j3h1beMFG0XSi3K/bClV8hqJ6ZMzJ9fmZRpZDYqTq+T0VaZT8PRVtq1aWbQLUFJrYPvPxr+JVk/K7SuPtjxVgWsWkaC4idxj2BUisE1VqH+VyfI7tZC6oGCPB1U1pjJtnBUBRtgNMUmK5+fRDDpFcEGMFKWGWti6WAjdlyPeruWQIjnSPUhp514FUltJeYlHS4wNF3qEdF0isPbwvF60Kj8GVIRimQmEBySD1Qk+wYqNdBDwOarrdJ0TRGKdT24bg16A/do7eb9Jet3Wpgglb7/JTJceE+pA4wKuHIiluO6lRrnAipTpFrgWMpznOjIahBAQTbXAYGs28GmHpEklWQApqmA6zjCW9g20WUKtXMogzo1DTEAaNLSDLtii3KwZLpEFJDDUqcQC0VM4FNMKpQ0QugdMBQWMcMis1UiDEDrLgoqgAKOiWOTk7OBt2OaiGsKBq7KZ2oQunYHYKhg5eHixIaWF7ExsPyF1SkEW2OUEH2NVaYKhrDJQRxExQNi2QZgM2DSg0AJ5EwUsKtge6QCIUlt2Z0l1AyQw8f1yHtKiFya1DHzDkVlhYEWUJv8AJm3i6ezYsoOZMmRgdexCN3Q6KhJsGkFAVq0HxthWGKqEDTziGEVFlUjulOKRMWlAOxINKeBgTXBhjNNnn9JBKYAFHiSq4bmo63LbRagV4UXfijaj1MMVcv0gNFeNvN1rxFG1SaTDFVtWu1y8RKXKe8eTl4DgK4YH918RsfOdyXHcncncncncncncncnclxcXFxcXFx3JcWeNMplPSV0PtOwzsPtOw+07D7TsPtOw+07D7TsPtMtU+07D7TsPtK6H2lJuWG53JcKDX4w9YZDdfgrpwHs4L7jOVxKNWFPL/wAmUWFjmYc+blK9JfL5b2lJyl6PPuvL8uVCx1sYo0u92EaqB3ZfzicKOeBgp88/Yb/MXlq5kVLSnc/mZsMPQZ2HoB8Q7Hopn+GChT/FTXsXSiT9ilX3gaSelP3/AKQKhDBEXvnXsyobWNBXP2Yu1Y5/yjO4XQvgwwsfQnwIcwPSvxFus/fNeYz20BfEBzblJgNYQJj7BfE95EFpRq5VH3EWJ2dW+XNH73BYYvV+SgIPydPNTB134SoYm3dU/kjqyeXQfZcoIho0ABFVYtFq4QjWN0GVLBSzRWV/9N//xAAhEQACAgEEAwEBAAAAAAAAAAAAARARMQIgIVEwQEESYf/aAAgBAgEBPwAo4KXZS7KXZS7KXZS7KXZS7HRwcHBwcHBxCSKRSKQ41YXracjzGrClI4KQ16GnI8xqwoSG5T7GvPpyPMNx82vz6cjzDj5tfn05HmHC7K+nBwVQ1XnWR5hwlwJMv+FP4h6Wa8+dvgeYfrvMP13mH42q8jz4EIoaE9lRQihrY8w1W9MZexQ2JRfZWx5jV6Ciy5Y8xq3VHw0jwVzLKGPM/IWR5jVuub22yyy5uFkeYfMJFf0aKKKKKEj8lH5KKPyUUfkoooftf//EAB0RAAICAwEBAQAAAAAAAAAAAAABETAQIUAgUGD/2gAIAQMBAT8A5NmzZvK5nlczFhZjjYqVexdDqV7F4kkaNEi/CL6S+67ldF01T4kknu//2Q=="); + params.put("pic_fmt", "jpg"); // 图片格式。jpg, png + params.put("pic_type", "102"); // 图片类型,101: 个人身份证信息面,102: 个人身份证国徽面,201: 企业证件照片,202: 法人身份证信息面,203: 法人身份证国徽面 + + UserPic obj = UserPic.upload(params); + + assertEquals("user should be same as param", params.get("user"), obj.getUser()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/user/UserTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/user/UserTest.java new file mode 100644 index 0000000..f27a4f9 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/user/UserTest.java @@ -0,0 +1,100 @@ +package com.pingplusplus.user; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.User; +import com.pingplusplus.model.UserCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/* + * @author Afon, @date 17-03-28 + */ +public class UserTest extends PingppTestBase { + + /** + * 创建用户 (User) + */ + @Test public void testUserCreate() throws PingppException { + Map params = new HashMap(); + params.put("id", "test_user_" + System.currentTimeMillis()); // 用户 ID,首字母必须是英文数字或者 _-@, 必传 + params.put("address", "Shanghai, China"); // 用户地址, 可选 + params.put("avatar", "https://example.com/avatar.png"); // 头像, 可选 + params.put("email", params.get("id") + "@gmail.com"); // 邮箱地址, 可选 + params.put("gender", System.currentTimeMillis() % 2 == 1 ? "MALE" : "FEMALE"); // 性别。MALE:男,FEMALE:女, 可选 + params.put("mobile", "17602101010"); // 手机号码, 可选 + Map metadata = new HashMap(); + metadata.put("custom_key", "custom_value"); + params.put("metadata", metadata); + + User obj = User.create(params); //创建 User 方法 + + assertEquals("object should be user", "user", obj.getObject()); + assertEquals("id", params.get("id"), obj.getId()); + assertEquals("app", PingppTestData.getAppID(), obj.getApp()); + assertEquals("address", params.get("address"), obj.getAddress()); + assertEquals("avatar", params.get("avatar"), obj.getAvatar()); + assertEquals("email", params.get("email"), obj.getEmail()); + assertEquals("gender", params.get("gender"), obj.getGender()); + assertEquals("mobile", params.get("mobile"), obj.getMobile()); + assertEquals("available_coupons", 0, obj.getAvailableCoupons().intValue()); + assertEquals("available_balance", 0, obj.getAvailableBalance().intValue()); + assertEquals("withdrawable_balance", 0, obj.getWithdrawableBalance().intValue()); + assertEquals("disabled", false, obj.getDisabled()); + } + + /** + * 查询单个用户 (User) + */ + @Test public void testUserRetrieve() throws PingppException { + String userId = "test_user_001"; + User obj = User.retrieve(userId); //查询 User 方法 + + assertEquals("object should be user", "user", obj.getObject()); + assertEquals("id", userId, obj.getId()); + assertEquals("app", PingppTestData.getAppID(), obj.getApp()); + } + + /** + * 查询用户列表 (User) + */ + @Test public void testUserList() throws PingppException { + Map params = new HashMap<>(); + UserCollection objs = User.list(params); //查询 User 列表方法 + + assertEquals("object should be list", "list", objs.getObject()); + } + + /** + * 更新用户信息 (User) + */ + @Test public void testUserUpdate() throws PingppException { + String userId = "test_user_001"; + Map params = new HashMap(); + params.put("address", "Shanghai, China"); + params.put("avatar", "https://example.com/avatar.png"); + params.put("email", params.get("id") + "@gmail.com"); + params.put("gender", System.currentTimeMillis() % 2 == 1 ? "MALE" : "FEMALE"); + params.put("mobile", "17602101010"); + Map metadata = new HashMap(); + metadata.put("custom_key", "custom_value"); + params.put("metadata", metadata); + + User obj = User.update(userId, params); //更新 User 方法 + + assertEquals("object should be user", "user", obj.getObject()); + assertEquals("id", userId, obj.getId()); + assertEquals("app", PingppTestData.getAppID(), obj.getApp()); + assertEquals("address", params.get("address"), obj.getAddress()); + assertEquals("avatar", params.get("avatar"), obj.getAvatar()); + assertEquals("email", params.get("email"), obj.getEmail()); + assertEquals("gender", params.get("gender"), obj.getGender()); + assertEquals("mobile", params.get("mobile"), obj.getMobile()); + assertEquals("disabled", false, obj.getDisabled()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/withdrawal/BatchWithdrawalTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/withdrawal/BatchWithdrawalTest.java new file mode 100644 index 0000000..bcb9b48 --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/withdrawal/BatchWithdrawalTest.java @@ -0,0 +1,66 @@ +package com.pingplusplus.withdrawal; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.PingppTestData; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.BatchWithdrawal; +import com.pingplusplus.model.BatchWithdrawalCollection; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; + +public class BatchWithdrawalTest extends PingppTestBase { + /** + * 批量提现确认 + */ + @Test + public void testBatchWithdrawalCreate() throws PingppException { + Map params = new HashMap(); + ArrayList withdrawals = new ArrayList<>(); // withdrawal id 列表 + withdrawals.add("1701708221834035593"); + params.put("withdrawals", withdrawals); + params.put("status", "pending"); // 状态值: 提现确认:pending,提现撤销:canceled。 + + BatchWithdrawal obj = BatchWithdrawal.create(params); + + assertEquals("object should be batch_withdrawal", "batch_withdrawal", obj.getObject()); + assertNotNull("id should not be null", obj.getId()); + assertEquals("app", PingppTestData.getAppID(), obj.getApp()); + assertNotNull("amount should not be null", obj.getAmount()); + assertTrue("created should be greater than 0", obj.getCreated() > 0); + assertNotNull("status should not be null", obj.getStatus()); + if (params.get("status").equals("pending")) { + assertNull("time_finished should be null when status is pending", obj.getTimeFinished()); + } + } + + /** + * 查询批量提现对象 + */ + @Test public void testBatchWithdrawalRetrieve() throws PingppException { + + // 查询 BatchWithdrawal 对象方法 + // 参数: batch_withdrawal id + BatchWithdrawal obj = BatchWithdrawal.retrieve("1901708221706050363"); + + assertEquals("object should be batch_withdrawal", "batch_withdrawal", obj.getObject()); + } + + /** + * 查询批量提现列表 + */ + @Test public void testBatchWithdrawalList() throws PingppException { + Map params = new HashMap(); + params.put("per_page", 3); + + // 查询 BatchWithdrawal 列表方法 + // 参数: params + BatchWithdrawalCollection obj = BatchWithdrawal.list(params); + + assertEquals("object should be list", "list", obj.getObject()); + } +} diff --git a/pingpp-sdk/src/test/java/com/pingplusplus/withdrawal/WithdrawalTest.java b/pingpp-sdk/src/test/java/com/pingplusplus/withdrawal/WithdrawalTest.java new file mode 100644 index 0000000..87b807b --- /dev/null +++ b/pingpp-sdk/src/test/java/com/pingplusplus/withdrawal/WithdrawalTest.java @@ -0,0 +1,93 @@ +package com.pingplusplus.withdrawal; + +import com.pingplusplus.PingppTestBase; +import com.pingplusplus.exception.PingppException; +import com.pingplusplus.model.Withdrawal; +import com.pingplusplus.model.WithdrawalCollection; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; + +public class WithdrawalTest extends PingppTestBase { + /** + * 创建提现申请 + */ + @Test + public void testCreateWithdrawal() throws PingppException { + Map params = new HashMap(); + params.put("user", "test_user_001"); // 用户 ID, 必传 + params.put("channel", "alipay"); // 提现使用渠道。银联:unionpay,支付宝:alipay,微信:wx_pub,通联:allinpay,京东:jdpay, 可选 + params.put("amount", 100); // 转账金额, 必传 + params.put("description", "custom description"); // 描述, 可选 + params.put("order_no", "1010" + System.currentTimeMillis()); // 提现订单号, 必传 + Map extra = new HashMap(); + extra.put("name", "NAME"); + extra.put("account", "test_user_001@gmail.com"); + params.put("extra", extra); + params.put("user_fee", 5); // 用户需要承担的手续费, 必传 + params.put("settle_account", "test_user_001"); // 使用结算账户提现,不需要填写 extra 参数,同时填写时,结算账号不生效 + + Withdrawal withdrawal = Withdrawal.create(params); // 创建 Withdrawal 对象 + + assertEquals("object should be withdrawal", "withdrawal", withdrawal.getObject()); + assertEquals("user should be same as the value in params", params.get("user"), withdrawal.getUser()); + assertEquals("amount should be same as the value in params", params.get("amount"), withdrawal.getAmount()); + assertEquals("description should be same as the value in params", params.get("description"), withdrawal.getDescription()); + assertEquals("order_no should be same as the value in params", params.get("order_no"), withdrawal.getOrderNo()); + assertEquals("user_name should be same as the value in params", extra.get("user_name"), withdrawal.getExtra().get("user_name")); + assertEquals("account should be same as the value in params", extra.get("account"), withdrawal.getExtra().get("account")); + assertEquals("user_fee should be same as the value in params", params.get("user_fee"), withdrawal.getUserFee()); + assertEquals("status should be created", "created", withdrawal.getStatus()); + assertEquals("time_canceled should be null", null, withdrawal.getTimeCanceled()); + assertEquals("time_succeeded should be created", null, withdrawal.getTimeSucceeded()); + assertEquals("failure_msg should be null", null, withdrawal.getFailureMsg()); + assertNull("operation_url should be null", withdrawal.getOperationUrl()); + } + + /** + * 获取提现对象 + */ + @Test public void testWithdrawalRetrieve() throws PingppException { + + // 查询 Withdrawal + // 参数: withdrawal id + Withdrawal withdrawal = Withdrawal.retrieve("1701708221834035593"); + + assertEquals("object should be withdrawal", "withdrawal", withdrawal.getObject()); + } + + /** + * 获取提现列表 + */ + @Test public void testGetWithdrawalList() throws PingppException { + Map params = new HashMap(); + params.put("page", 1); + params.put("per_page", 3); + + WithdrawalCollection withdrawals = Withdrawal.list(params); // 查询 Withdrawal 列表 + + assertNotNull("total_withdrawal_list should not be null", withdrawals.getTotalWithdrawalsAmount()); + assertEquals("object should be list", "list", withdrawals.getObject()); + assertEquals("data count should be same with limit", ((Integer)params.get("per_page")).intValue(), withdrawals.getData().size()); + } + + /** + * 更新提现对象 + */ + @Test public void testWithdrawalUpdate() throws PingppException { + Map params = new HashMap(); + params.put("status", "canceled"); // 更新状态。确认:pending,取消:canceled。 + // 更新 Withdrawal 方法 + // 参数一: withdrawal id + // 参数二: params + Withdrawal withdrawal = Withdrawal.update("1701708221834035593", params); + // 或者使用以下方法来更新 Withdrawal 状态 + // Withdrawal.cancel("1701708221834035593"); // 取消 Withdrawal + // Withdrawal.confirm("1701708221834035593"); // 确认 Withdrawal + + assertEquals("object should be withdrawal", "withdrawal", withdrawal.getObject()); + } +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..71f3e19 --- /dev/null +++ b/pom.xml @@ -0,0 +1,63 @@ + + + 4.0.0 + + com.pingxx + pingpp-java-parent + 2.5.6 + pom + + A Java SDK for Ping++ Payment API. + + + Apache License 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + repo + + + + + scm:git:https://github.com/PingPlusPlus/pingpp-java.git + + + + afon + Afon + xufeng.weng@pingxx.com + + + + + pingpp-sdk + + + + 1.8 + 1.8 + + + + + + + + + org.apache.maven.plugins + maven-install-plugin + 2.5.2 + + true + + + + org.apache.maven.plugins + maven-deploy-plugin + 2.7 + + true + + + + + diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..c5a152d --- /dev/null +++ b/settings.gradle @@ -0,0 +1,3 @@ +rootProject.name = 'pingpp-java' +include 'pingpp-sdk' +include 'example' diff --git a/src/main/java/com/pingplusplus/Pingpp.java b/src/main/java/com/pingplusplus/Pingpp.java deleted file mode 100644 index 5f595b3..0000000 --- a/src/main/java/com/pingplusplus/Pingpp.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.pingplusplus; - -/** - * Ping++ Base class - */ -public abstract class Pingpp { - /** - * Ping++ API BASE URL - */ - public static final String LIVE_API_BASE = "https://api.pingxx.com"; - /** - * version - */ - public static final String VERSION = "2.1.7"; - /** - * api key - */ - public static volatile String apiKey; - /** - * api version - */ - public static volatile String apiVersion = "2016-03-24"; - - public static String AcceptLanguage = "zh-CN"; - - private static volatile boolean verifySSL = true; - private static volatile String apiBase = LIVE_API_BASE; - - public static volatile String privateKey; - public static volatile String privateKeyPath; - - public static Boolean DEBUG = false; - - /** - * (FOR TESTING ONLY) - * If you'd like your API requests to hit your own (mocked) server, - * you can set this up here by overriding the base api URL. - */ - public static void overrideApiBase(final String overriddenApiBase) { - apiBase = overriddenApiBase; - } - - /** - * (FOR TESTING ONLY) - * Only disable SSL verification if you're using your own (mocked) server. - * Disabling verification on pingxx.com is not supported - */ - public static void setVerifySSL(boolean verify) { - verifySSL = verify; - } - - /** - * get SSL state - * - * @return true is set SSL ,false is not set SSL - */ - public static boolean getVerifySSL() { - return verifySSL; - } - - /** - * get api url - * - * @return String api url - */ - public static String getApiBase() { - return apiBase; - } - - /** - * set api url - * - * @param apiBase - */ - public static void setApiBase(String apiBase) { - Pingpp.apiBase = apiBase; - } -} diff --git a/src/main/java/com/pingplusplus/exception/APIConnectionException.java b/src/main/java/com/pingplusplus/exception/APIConnectionException.java deleted file mode 100644 index 38af6c7..0000000 --- a/src/main/java/com/pingplusplus/exception/APIConnectionException.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.pingplusplus.exception; - -public class APIConnectionException extends PingppException { - - private static final long serialVersionUID = 1L; - - public APIConnectionException(String message) { - super(message); - } - - public APIConnectionException(String message, Throwable e) { - super(message, e); - } - -} diff --git a/src/main/java/com/pingplusplus/exception/APIException.java b/src/main/java/com/pingplusplus/exception/APIException.java deleted file mode 100644 index 50b9db0..0000000 --- a/src/main/java/com/pingplusplus/exception/APIException.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.pingplusplus.exception; - -public class APIException extends PingppException { - - private static final long serialVersionUID = 1L; - - public APIException(String message, Throwable e) { - super(message, e); - } - -} diff --git a/src/main/java/com/pingplusplus/exception/AuthenticationException.java b/src/main/java/com/pingplusplus/exception/AuthenticationException.java deleted file mode 100644 index 40b9c9c..0000000 --- a/src/main/java/com/pingplusplus/exception/AuthenticationException.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.pingplusplus.exception; - -public class AuthenticationException extends PingppException { - - - public AuthenticationException(String message) { - super(message); - } - - private static final long serialVersionUID = 1L; - -} diff --git a/src/main/java/com/pingplusplus/exception/ChannelException.java b/src/main/java/com/pingplusplus/exception/ChannelException.java deleted file mode 100644 index 8f42eb4..0000000 --- a/src/main/java/com/pingplusplus/exception/ChannelException.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.pingplusplus.exception; - -public class ChannelException extends PingppException { - - private static final long serialVersionUID = 1L; - - private final String param; - - public ChannelException(String message, String param, Throwable e) { - super(message, e); - this.param = param; - } - - public String getParam() { - return param; - } - -} diff --git a/src/main/java/com/pingplusplus/exception/InvalidRequestException.java b/src/main/java/com/pingplusplus/exception/InvalidRequestException.java deleted file mode 100644 index f0464e2..0000000 --- a/src/main/java/com/pingplusplus/exception/InvalidRequestException.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.pingplusplus.exception; - -public class InvalidRequestException extends PingppException { - - private static final long serialVersionUID = 1L; - - private final String param; - - public InvalidRequestException(String message, String param, Throwable e) { - super(message, e); - this.param = param; - } - - public String getParam() { - return param; - } - -} diff --git a/src/main/java/com/pingplusplus/exception/PingppException.java b/src/main/java/com/pingplusplus/exception/PingppException.java deleted file mode 100644 index 48865be..0000000 --- a/src/main/java/com/pingplusplus/exception/PingppException.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.pingplusplus.exception; - -public abstract class PingppException extends Exception { - - public PingppException(String message) { - super(message, null); - } - - public PingppException(String message, Throwable e) { - super(message, e); - } - - private static final long serialVersionUID = 1L; - -} diff --git a/src/main/java/com/pingplusplus/model/Card.java b/src/main/java/com/pingplusplus/model/Card.java deleted file mode 100644 index 2eb510d..0000000 --- a/src/main/java/com/pingplusplus/model/Card.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.pingplusplus.model; - -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; -import com.pingplusplus.net.APIResource; - -import java.util.Map; - -/** - * Created by sunkai on 15/9/21. - */ -public class Card extends APIResource { - private String id; - private String object; - private Long created; - private String last4; - private String funding; - private String brand; - private String bank; - private String customer; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getObject() { - return object; - } - - public void setObject(String object) { - this.object = object; - } - - public Long getCreated() { - return created; - } - - public void setCreated(Long created) { - this.created = created; - } - - public String getLast4() { - return last4; - } - - public void setLast4(String last4) { - this.last4 = last4; - } - - public String getFunding() { - return funding; - } - - public void setFunding(String funding) { - this.funding = funding; - } - - public String getBrand() { - return brand; - } - - public void setBrand(String brand) { - this.brand = brand; - } - - public String getBank() { - return bank; - } - - public void setBank(String bank) { - this.bank = bank; - } - - public String getCustomer() { - return customer; - } - - public void setCustomer(String customer) { - this.customer = customer; - } - - public DeletedCard delete() throws ChannelException, APIException, AuthenticationException, InvalidRequestException, APIConnectionException { - return request(RequestMethod.DELETE, this.getInstanceURL(), null, DeletedCard.class); - } - - public static Card retrieve(String customerId, String id) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - String url = instanceURL(Customer.class, customerId) + "/sources/" + id; - return request(APIResource.RequestMethod.GET, url, null, Card.class); - } - - public String getInstanceURL() { - if (this.getCustomer() != null) { - return String.format("%s/%s/sources/%s", classURL(Customer.class), this.getCustomer(), this.getId()); - } else { - return null; - } - } -} diff --git a/src/main/java/com/pingplusplus/model/CardCollection.java b/src/main/java/com/pingplusplus/model/CardCollection.java deleted file mode 100644 index c392398..0000000 --- a/src/main/java/com/pingplusplus/model/CardCollection.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.pingplusplus.model; - -import com.pingplusplus.Pingpp; -import com.pingplusplus.exception.*; - -import java.util.Map; - -public class CardCollection extends PingppCollectionAPIResource { - - public Card retrieve(String id) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - String url = String.format("%s%s/%s", Pingpp.getApiBase(), this.getURL(), id); - return request(RequestMethod.GET, url, null, Card.class); - } - - public CardCollection all(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - - String url = String.format("%s%s", Pingpp.getApiBase(), this.getURL()); - return request(RequestMethod.GET, url, params, CardCollection.class); - } - - public Card create(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - - String url = String.format("%s%s", Pingpp.getApiBase(), this.getURL()); - return request(RequestMethod.POST, url, params, Card.class); - } -} diff --git a/src/main/java/com/pingplusplus/model/ChargeRefundCollection.java b/src/main/java/com/pingplusplus/model/ChargeRefundCollection.java deleted file mode 100644 index 5f7524a..0000000 --- a/src/main/java/com/pingplusplus/model/ChargeRefundCollection.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.pingplusplus.model; - -import com.pingplusplus.Pingpp; -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; - -import java.util.Map; - -public class ChargeRefundCollection extends PingppCollectionAPIResource { - - public ChargeRefundCollection all(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - - String url = String.format("%s%s", Pingpp.getApiBase(), this.getURL()); - return request(RequestMethod.GET, url, params, ChargeRefundCollection.class); - } - - public Refund retrieve(String id) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - - String url = String.format("%s%s/%s", Pingpp.getApiBase(), this.getURL(), id); - return request(RequestMethod.GET, url, null, Refund.class); - } - - public Refund create(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - - String url = String.format("%s%s", Pingpp.getApiBase(), this.getURL()); - return request(RequestMethod.POST, url, params, Refund.class); - } - -} diff --git a/src/main/java/com/pingplusplus/model/Customer.java b/src/main/java/com/pingplusplus/model/Customer.java deleted file mode 100644 index 62f8dcb..0000000 --- a/src/main/java/com/pingplusplus/model/Customer.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.pingplusplus.model; - -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; -import com.pingplusplus.net.APIResource; - -import java.util.Map; - -/** - * Created by sunkai on 15/9/21. - */ -public class Customer extends APIResource { - private String id; - private String object; - private Long created; - private Boolean livemode; - private Object app; - private String name; - private String email; - private String currency; - private String description; - private Map metadata; - private CardCollection sources; - private String defaultSource; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getObject() { - return object; - } - - public void setObject(String object) { - this.object = object; - } - - public Long getCreated() { - return created; - } - - public void setCreated(Long created) { - this.created = created; - } - - public Boolean getLivemode() { - return livemode; - } - - public void setLivemode(Boolean livemode) { - this.livemode = livemode; - } - - public Object getApp() { - return app; - } - - public void setApp(Object app) { - this.app = app; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getCurrency() { - return currency; - } - - public void setCurrency(String currency) { - this.currency = currency; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public Map getMetadata() { - return metadata; - } - - public void setMetadata(Map metadata) { - this.metadata = metadata; - } - - public CardCollection getSources() { - return sources; - } - - public void setSources(CardCollection sources) { - this.sources = sources; - } - - public String getDefaultSource() { - return defaultSource; - } - - public void setDefaultSource(String defaultSource) { - this.defaultSource = defaultSource; - } - - public static Customer create(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return request(RequestMethod.POST, classURL(Customer.class), params, Customer.class); - } - - public Customer update(Map params) throws ChannelException, APIException, AuthenticationException, InvalidRequestException, APIConnectionException { - return request(RequestMethod.PUT, instanceURL(Customer.class, this.id), params, Customer.class); - } - - public DeletedCustomer delete() throws ChannelException, APIException, AuthenticationException, InvalidRequestException, APIConnectionException { - return request(RequestMethod.DELETE, instanceURL(Customer.class, this.id), null, DeletedCustomer.class); - } - - public static Customer retrieve(String id) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - return request(RequestMethod.GET, instanceURL(Customer.class, id), null, Customer.class); - } - - public static CustomerCollection all(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return request(RequestMethod.GET, classURL(Customer.class), params, CustomerCollection.class); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/src/main/java/com/pingplusplus/model/CustomerCollection.java b/src/main/java/com/pingplusplus/model/CustomerCollection.java deleted file mode 100644 index 75cc88f..0000000 --- a/src/main/java/com/pingplusplus/model/CustomerCollection.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.pingplusplus.model; - -public class CustomerCollection extends PingppCollection { -} diff --git a/src/main/java/com/pingplusplus/model/DeletedCustomer.java b/src/main/java/com/pingplusplus/model/DeletedCustomer.java deleted file mode 100644 index e2e6f07..0000000 --- a/src/main/java/com/pingplusplus/model/DeletedCustomer.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.pingplusplus.model; - -/** - * Created by Afon on 15/12/23. - */ -public class DeletedCustomer extends PingppObject implements DeletedPingppObject { - String id; - Boolean deleted; - - public String getId() { - return id; - } - public void setId(String id) { - this.id = id; - } - public Boolean getDeleted() { - return deleted; - } - public void setDeleted(Boolean deleted) { - this.deleted = deleted; - } -} diff --git a/src/main/java/com/pingplusplus/model/Notify.java b/src/main/java/com/pingplusplus/model/Notify.java deleted file mode 100644 index 3d26dc5..0000000 --- a/src/main/java/com/pingplusplus/model/Notify.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.pingplusplus.model; - -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.pingplusplus.net.APIResource; - -public class Notify { - class InnerObject { - String object; - } - - public static Object parseNotify(String notifyJson) { - - InnerObject innerObject; - try { - innerObject = new Gson().fromJson(notifyJson, InnerObject.class); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - - if (innerObject == null || innerObject.object == null || innerObject.object.isEmpty()) - return null; - - if (innerObject.object.equals("charge")) { - return APIResource.GSON.fromJson(notifyJson, Charge.class); - } else if (innerObject.object.equals("refund")) { - return new GsonBuilder() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .create() - .fromJson(notifyJson, Refund.class); - } - - return null; - } -} diff --git a/src/main/java/com/pingplusplus/model/PingppObject.java b/src/main/java/com/pingplusplus/model/PingppObject.java deleted file mode 100644 index 5a47b45..0000000 --- a/src/main/java/com/pingplusplus/model/PingppObject.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.pingplusplus.model; - -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - -import java.lang.reflect.Field; - -public abstract class PingppObject { - - public static final Gson PRETTY_PRINT_GSON = new GsonBuilder(). - setPrettyPrinting(). - serializeNulls(). - setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES). - disableHtmlEscaping(). - create(); - - @Override - public String toString() { - return PRETTY_PRINT_GSON.toJson(this); - } -} diff --git a/src/main/java/com/pingplusplus/model/Refund.java b/src/main/java/com/pingplusplus/model/Refund.java deleted file mode 100644 index a18ade3..0000000 --- a/src/main/java/com/pingplusplus/model/Refund.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.pingplusplus.model; - -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; -import com.pingplusplus.net.APIResource; - -import java.util.Map; - -public class Refund extends APIResource /*implements MetadataStore*/ { - String id; - String object; - String orderNo; - Integer amount; - Long created; - Boolean succeed; - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public void setId(String id) { - this.id = id; - } - - String status; - Long timeSucceed; - String description; - String failureCode; - String failureMsg; - Map metadata; - String charge; - - public Refund update(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return update(params, null); - } - - public Refund update(Map params, String apiKey) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return request(RequestMethod.POST, this.getInstanceURL(), params, Refund.class); - } - - public String getInstanceURL() { - if (this.charge != null) { - return String.format("%s/%s/refunds/%s", classURL(Charge.class), this.charge, this.getId()); - } - return null; - } - - public String getId() { - return id; - } - - public Integer getAmount() { - return amount; - } - - public void setAmount(Integer amount) { - this.amount = amount; - } - - public Long getCreated() { - return created; - } - - public void setCreated(Long created) { - this.created = created; - } - - public String getCharge() { - return charge; - } - - public void setCharge(String charge) { - this.charge = charge; - } - - public Boolean getSucceed() { - return succeed; - } - - public void setSucceed(Boolean succeed) { - this.succeed = succeed; - } - - public Long getTimeSucceed() { - return timeSucceed; - } - - public void setTimeSucceed(Long timeSucceed) { - this.timeSucceed = timeSucceed; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getFailureMsg() { - return failureMsg; - } - - public void setFailureMsg(String failureMsg) { - this.failureMsg = failureMsg; - } - - public String getFailureCode() { - return failureCode; - } - - public void setFailureCode(String failureCode) { - this.failureCode = failureCode; - } - - public String getOrderNo() { - return orderNo; - } - - public void setOrderNo(String orderNo) { - this.orderNo = orderNo; - } - - public String getObject() { - return object; - } - - public void setObject(String object) { - this.object = object; - } - - public Map getMetadata() { - return metadata; - } - - public void setMetadata(Map metadata) { - this.metadata = metadata; - } -} diff --git a/src/main/java/com/pingplusplus/model/SMSCode.java b/src/main/java/com/pingplusplus/model/SMSCode.java deleted file mode 100644 index fa26ed7..0000000 --- a/src/main/java/com/pingplusplus/model/SMSCode.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.pingplusplus.model; - -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; -import com.pingplusplus.net.APIResource; - -/** - * Created by sunkai on 15/9/21. - */ -public class SMSCode extends APIResource { - private String id; - private String object; - private Long created; - private Boolean validated; - private String source; - private String code; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getObject() { - return object; - } - - public void setObject(String object) { - this.object = object; - } - - public Long getCreated() { - return created; - } - - public void setCreated(Long created) { - this.created = created; - } - - public Boolean getValidated() { - return validated; - } - - public void setValidated(Boolean validated) { - this.validated = validated; - } - - public String getSource() { - return source; - } - - public void setSource(String source) { - this.source = source; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public static SMSCode retrieve(String id) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - return request(APIResource.RequestMethod.GET, instanceURL(SMSCode.class, id), null, SMSCode.class); - } -} diff --git a/src/main/java/com/pingplusplus/model/Token.java b/src/main/java/com/pingplusplus/model/Token.java deleted file mode 100644 index eb379c9..0000000 --- a/src/main/java/com/pingplusplus/model/Token.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.pingplusplus.model; - -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; -import com.pingplusplus.net.APIResource; - -import java.util.Map; - -/** - * Created by sunkai on 15/9/21. - */ -public class Token extends APIResource { - private String id; - private String object; - private Long created; - private Boolean livemode; - private Boolean used; - private Long timeUsed; - private String type; - private Card card; - private SMSCode smsCode; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getObject() { - return object; - } - - public void setObject(String object) { - this.object = object; - } - - public Long getCreated() { - return created; - } - - public void setCreated(Long created) { - this.created = created; - } - - public Boolean getLivemode() { - return livemode; - } - - public void setLivemode(Boolean livemode) { - this.livemode = livemode; - } - - public Boolean getUsed() { - return used; - } - - public void setUsed(Boolean used) { - this.used = used; - } - - public Long getTimeUsed() { - return timeUsed; - } - - public void setTimeUsed(Long timeUsed) { - this.timeUsed = timeUsed; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public Card getCard() { - return card; - } - - public void setCard(Card card) { - this.card = card; - } - - public SMSCode getSmsCode() { - return smsCode; - } - - public void setSmsCode(SMSCode smsCode) { - this.smsCode = smsCode; - } - - public static Token create(Map params) - throws AuthenticationException, InvalidRequestException, - APIConnectionException, APIException, ChannelException { - return request(APIResource.RequestMethod.POST, classURL(Token.class), params, Token.class); - } - - public static Token retrieve(String id) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - return request(RequestMethod.GET, instanceURL(Token.class, id), null, Token.class); - } -} diff --git a/src/main/java/com/pingplusplus/net/APIResource.java b/src/main/java/com/pingplusplus/net/APIResource.java deleted file mode 100644 index 7f5876d..0000000 --- a/src/main/java/com/pingplusplus/net/APIResource.java +++ /dev/null @@ -1,639 +0,0 @@ -package com.pingplusplus.net; - -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.pingplusplus.Pingpp; -import com.pingplusplus.exception.APIConnectionException; -import com.pingplusplus.exception.APIException; -import com.pingplusplus.exception.AuthenticationException; -import com.pingplusplus.exception.ChannelException; -import com.pingplusplus.exception.InvalidRequestException; -import com.pingplusplus.model.*; -import org.apache.commons.codec.binary.Base64; -import sun.security.util.DerInputStream; -import sun.security.util.DerValue; - -import java.io.*; -import java.math.BigInteger; -import java.net.URL; -import java.net.URLEncoder; -import java.security.*; -import java.security.spec.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Scanner; - -import javax.net.ssl.HttpsURLConnection; - -/** - * extends the abstract class when you need requset anything from ping++ - */ -public abstract class APIResource extends PingppObject { - /** - * URLEncoder charset - */ - public static final String CHARSET = "UTF-8"; - - - /** - * Http requset method - */ - protected enum RequestMethod { - GET, POST, DELETE, PUT - } - - /** - * Gson object use to transform json string to Charge object - */ - public static final Gson GSON = new GsonBuilder() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .registerTypeAdapter(Charge.class, new ChargeDeserializer()) - .registerTypeAdapter(RedEnvelope.class, new RedEnvelopeDeserializer()) - .registerTypeAdapter(Transfer.class, new TransferDeserializer()) - .registerTypeAdapter(ChargeRefundCollection.class, new ChargeRefundCollectionDeserializer()) - .registerTypeAdapter(EventData.class, new EventDataDeserializer()) - .registerTypeAdapter(PingppRawJsonObject.class, new PingppRawJsonObjectDeserializer()) - .create(); - - /** - * @param clazz - * @return - */ - private static String className(Class clazz) { - String className = clazz.getSimpleName().toLowerCase().replace("$", " "); - - if (className.equals("redenvelope")) { - return "red_envelope"; - } - if (className.equals("smscode")) { - return "sms_code"; - } else { - return className; - } - } - - /** - * @param clazz - * @return - */ - protected static String singleClassURL(Class clazz) { - return String.format("%s/v1/%s", Pingpp.getApiBase(), className(clazz)); - } - - /** - * @param clazz - * @return - */ - protected static String classURL(Class clazz) { - return String.format("%ss", singleClassURL(clazz)); - } - - /** - * @param clazz - * @param id - * @return - * @throws InvalidRequestException - */ - protected static String instanceURL(Class clazz, String id) throws InvalidRequestException { - try { - return String.format("%s/%s", classURL(clazz), urlEncode(id)); - } catch (UnsupportedEncodingException e) { - throw new InvalidRequestException("Unable to encode parameters to " + CHARSET, null, e); - } - } - - - /** - * @param str - * @return - * @throws UnsupportedEncodingException - */ - private static String urlEncode(String str) throws UnsupportedEncodingException { - if (str == null) { - return null; - } else { - return URLEncoder.encode(str, CHARSET); - } - } - - /** - * @param k - * @param v - * @return - * @throws UnsupportedEncodingException - */ - private static String urlEncodePair(String k, String v) - throws UnsupportedEncodingException { - return String.format("%s=%s", urlEncode(k), urlEncode(v)); - } - - /** - * @param apiKey - * @return - */ - static Map getHeaders(String apiKey) { - Map headers = new HashMap(); - headers.put("Accept-Charset", CHARSET); - headers.put("User-Agent", - String.format("Pingpp/v1 JavaBindings/%s", Pingpp.VERSION)); - - if (apiKey == null) { - apiKey = Pingpp.apiKey; - } - - headers.put("Authorization", String.format("Bearer %s", apiKey)); - headers.put("Accept-Language", Pingpp.AcceptLanguage); - - // debug headers - String[] propertyNames = {"os.name", "os.version", "os.arch", - "java.version", "java.vendor", "java.vm.version", - "java.vm.vendor"}; - Map propertyMap = new HashMap(); - for (String propertyName : propertyNames) { - propertyMap.put(propertyName, System.getProperty(propertyName)); - } - propertyMap.put("bindings.version", Pingpp.VERSION); - propertyMap.put("lang", "Java"); - propertyMap.put("publisher", "Pingpp"); - headers.put("X-Pingpp-Client-User-Agent", GSON.toJson(propertyMap)); - if (Pingpp.apiVersion != null) { - headers.put("Pingplusplus-Version", Pingpp.apiVersion); - } - return headers; - } - - /** - * @param url - * @param apiKey - * @return - * @throws IOException - */ - private static java.net.HttpURLConnection createPingppConnection( - String url, String apiKey) throws IOException { - URL pingppURL = null; - pingppURL = new URL(url); - - HttpsURLConnection conn = (HttpsURLConnection) pingppURL.openConnection(); - - conn.setConnectTimeout(30 * 1000); - conn.setReadTimeout(80 * 1000); - conn.setUseCaches(false); - for (Map.Entry header : getHeaders(apiKey).entrySet()) { - conn.setRequestProperty(header.getKey(), header.getValue()); - } - - return conn; - } - - /** - * @throws APIConnectionException - */ - private static void throwInvalidCertificateException() throws APIConnectionException { - throw new APIConnectionException("Invalid server certificate. You tried to connect to a server that has a revoked SSL certificate, which means we cannot securely send data to that server. "); - } - - /** - * @param url - * @param query - * @return - */ - private static String formatURL(String url, String query) { - if (query == null || query.isEmpty()) { - return url; - } else { - // In some cases, URL can already contain a question mark (eg, upcoming invoice lines) - String separator = url.contains("?") ? "&" : "?"; - return String.format("%s%s%s", url, separator, query); - } - } - - /** - * @param url - * @param query - * @param apiKey - * @return - * @throws IOException - * @throws APIConnectionException - */ - private static java.net.HttpURLConnection createGetConnection( - String url, String query, String apiKey) throws IOException, APIConnectionException { - String getURL = formatURL(url, query); - java.net.HttpURLConnection conn = createPingppConnection(getURL, - apiKey); - conn.setRequestMethod("GET"); - - return conn; - } - - private static java.net.HttpURLConnection createDeleteConnection( - String url, String query, String apiKey) throws IOException, APIConnectionException { - String getURL = formatURL(url, query); - java.net.HttpURLConnection conn = createPingppConnection(getURL, - apiKey); - conn.setRequestMethod("DELETE"); - - return conn; - } - - /** - * @param url - * @param query - * @param apiKey - * @return - * @throws IOException - * @throws APIConnectionException - */ - private static java.net.HttpURLConnection createPostConnection( - String url, String query, String apiKey) throws IOException, APIConnectionException { - java.net.HttpURLConnection conn = createPingppConnection(url, - apiKey); - - conn.setDoOutput(true); - conn.setRequestMethod("POST"); - conn.setRequestProperty("Content-Type", String.format( - "application/json;charset=%s", CHARSET)); - String signature = generateSign(query); - if (signature != null) { - conn.setRequestProperty("Pingplusplus-Signature", signature); - } - - OutputStream output = null; - try { - output = conn.getOutputStream(); - output.write(query.getBytes(CHARSET)); - } finally { - if (output != null) { - output.close(); - } - } - return conn; - } - - /** - * @param url - * @param query - * @param apiKey - * @return - * @throws IOException - * @throws APIConnectionException - */ - private static java.net.HttpURLConnection createPutConnection( - String url, String query, String apiKey) throws IOException, APIConnectionException { - java.net.HttpURLConnection conn = createPingppConnection(url, - apiKey); - - conn.setDoOutput(true); - conn.setRequestMethod("PUT"); - conn.setRequestProperty("Content-Type", String.format( - "application/json;charset=%s", CHARSET)); - String signature = generateSign(query); - if (signature != null) { - conn.setRequestProperty("Pingplusplus-Signature", signature); - } - - OutputStream output = null; - try { - output = conn.getOutputStream(); - output.write(query.getBytes(CHARSET)); - } finally { - if (output != null) { - output.close(); - } - } - return conn; - } - - /** - * @param params - * @return - * @throws UnsupportedEncodingException - * @throws InvalidRequestException - */ - private static String createQuery(Map params) - throws UnsupportedEncodingException, InvalidRequestException { - Map flatParams = flattenParams(params); - StringBuilder queryStringBuffer = new StringBuilder(); - for (Map.Entry entry : flatParams.entrySet()) { - if (queryStringBuffer.length() > 0) { - queryStringBuffer.append("&"); - } - queryStringBuffer.append(urlEncodePair(entry.getKey(), - entry.getValue())); - } - return queryStringBuffer.toString(); - } - - /** - * @param params - * @return - */ - private static String createJSONString(Map params) { - Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create(); - return gson.toJson(params); - } - - /** - * @param params - * @return - * @throws InvalidRequestException - */ - private static Map flattenParams(Map params) - throws InvalidRequestException { - if (params == null) { - return new HashMap(); - } - Map flatParams = new HashMap(); - for (Map.Entry entry : params.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - if (value instanceof Map) { - Map flatNestedMap = new HashMap(); - Map nestedMap = (Map) value; - for (Map.Entry nestedEntry : nestedMap.entrySet()) { - flatNestedMap.put( - String.format("%s[%s]", key, nestedEntry.getKey()), - nestedEntry.getValue()); - } - flatParams.putAll(flattenParams(flatNestedMap)); - } else if (value instanceof ArrayList) { - ArrayList ar = (ArrayList) value; - Map flatNestedMap = new HashMap(); - int size = ar.size(); - for (int i = 0; i < size; i++) { - flatNestedMap.put(String.format("%s[%d]", key, i), ar.get(i)); - } - flatParams.putAll(flattenParams(flatNestedMap)); - } else if ("".equals(value)) { - throw new InvalidRequestException("You cannot set '" + key + "' to an empty string. " + - "We interpret empty strings as null in requests. " + - "You may set '" + key + "' to null to delete the property.", - key, null); - } else if (value == null) { - flatParams.put(key, ""); - } else { - flatParams.put(key, value.toString()); - } - } - return flatParams; - } - - - // represents Errors returned as JSON - private static class ErrorContainer { - private APIResource.Error error; - } - - /** - * - */ - private static class Error { - @SuppressWarnings("unused") - String type; - - String message; - - String code; - - String param; - - @Override - public String toString() { - StringBuffer sb = new StringBuffer(); - if (null != type && !type.isEmpty()) { - sb.append("Error type: " + type + "\n"); - } - if (null != message && !message.isEmpty()) { - sb.append("\t Error message: " + message + "\n"); - } - if (null != code && !code.isEmpty()) { - sb.append("\t Error code: " + code + "\n"); - } - - return sb.toString(); - } - } - - /** - * @param responseStream - * @return - * @throws IOException - */ - private static String getResponseBody(InputStream responseStream) - throws IOException { - //\A is the beginning of - // the stream boundary - String rBody = new Scanner(responseStream, CHARSET) - .useDelimiter("\\A") - .next(); // - responseStream.close(); - return rBody; - } - - /** - * @param method - * @param url - * @param query - * @param apiKey - * @return - * @throws APIConnectionException - */ - private static PingppResponse makeURLConnectionRequest( - APIResource.RequestMethod method, String url, String query, - String apiKey) throws APIConnectionException { - java.net.HttpURLConnection conn = null; - try { - switch (method) { - case GET: - conn = createGetConnection(url, query, apiKey); - break; - case POST: - conn = createPostConnection(url, query, apiKey); - break; - case DELETE: - conn = createDeleteConnection(url, query, apiKey); - break; - case PUT: - conn = createPutConnection(url, query, apiKey); - break; - default: - throw new APIConnectionException( - String.format("Unrecognized HTTP method %s. ", method)); - } - // trigger the request - int rCode = conn.getResponseCode(); - String rBody = null; - Map> headers; - - if (rCode >= 200 && rCode < 300) { - rBody = getResponseBody(conn.getInputStream()); - } else { - rBody = getResponseBody(conn.getErrorStream()); - } - headers = conn.getHeaderFields(); - return new PingppResponse(rCode, rBody, headers); - - } catch (IOException e) { - throw new APIConnectionException( - String.format( - "IOException during API request to Pingpp (%s): %s " - + "Please check your internet connection and try again. If this problem persists," - + "you should check Pingpp's service status at https://pingxx.com/status.", - Pingpp.getApiBase(), e.getMessage()), e); - } finally { - if (conn != null) { - conn.disconnect(); - } - } - } - - /** - * @param method - * @param url - * @param params - * @param clazz - * @param - * @return - * @throws AuthenticationException - * @throws InvalidRequestException - * @throws APIConnectionException - * @throws APIException - */ - protected static T request(APIResource.RequestMethod method, String url, Map params, Class clazz) throws AuthenticationException, - InvalidRequestException, APIConnectionException, - APIException, ChannelException { - if ((Pingpp.apiKey == null || Pingpp.apiKey.length() == 0)) { - throw new AuthenticationException( - "No API key provided. (HINT: set your API key using 'Pingpp.apiKey = '. " - + "You can generate API keys from the Pingpp web interface. " - + "See https://pingxx.com for details."); - } - - String query = null; - - switch (method) { - case GET: - case DELETE: - try { - query = createQuery(params); - } catch (UnsupportedEncodingException e) { - throw new InvalidRequestException("Unable to encode parameters to " + CHARSET, null, e); - } - break; - case POST: - case PUT: - query = createJSONString(params); - break; - } - - PingppResponse response; - try { - // HTTPSURLConnection verifies SSL cert by default - response = makeURLConnectionRequest(method, url, query, Pingpp.apiKey); - } catch (ClassCastException ce) { - throw ce; - } - int rCode = response.getResponseCode(); - String rBody = response.getResponseBody(); - if (rCode < 200 || rCode >= 300) { - handleAPIError(rBody, rCode); - } - return GSON.fromJson(rBody, clazz); - } - - /** - * 错误处理 - * - * @param rBody - * @param rCode - * @throws InvalidRequestException - * @throws AuthenticationException - * @throws APIException - */ - private static void handleAPIError(String rBody, int rCode) - throws InvalidRequestException, AuthenticationException, - APIException, ChannelException { - APIResource.Error error = GSON.fromJson(rBody, - APIResource.ErrorContainer.class).error; - switch (rCode) { - case 400: - throw new InvalidRequestException(error.toString(), error.param, null); - case 404: - throw new InvalidRequestException(error.toString(), error.param, null); - case 402: - throw new ChannelException(error.toString(), error.param, null); - case 401: - throw new AuthenticationException(error.toString()); - default: - throw new APIException(error.toString(), null); - } - } - - /** - * 生成请求签名 - * - * @param data - */ - - private static String generateSign(String data) - throws IOException { - if (Pingpp.privateKey == null) { - if (Pingpp.privateKeyPath == null) { - return null; - } - FileInputStream inputStream = new FileInputStream(Pingpp.privateKeyPath); - byte[] keyBytes = new byte[inputStream.available()]; - inputStream.read(keyBytes); - inputStream.close(); - String keyString = new String(keyBytes, CHARSET); - Pingpp.privateKey = keyString; - } - - String trimmedPrivateKey = Pingpp.privateKey - .replaceAll("(-+BEGIN (RSA )?PRIVATE KEY-+\\r?\\n|-+END (RSA )?PRIVATE KEY-+\\r?\\n?)", ""); - byte[] privateKeyBytes = Base64.decodeBase64(trimmedPrivateKey); - - DerInputStream derReader = new DerInputStream(privateKeyBytes); - DerValue[] seq = derReader.getSequence(0); - - if (seq.length < 9) { - System.out.println("Could not parse a PKCS1 private key."); - return null; - } - - // skip version seq[0]; - BigInteger modulus = seq[1].getBigInteger(); - BigInteger publicExp = seq[2].getBigInteger(); - BigInteger privateExp = seq[3].getBigInteger(); - BigInteger prime1 = seq[4].getBigInteger(); - BigInteger prime2 = seq[5].getBigInteger(); - BigInteger exp1 = seq[6].getBigInteger(); - BigInteger exp2 = seq[7].getBigInteger(); - BigInteger crtCoef = seq[8].getBigInteger(); - RSAPrivateCrtKeySpec spec = new RSAPrivateCrtKeySpec(modulus, publicExp, privateExp, prime1, prime2, exp1, exp2, crtCoef); - - try { - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PrivateKey privateKey = keyFactory.generatePrivate(spec); - - Signature signature = Signature.getInstance("SHA256withRSA"); - signature.initSign(privateKey); - signature.update(data.getBytes(CHARSET)); - byte[] signBytes = signature.sign(); - - return Base64.encodeBase64String(signBytes).replaceAll("\n|\r", ""); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } catch (InvalidKeySpecException e) { - e.printStackTrace(); - } catch (InvalidKeyException e) { - e.printStackTrace(); - } catch (SignatureException e) { - e.printStackTrace(); - } - - return null; - } -} diff --git a/src/main/java/com/pingplusplus/net/ChargeDeserializer.java b/src/main/java/com/pingplusplus/net/ChargeDeserializer.java deleted file mode 100644 index cca138b..0000000 --- a/src/main/java/com/pingplusplus/net/ChargeDeserializer.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.pingplusplus.net; - -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import com.pingplusplus.model.App; -import com.pingplusplus.model.Charge; -import com.pingplusplus.model.ChargeRefundCollection; - -import java.lang.reflect.Type; - -/** - * Created by afon on 14/11/25. - */ -public class ChargeDeserializer implements JsonDeserializer { - - @Override - public Charge deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { - - JsonObject chargeJson = jsonElement.getAsJsonObject(); - if (null != chargeJson.getAsJsonObject("credential")) { - JsonObject credentialJson = chargeJson.getAsJsonObject("credential"); - if (null != credentialJson.getAsJsonObject("wx")) { - JsonObject wx = credentialJson.getAsJsonObject("wx"); - Long timeStamp = wx.get("timeStamp").getAsLong(); - wx.addProperty("timeStamp", "" + timeStamp); - } else if (null != credentialJson.getAsJsonObject("wx_pub")) { - JsonObject wxPub = credentialJson.getAsJsonObject("wx_pub"); - if (null == wxPub.get("signed_data") && wxPub.get("timeStamp") != null) { - Long timeStamp = wxPub.get("timeStamp").getAsLong(); - wxPub.addProperty("timeStamp", "" + timeStamp); - } - } else if (null != credentialJson.getAsJsonObject("bfb")) { - JsonObject bfb = credentialJson.getAsJsonObject("bfb"); - Long total_amount = bfb.get("total_amount").getAsLong(); - bfb.addProperty("total_amount", total_amount + ""); - } - } - - Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES). - registerTypeAdapter(ChargeRefundCollection.class, new ChargeRefundCollectionDeserializer()) - .create(); - JsonElement appElement = chargeJson.get("app"); - Charge charge = gson.fromJson(jsonElement, Charge.class); - - if (null != appElement && appElement.isJsonObject()) { - App app = gson.fromJson(appElement, App.class); - charge.setApp(app); - } - return charge; - } -} diff --git a/src/main/java/com/pingplusplus/net/ChargeRefundCollectionDeserializer.java b/src/main/java/com/pingplusplus/net/ChargeRefundCollectionDeserializer.java deleted file mode 100644 index 2eb7b43..0000000 --- a/src/main/java/com/pingplusplus/net/ChargeRefundCollectionDeserializer.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.pingplusplus.net; - -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; -import com.google.gson.JsonElement; -import com.google.gson.JsonParseException; -import com.google.gson.reflect.TypeToken; -import com.pingplusplus.model.ChargeRefundCollection; -import com.pingplusplus.model.Refund; - -import java.lang.reflect.Type; -import java.util.List; - -public class ChargeRefundCollectionDeserializer implements JsonDeserializer { - - public ChargeRefundCollection deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - Gson gson = new GsonBuilder() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .create(); - - // API versions 2014-05-19 and earlier render charge refunds as an array instead of an object - if (json.isJsonArray()) { - Type refundListType = new TypeToken>() { - }.getType(); - List refunds = gson.fromJson(json, refundListType); - ChargeRefundCollection collection = new ChargeRefundCollection(); - collection.setData(refunds); - collection.setHasMore(false); - //collection.setTotalCount(refunds.size()); - return collection; - } - - return gson.fromJson(json, typeOfT); - } -}