├── .gitignore
├── .travis.yml
├── API.md
├── LICENSE.md
├── README.md
├── alipay.png
├── pom.xml
├── wechat.png
├── wepay-core
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── me
│ │ └── hao0
│ │ └── wepay
│ │ ├── annotation
│ │ └── Optional.java
│ │ ├── core
│ │ ├── Bills.java
│ │ ├── Component.java
│ │ ├── Notifies.java
│ │ ├── Orders.java
│ │ ├── Pays.java
│ │ ├── Refunds.java
│ │ ├── Wepay.java
│ │ └── WepayBuilder.java
│ │ ├── exception
│ │ ├── SignException.java
│ │ └── WepayException.java
│ │ ├── model
│ │ ├── bill
│ │ │ ├── Bill.java
│ │ │ ├── BillCount.java
│ │ │ ├── BillDetail.java
│ │ │ ├── BillFields.java
│ │ │ ├── CommonBill.java
│ │ │ └── RefundBill.java
│ │ ├── common
│ │ │ └── Coupon.java
│ │ ├── enums
│ │ │ ├── BillType.java
│ │ │ ├── FeeType.java
│ │ │ ├── RefundChannel.java
│ │ │ ├── RefundStatus.java
│ │ │ ├── TradeState.java
│ │ │ ├── TradeType.java
│ │ │ └── WepayField.java
│ │ ├── order
│ │ │ └── WePayOrder.java
│ │ ├── pay
│ │ │ ├── AppPayResponse.java
│ │ │ ├── JsPayRequest.java
│ │ │ ├── JsPayResponse.java
│ │ │ ├── PayRequest.java
│ │ │ ├── QrPayRequest.java
│ │ │ └── QrPayResponse.java
│ │ └── refund
│ │ │ ├── RefundApplyRequest.java
│ │ │ ├── RefundApplyResponse.java
│ │ │ ├── RefundItem.java
│ │ │ └── RefundQueryResponse.java
│ │ ├── serializer
│ │ ├── BooleanDeserializer.java
│ │ ├── DateDeserializer.java
│ │ ├── FeeTypeDeserializer.java
│ │ ├── RefundChannelDeserializer.java
│ │ ├── TradeStateDeserializer.java
│ │ └── TradeTypeDeserializer.java
│ │ └── util
│ │ ├── Maps.java
│ │ └── RandomStrs.java
│ └── test
│ └── java
│ └── me
│ └── hao0
│ └── wepay
│ └── WepayTest.java
└── wepay-demo
├── pom.xml
└── src
└── main
├── java
└── me
│ └── hao0
│ └── wepay
│ └── demo
│ ├── controller
│ ├── Notifies.java
│ ├── Pays.java
│ └── Refunds.java
│ └── support
│ └── WepaySupport.java
├── resources
├── app-example.properties
├── logback.xml
└── spring
│ ├── root-context.xml
│ └── web-context.xml
└── webapp
└── WEB-INF
└── web.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled source #
2 | ###################
3 | *.com
4 | *.class
5 | *.dll
6 | *.exe
7 | *.o
8 | *.so
9 | server_log_home_IS_UNDEFINED
10 |
11 | # Packages #
12 | ############
13 | # it's better to unpack these files and commit the raw source
14 | # git has its own built in compression methods
15 | *.7z
16 | *.dmg
17 | *.gz
18 | *.iso
19 | *.jar
20 | *.rar
21 | *.tar
22 | *.zip
23 |
24 | # Logs and databases #
25 | ######################
26 | *.log
27 |
28 | # OS generated files #
29 | ######################
30 | .DS_Store*
31 | ehthumbs.db
32 | #Icon?
33 | Thumbs.db
34 |
35 | # Editor Files #
36 | ################
37 | *~
38 | *.swp
39 |
40 | # Gradle Files #
41 | ################
42 | .gradle
43 |
44 | # Build output directies
45 | /target
46 | */target
47 | /build
48 | */build
49 | /generated-sources
50 | */generated-sources
51 | *Thunderbolt/core/generated-sources/*
52 | var
53 | logs
54 |
55 | .idea
56 | # IntelliJ specific files/directories
57 | out
58 | .idea/*
59 | *.ipr
60 | *.iws
61 | *.iml
62 | atlassian-ide-plugin.xml
63 |
64 | # Eclipse specific files/directories
65 | .classpath
66 | .project
67 | .settings
68 | .metadata
69 | .recommenders
70 |
71 | # NetBeans specific files/directories
72 | .nbattrs
73 | *.orig
74 | service-location/service-location/*
75 | service-base/service-base/*
76 | service-coupon/service-coupon/*
77 | service-courier/service-courier/*
78 | service-demo/service-demo/*
79 | service-sms/service-sms/*
80 | service-user/service-user/*
81 |
82 | dev.properties
83 |
84 | Demo*.java
85 |
86 | *.p12
87 |
88 | app.properties
89 |
90 | pom.xml.versionsBackup
91 |
92 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk8
4 | # - oraclejdk7
5 | - openjdk7
6 |
7 | script: mvn clean package -DskipTests
--------------------------------------------------------------------------------
/API.md:
--------------------------------------------------------------------------------
1 | # Wepay API文档
2 |
3 | + 已实现组件:
4 |
5 | + 支付: pay()
6 | + 退款: refund()
7 | + 订单: order()
8 | + 通知: notify()
9 | + 账单: bill()
10 |
11 | + **支付pay()**:
12 |
13 | ```java
14 | /**
15 | * JS支付(公众号支付)
16 | * @param request 支付请求对象
17 | * @return JsPayResponse对象,或抛WepayException
18 | */
19 | JsPayResponse jsPay(JsPayRequest request);
20 |
21 | /**
22 | * 动态二维码支付(NATIVE)[模式二]
23 | * @param request 支付请求对象
24 | * @param convert 是否转换为二维码图片链接(使用联图)
25 | * @return 可访问的二维码链接,或抛WepayException
26 | */
27 | QrPayResponse qrPay(QrPayRequest request, Boolean convert);
28 |
29 | /**
30 | * app支付
31 | * @param request 支付请求对象
32 | * @return AppPayResponse对象,或抛WepayException
33 | */
34 | AppPayResponse appPay(PayRequest request);
35 | ```
36 |
37 | + **退款refund()**:
38 |
39 | ```java
40 | /**
41 | * 申请退款
42 | * @param request 退款请求对象
43 | * @return RefundResponse对象,或抛WepayException
44 | */
45 | RefundApplyResponse apply(RefundApplyRequest request);
46 |
47 | /**
48 | * 通过商户订单号查询退款
49 | * @param outTradeNo 商户订单号
50 | * @return 退款查询对象,或抛WepayException
51 | */
52 | RefundQueryResponse queryByOutTradeNo(String outTradeNo);
53 |
54 | /**
55 | * 通过商户退款单号查询退款
56 | * @param outRefundNo 商户退款单号
57 | * @return 退款查询对象,或抛WepayException
58 | */
59 | RefundQueryResponse queryByOutRefundNo(String outRefundNo);
60 |
61 | /**
62 | * 通过微信订单号查询退款
63 | * @param transactionId 微信订单号
64 | * @return 退款查询对象,或抛WepayException
65 | */
66 | RefundQueryResponse queryByTransactionId(String transactionId);
67 |
68 | /**
69 | * 通过微信退款单号查询退款
70 | * @param refundId 微信退款单号
71 | * @return 退款查询对象,或抛WepayException
72 | */
73 | RefundQueryResponse queryByRefundId(String refundId);
74 | ```
75 |
76 | + **订单order()**:
77 |
78 | ```java
79 | /**
80 | * 根据微信订单号查询订单
81 | * @param transactionId 微信订单号
82 | * @return PayOrder对象,或抛WepayException
83 | */
84 | WePayOrder queryByTransactionId(String transactionId);
85 |
86 | /**
87 | * 根据商户订单号查询订单
88 | * @param outTradeNo 商户订单号
89 | * @return PayOrder对象,或抛WepayException
90 | */
91 | WePayOrder queryByOutTradeNo(String outTradeNo);
92 |
93 | /**
94 | * 关闭订单
95 | * @param outTradeNo 商户订单号
96 | * @return 关闭成功返回true,或抛WepayException
97 | */
98 | Boolean closeOrder(String outTradeNo);
99 |
100 | ```
101 |
102 | + **通知notify()**:
103 |
104 | ```java
105 | /**
106 | * 签名校验
107 | * @param params 待验证参数(包含sign)
108 | * @return 验证通过返回true,反之false
109 | */
110 | Boolean verifySign(Map params);
111 |
112 | /**
113 | * 通知成功
114 | * @return 通知成功的XML消息
115 | */
116 | String ok();
117 |
118 | /**
119 | * 通知不成功
120 | * @param errMsg 失败消息
121 | * @return 通知失败的XML消息
122 | */
123 | String notOk(String errMsg);
124 | ```
125 |
126 | + **通知bill()**:
127 |
128 | ```java
129 | /**
130 | * 查询所有账单
131 | * @param deviceInfo 微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单
132 | * @param date 账单的日期
133 | * @return 账单明细
134 | */
135 | BillDetail queryAll(String deviceInfo, String date);
136 |
137 | /**
138 | * 查询交易成功的账单
139 | * @param deviceInfo 微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单
140 | * @param date 账单的日期
141 | * @return 账单明细
142 | */
143 | BillDetail querySuccess(String deviceInfo, String date);
144 |
145 | /**
146 | * 查询退款账单
147 | * @param deviceInfo 微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单
148 | * @param date 账单的日期
149 | * @return 账单明细
150 | */
151 | BillDetail queryRefund(String deviceInfo, String date);
152 | ```
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Being simple
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Wepay[](https://travis-ci.org/ihaolin/wepay)
2 |
3 | 轻量的微信支付组件(A Lightweight Wechat Pay Component)
4 | ---
5 |
6 | + 包引入:
7 |
8 | ```xml
9 |
10 | me.hao0
11 | wepay-core
12 | 1.3.2
13 |
14 | ```
15 |
16 | + 依赖包,注意引入项目时是否需要**exclude**:
17 |
18 | ```xml
19 |
20 | me.hao0
21 | common
22 | 1.1.2
23 |
24 |
25 | ```
26 |
27 | + 基本用法:
28 |
29 | ```java
30 | Wepay wepay = WepayBuilder
31 | .newBuilder(appId, appKey, mchId)
32 | .config1(...) // 其他可选配置
33 | ...
34 | .build();
35 |
36 | wepay.module().api();
37 | ```
38 |
39 | + 已实现的组件:
40 |
41 | + 支付``pay()``;
42 | + 退款``refund()``;
43 | + 订单``order()``;
44 | + 通知``notify()``;
45 | + 账单``bill()``。
46 |
47 | + API文档[这里](API.md)。
48 |
49 | + **关于测试**:
50 |
51 | + [测试用例中](wepay-core/src/test/java/me/hao0/wepay/WepayTest.java)是一些基本测试,需作一些配置:
52 |
53 | ```java
54 | // 在test/reources目录中配置dev.properties
55 | // 包括appId(APP ID), appKey(支付密钥), mchId(商户号)
56 | Properties props = new Properties();
57 | InputStream in = Object.class.getResourceAsStream("/dev.properties");
58 | props.load(in);
59 | in.close();
60 |
61 | // 配置证书,退款需要证书,不配置可测试除退款的接口
62 | Path path = Paths.get("/path/to/your_cert.p12");
63 | byte[] data = Files.readAllBytes(path);
64 |
65 | wepay = WepayBuilder.newBuilder(
66 | props.getProperty("appId"),
67 | props.getProperty("appKey"),
68 | props.getProperty("mchId"))
69 | .certPasswd(props.getProperty("mchId"))
70 | .certs(data)
71 | .build();
72 | ```
73 |
74 | + [wepay-demo](wepay-demo)项目是一个可运行web项目,方便测试,可按如下步骤进行测试,复制[wepay-demo](wepay-demo)中的``app-example.properties``为``app.properties``,并作相应配置:
75 |
76 | ```ruby
77 | # 微信app id
78 | appId=
79 | # 微信支付key
80 | appKey=
81 | # 商户号
82 | mchId=
83 | # 支付通知url
84 | payNotifyUrl=${your_domain}/notifies/paid
85 | ```
86 |
87 | + **注意**:**``payNotifyUrl ``**应该配置为微信服务器可以外网调用的地址,本地测试建议使用[ngrok](https://ngrok.com/)工具来作本地外网映射。
88 |
89 | + 到[wepay-demo](wepay-demo)根目录运行以下命令即可:
90 |
91 | ```bash
92 | mvn clean jetty:run -Dmaven.test.skip -Djetty.port={自定义端口号}
93 | ```
94 |
95 | + 动态二维码支付可访问(**请求正常后,会出现由联图生成的二维码图片,用微信扫描支付成功后,后台会得到对应通知``Notifies``**):
96 |
97 | ```bash
98 | http://localhost:{port}/pays/qrpay?orderNumber={自定义订单号}
99 | ```
100 |
101 | + 退款可访问(**提交成功后,微信会有消息通知**):
102 |
103 | ```bash
104 | http://localhost:{port}/refunds/apply?orderNumber={商户订单号} ```
105 |
106 | + 相关文档:
107 |
108 | + [微信支付文档](https://pay.weixin.qq.com/wiki/doc/api/index.html)。
109 |
110 | + 历史版本:
111 |
112 | + 1.0.0:
113 |
114 | + 基本功能实现。
115 |
116 | + 1.1.0:
117 |
118 | + 增加账单查询。
119 |
120 | + 1.1.1:
121 |
122 | + 修复prepayId。
123 |
124 | + 1.1.2:
125 |
126 | + 修复JS/APP支付签名问题。
127 |
128 | + 1.2.2:
129 |
130 | + 增加退款查询字段: 退款状态, 退款金额, 退款入账方。
131 |
132 | + 1.2.3:
133 |
134 | + fix isNullOrEmpty。
135 |
136 | + 1.2.4:
137 |
138 | + 升级common至1.1.2, 可配置解析微信XML的编码类型, 默认为UTF-8, 防止与本地默认编码不一致。
139 |
140 | + 1.2.5:
141 |
142 | + 二维码支付结果更新为[QrPayResponse](wepay-core/src/main/java/me/hao0/wepay/model/pay/QrPayResponse.java),并增加**prepay_id**字段。
143 |
144 | + 1.3.0:
145 |
146 | + 获取微信响应内容,签名校验失败时,抛出异常[SignException](wepay-core/src/main/java/me/hao0/wepay/exception/SignException.java)。
147 |
148 | + 1.3.1:
149 |
150 | + 修复`goods_tag`字段名。
151 |
152 | + 1.3.2:
153 |
154 | + 修复`clientIp`字段为`clientIp`。
155 |
156 | + 相关组件:
157 |
158 | + 支付宝支付组件;
159 | + 微信公众号组件。
160 |
161 | ## 有事请烧钱
162 |
163 | + 支付宝:
164 |
165 |
166 |
167 | + 微信:
168 |
169 |
170 |
--------------------------------------------------------------------------------
/alipay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ihaolin/wepay/3360b6a57493d879d5a19def833db36fb455f859/alipay.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | me.hao0
8 | wepay
9 | 1.3.2
10 |
11 | wepay-core
12 | wepay-demo
13 |
14 | pom
15 |
16 | wepay
17 | 轻量的微信支付组件(A Lightweight Wechat Pay Component)
18 | https://github.com/ihaolin/wepay
19 |
20 |
21 |
22 | The MIT License (MIT)
23 | https://opensource.org/licenses/MIT
24 |
25 |
26 |
27 |
28 |
29 | haolin
30 | haolin.h0@gmail.com
31 |
32 |
33 |
34 |
35 | scm:git:git@github.com:ihaolin/wepay.git
36 | scm:git:git@github.com:ihaolin/wepay.git
37 | git@github.com:ihaolin/wepay.git
38 |
39 |
40 |
41 |
42 |
43 | org.apache.maven.plugins
44 | maven-compiler-plugin
45 | 2.3.2
46 |
47 | 1.7
48 | 1.7
49 |
50 |
51 |
52 | org.codehaus.mojo
53 | versions-maven-plugin
54 | 2.2
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 | org.codehaus.mojo
63 | findbugs-maven-plugin
64 | 3.0.3
65 |
66 | true
67 | target/site
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | release
76 |
77 |
78 |
79 | org.apache.maven.plugins
80 | maven-source-plugin
81 | 2.2.1
82 |
83 |
84 | package
85 |
86 | jar-no-fork
87 |
88 |
89 |
90 |
91 |
92 |
93 | org.apache.maven.plugins
94 | maven-javadoc-plugin
95 | 2.10.3
96 |
97 |
98 | package
99 |
100 | jar
101 |
102 |
103 |
104 |
105 |
106 |
107 | org.apache.maven.plugins
108 | maven-gpg-plugin
109 | 1.6
110 |
111 |
112 | verify
113 |
114 | sign
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | oss
124 | https://oss.sonatype.org/content/repositories/snapshots/
125 |
126 |
127 | oss
128 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/wechat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ihaolin/wepay/3360b6a57493d879d5a19def833db36fb455f859/wechat.png
--------------------------------------------------------------------------------
/wepay-core/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | wepay
5 | me.hao0
6 | 1.3.2
7 |
8 | 4.0.0
9 |
10 | 1.3.2
11 | wepay-core
12 | jar
13 |
14 | wepay-core
15 | http://maven.apache.org
16 |
17 |
18 | UTF-8
19 |
20 |
21 |
22 |
23 |
24 | me.hao0
25 | common
26 | 1.1.2
27 |
28 |
29 |
30 | junit
31 | junit
32 | 4.11
33 | test
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/annotation/Optional.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.annotation;
2 |
3 | /**
4 | * 标记字段是可选的
5 | * Author: haolin
6 | * Email: haolin.h0@gmail.com
7 | * Date: 11/11/15
8 | * @since 1.0.0
9 | */
10 | public @interface Optional {
11 |
12 | /**
13 | * 是否任何情况下都可选
14 | * @return optional or not
15 | */
16 | boolean any() default true;
17 | }
18 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/core/Bills.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.core;
2 |
3 | import me.hao0.common.http.Http;
4 | import me.hao0.common.json.Jsons;
5 | import me.hao0.common.xml.XmlReaders;
6 | import me.hao0.wepay.exception.WepayException;
7 | import me.hao0.wepay.model.bill.Bill;
8 | import me.hao0.wepay.model.bill.BillCount;
9 | import me.hao0.wepay.model.bill.BillDetail;
10 | import me.hao0.wepay.model.bill.BillFields;
11 | import me.hao0.wepay.model.bill.CommonBill;
12 | import me.hao0.wepay.model.bill.RefundBill;
13 | import me.hao0.wepay.model.enums.BillType;
14 | import me.hao0.wepay.model.enums.WepayField;
15 | import me.hao0.wepay.util.Maps;
16 | import me.hao0.wepay.util.RandomStrs;
17 | import java.util.ArrayList;
18 | import java.util.HashMap;
19 | import java.util.List;
20 | import java.util.Map;
21 | import java.util.TreeMap;
22 | import static me.hao0.common.util.Preconditions.*;
23 |
24 | /**
25 | * 账单组件
26 | * Author: haolin
27 | * Email: haolin.h0@gmail.com
28 | * Date: 4/12/15
29 | * @since 1.1.0
30 | */
31 | public class Bills extends Component {
32 |
33 | /**
34 | * 下载账单
35 | */
36 | private static final String DOWNLOAD = "https://api.mch.weixin.qq.com/pay/downloadbill";
37 |
38 | private static final String LINE_SEPARATOR = "\\n";
39 |
40 | private static final String FIELD_SEPARATOR = ",`";
41 |
42 | Bills(Wepay wepay) {
43 | super(wepay);
44 | }
45 |
46 | /**
47 | * 查询所有账单
48 | * @param deviceInfo 微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单
49 | * @param date 账单的日期
50 | * @return 账单明细
51 | */
52 | public BillDetail queryAll(String deviceInfo, String date){
53 | String data = query(deviceInfo, date, BillType.ALL);
54 | return renderBillDetail(data, BillFields.ALL, CommonBill.class);
55 | }
56 |
57 | /**
58 | * 查询交易成功账单
59 | * @param deviceInfo 微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单
60 | * @param date 账单的日期
61 | * @return 账单明细
62 | */
63 | public BillDetail querySuccess(String deviceInfo, String date){
64 | String data = query(deviceInfo, date, BillType.SUCCESS);
65 | return renderBillDetail(data, BillFields.SUCCESS, Bill.class);
66 | }
67 |
68 | /**
69 | * 查询退款账单
70 | * @param deviceInfo 微信支付分配的终端设备号,填写此字段,只下载该设备号的对账单
71 | * @param date 账单的日期
72 | * @return 账单明细
73 | */
74 | public BillDetail queryRefund(String deviceInfo, String date){
75 | String data = query(deviceInfo, date, BillType.REFUND);
76 | return renderBillDetail(data, BillFields.REFUND, RefundBill.class);
77 | }
78 |
79 | @SuppressWarnings("unchecked")
80 | private BillDetail renderBillDetail(String billData, List fields, Class billClazz) {
81 | String[] dataLines = billData.split(LINE_SEPARATOR);
82 | if (dataLines.length > 0){
83 | List bills = new ArrayList<>();
84 | T bill;
85 | for (int i = 1; i(bills, count);
92 | }
93 | return BillDetail.empty();
94 | }
95 |
96 | private BillCount renderCount(String countData) {
97 | // remove first `
98 | countData = countData.substring(1).replaceAll("\\r", "");
99 | String[] fieldVals = countData.split(FIELD_SEPARATOR);
100 | Map billCount = new HashMap<>();
101 | List fieldNames = BillFields.COUNT;
102 | for (int i = 0; i T renderBill(String dataLine, List fieldNames, Class billClazz) {
109 | // remove first `
110 | dataLine = dataLine.substring(1).replaceAll("\\r", "");
111 | String[] fieldVals = dataLine.split(FIELD_SEPARATOR);
112 | Map billData = new HashMap<>();
113 | for (int i = 0; i downloadParams = buildDownloadParams(deviceInfo, date, type);
131 | String billData = Http.post(DOWNLOAD).body(Maps.toXml(downloadParams)).request();
132 | if (billData.startsWith("")){
133 | XmlReaders readers = XmlReaders.create(billData);
134 | throw new WepayException(
135 | readers.getNodeStr(WepayField.RETURN_CODE),
136 | readers.getNodeStr(WepayField.RETURN_MSG));
137 | }
138 | return billData;
139 | }
140 |
141 |
142 | private Map buildDownloadParams(String deviceInfo, String date, BillType type) {
143 | Map downloadParams = new TreeMap<>();
144 |
145 | buildConfigParams(downloadParams);
146 |
147 | put(downloadParams, WepayField.NONCE_STR, RandomStrs.generate(16));
148 | put(downloadParams, WepayField.BILL_TYPE, type.type());
149 | put(downloadParams, WepayField.BILL_DATE, date);
150 |
151 | putIfNotEmpty(downloadParams, WepayField.DEVICE_INFO, deviceInfo);
152 |
153 | buildSignParams(downloadParams);
154 |
155 | return downloadParams;
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/core/Component.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.core;
2 |
3 | import me.hao0.common.http.Http;
4 | import me.hao0.common.http.Https;
5 | import me.hao0.common.json.Jsons;
6 | import me.hao0.common.security.MD5;
7 | import me.hao0.common.util.Strings;
8 | import me.hao0.common.xml.XmlReaders;
9 | import me.hao0.wepay.exception.SignException;
10 | import me.hao0.wepay.exception.WepayException;
11 | import me.hao0.wepay.model.enums.WepayField;
12 | import me.hao0.wepay.util.Maps;
13 | import java.util.Map;
14 | import java.util.TreeMap;
15 |
16 | /**
17 | * Author: haolin
18 | * Email: haolin.h0@gmail.com
19 | * Date: 26/11/15
20 | */
21 | public abstract class Component {
22 |
23 | protected Wepay wepay;
24 |
25 | protected Component(Wepay wepay){
26 | this.wepay = wepay;
27 | }
28 |
29 | protected Map doPost(final String url, final Map params){
30 | String requestBody = Maps.toXml(params);
31 | String resp = Http.post(url).ssl().body(requestBody).request();
32 | Map respMap = toMap(resp.replaceAll("(\\r|\\n)", ""));
33 | if (!doVerifySign(respMap)){
34 | throw new SignException("微信响应内容签名非法: " + respMap);
35 | }
36 | return respMap;
37 | }
38 |
39 | protected T doHttpsPost(final String url, final Map params, Class respClazz){
40 | String requestBody = Maps.toXml(params);
41 | String resp = Https.post(url).body(requestBody)
42 | .ssLSocketFactory(wepay.getSslSocketFactory()).request();
43 | Map respMap = toMap(resp.replaceAll("(\\r|\\n)", ""));
44 | if (!doVerifySign(respMap)){
45 | throw new SignException("微信响应内容签名非法: " + respMap);
46 | }
47 | return Jsons.DEFAULT.fromJson(Jsons.DEFAULT.toJson(respMap), respClazz);
48 | }
49 |
50 |
51 | /**
52 | * 将微信XML转换为Map
53 | * @param xml xml字符串
54 | * @return Map对象,或抛WechatException
55 | */
56 | protected Map toMap(final String xml) {
57 | XmlReaders readers = readResp(xml);
58 | return Maps.toMap(readers);
59 | }
60 |
61 | /**
62 | * 读取微信xml响应
63 | * @param xml xml字符串
64 | * @return 若成功,返回对应Reader,反之抛WepayException
65 | */
66 | private XmlReaders readResp(final String xml) {
67 | XmlReaders readers = XmlReaders.create(xml, wepay.respEncode);
68 | String returnCode = readers.getNodeStr(WepayField.RETURN_CODE);
69 | if (WepayField.SUCCESS.equals(returnCode)){
70 | String resultCode = readers.getNodeStr(WepayField.RESULT_CODE);
71 | if (WepayField.SUCCESS.equals(resultCode)){
72 | return readers;
73 | }
74 | throw new WepayException(
75 | readers.getNodeStr(WepayField.ERR_CODE),
76 | readers.getNodeStr(WepayField.ERR_CODE_DES));
77 | }
78 | throw new WepayException(
79 | readers.getNodeStr(WepayField.RETURN_CODE),
80 | readers.getNodeStr(WepayField.RETURN_MSG));
81 | }
82 |
83 | /**
84 | * 构建配置参数
85 | * @param params 参数
86 | */
87 | protected void buildConfigParams(final Map params){
88 | params.put(WepayField.APP_ID, wepay.getAppId());
89 | params.put(WepayField.MCH_ID, wepay.getMchId());
90 | }
91 |
92 | /**
93 | * 构建签名参数
94 | * @param params 支付参数
95 | */
96 | protected void buildSignParams(final Map params) {
97 | String sign = doSign(params);
98 | put(params, WepayField.SIGN, sign);
99 | }
100 |
101 | /**
102 | * 支付请求前签名
103 | * @param params 参数(已经升序, 排出非空值和sign)
104 | * @return MD5的签名字符串(大写)
105 | */
106 | protected String doSign(final Map params) {
107 | StringBuilder signing = new StringBuilder();
108 |
109 | for (Map.Entry entry : params.entrySet()) {
110 | if (!Strings.isNullOrEmpty(entry.getValue())){
111 | signing.append(entry.getKey()).append('=').append(entry.getValue()).append("&");
112 | }
113 | }
114 |
115 | // append key
116 | signing.append("key=").append(wepay.getAppKey());
117 |
118 | // md5
119 | return MD5.generate(signing.toString(), false).toUpperCase();
120 | }
121 |
122 | /**
123 | * 校验参数
124 | * @param data 待校验参数
125 | * @return 校验成功返回true,反之false
126 | */
127 | protected Boolean doVerifySign(final Map data) {
128 | String actualSign = String.valueOf(data.get(WepayField.SIGN));
129 | Map signingMap = filterSignParams(data);
130 | String expectSign = doSign(signingMap);
131 | return expectSign.equals(actualSign);
132 | }
133 |
134 | /**
135 | * 过滤签名参数(升序,排出空值,sign)
136 | * @param params 待校验参数
137 | * @return 过滤后的参数
138 | */
139 | protected Map filterSignParams(final Map params) {
140 | Map validParams = new TreeMap<>();
141 |
142 | for (Map.Entry param : params.entrySet()){
143 | if (WepayField.SIGN.equals(param.getKey())
144 | || param.getValue() == null
145 | || "".equals(String.valueOf(param.getValue()))){
146 | continue;
147 | }
148 | validParams.put(param.getKey(), String.valueOf(param.getValue()));
149 | }
150 |
151 | return validParams;
152 | }
153 |
154 | protected void putIfNotEmpty(final Map map, String field, String paramValue) {
155 | if (!Strings.isNullOrEmpty(paramValue)){
156 | map.put(field, paramValue);
157 | }
158 | }
159 |
160 | protected void put(final Map map, String field, String paramValue){
161 | map.put(field, paramValue);
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/core/Notifies.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.core;
2 |
3 | import me.hao0.wepay.model.enums.WepayField;
4 | import me.hao0.wepay.util.Maps;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /**
10 | * 通知组件
11 | * Author: haolin
12 | * Email: haolin.h0@gmail.com
13 | * Date: 28/11/15
14 | * @since 1.0.0
15 | */
16 | public class Notifies extends Component {
17 |
18 | Notifies(Wepay wepay) {
19 | super(wepay);
20 | }
21 |
22 | /**
23 | * 签名校验
24 | * @param params 待验证参数(包含sign)
25 | * @return 验证通过返回true,反之false
26 | */
27 | public Boolean verifySign(Map params){
28 | return doVerifySign(params);
29 | }
30 |
31 | /**
32 | * 通知成功
33 | * @return 通知成功的XML消息
34 | */
35 | public String ok(){
36 | Map notifyParams = new HashMap<>();
37 | notifyParams.put(WepayField.RETURN_CODE, "SUCCESS");
38 | notifyParams.put(WepayField.RETURN_MSG, "OK");
39 | return Maps.toXml(notifyParams);
40 | }
41 |
42 | /**
43 | * 通知不成功
44 | * @param errMsg 失败消息
45 | * @return 通知失败的XML消息
46 | */
47 | public String notOk(String errMsg){
48 | Map notifyParams = new HashMap<>();
49 | notifyParams.put(WepayField.RETURN_CODE, "FAIL");
50 | notifyParams.put(WepayField.RETURN_MSG, errMsg);
51 | return Maps.toXml(notifyParams);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/core/Orders.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.core;
2 |
3 | import me.hao0.common.json.Jsons;
4 | import me.hao0.wepay.model.common.Coupon;
5 | import me.hao0.wepay.model.enums.WepayField;
6 | import me.hao0.wepay.model.order.WePayOrder;
7 | import me.hao0.wepay.util.RandomStrs;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import java.util.Map;
11 | import java.util.TreeMap;
12 | import static me.hao0.common.util.Preconditions.*;
13 |
14 | /**
15 | * 订单组件
16 | * Author: haolin
17 | * Email: haolin.h0@gmail.com
18 | * Date: 27/11/15
19 | * @since 1.0.0
20 | */
21 | public final class Orders extends Component {
22 |
23 | /**
24 | * 查询订单
25 | */
26 | private static final String ORDER_QUERY = "https://api.mch.weixin.qq.com/pay/orderquery";
27 |
28 | /**
29 | * 关闭订单
30 | */
31 | private static final String ORDER_CLOSE = "https://api.mch.weixin.qq.com/pay/closeorder";
32 |
33 | Orders(Wepay wepay) {
34 | super(wepay);
35 | }
36 |
37 | /**
38 | * 根据微信订单号查询订单
39 | * @param transactionId 微信订单号
40 | * @return PayOrder对象,或抛WepayException
41 | */
42 | public WePayOrder queryByTransactionId(String transactionId){
43 | checkNotNullAndEmpty(transactionId, "transactionId");
44 | Map queryParams = new TreeMap<>();
45 | put(queryParams, WepayField.TRANSACTION_ID, transactionId);
46 | return doQueryOrder(queryParams);
47 | }
48 |
49 | /**
50 | * 根据商户订单号查询订单
51 | * @param outTradeNo 商户订单号
52 | * @return PayOrder对象,或抛WepayException
53 | */
54 | public WePayOrder queryByOutTradeNo(String outTradeNo){
55 | checkNotNullAndEmpty(outTradeNo, "outTradeNo");
56 | Map queryParams = new TreeMap<>();
57 | put(queryParams, WepayField.OUT_TRADE_NO, outTradeNo);
58 | return doQueryOrder(queryParams);
59 | }
60 |
61 | private WePayOrder doQueryOrder(Map queryParams) {
62 | buildQueryParams(queryParams);
63 | Map orderData = doPost(ORDER_QUERY, queryParams);
64 | WePayOrder order = Jsons.DEFAULT.fromJson(Jsons.DEFAULT.toJson(orderData), WePayOrder.class);
65 | setCoupons(order, orderData);
66 | return order;
67 | }
68 |
69 | private void setCoupons(WePayOrder order, Map orderData) {
70 | if (order != null
71 | && order.getCouponCount() != null
72 | && order.getCouponCount() > 0){
73 | List coupons = new ArrayList<>();
74 | Coupon coupon;
75 | for (int couponIndex = 0; couponIndex < order.getCouponCount(); couponIndex++){
76 | coupon = Coupon.newCoupon(
77 | (String)orderData.get(WepayField.COUPON_BATCH_ID + "_" + couponIndex),
78 | (String) orderData.get(WepayField.COUPON_ID + "_" + couponIndex),
79 | Integer.parseInt((String) orderData.get(WepayField.COUPON_FEE + "_" + couponIndex))
80 | );
81 | coupons.add(coupon);
82 | }
83 | order.setCoupons(coupons);
84 | }
85 | }
86 |
87 | /**
88 | * 关闭订单
89 | * @param outTradeNo 商户订单号
90 | * @return 关闭成功返回true,或抛WepayException
91 | */
92 | public Boolean closeOrder(String outTradeNo){
93 | checkNotNullAndEmpty(outTradeNo, "outTradeNo");
94 | Map closeParams = new TreeMap<>();
95 | put(closeParams, WepayField.OUT_TRADE_NO, outTradeNo);
96 | buildCloseParams(closeParams);
97 | return doPost(ORDER_CLOSE, closeParams) != null;
98 | }
99 |
100 | /**
101 | * 构建关闭订单参数
102 | * @param closeParams 关闭参数
103 | */
104 | private void buildCloseParams(Map closeParams) {
105 | buildConfigParams(closeParams);
106 | put(closeParams, WepayField.NONCE_STR, RandomStrs.generate(16));
107 | buildSignParams(closeParams);
108 | }
109 |
110 | /**
111 | * 构建查询订单参数
112 | * @param queryParams 查询参数
113 | */
114 | private void buildQueryParams(Map queryParams) {
115 | buildConfigParams(queryParams);
116 | put(queryParams, WepayField.NONCE_STR, RandomStrs.generate(16));
117 | buildSignParams(queryParams);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/core/Pays.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.core;
2 |
3 | import me.hao0.common.date.Dates;
4 | import me.hao0.common.security.MD5;
5 | import me.hao0.wepay.exception.WepayException;
6 | import me.hao0.wepay.model.enums.TradeType;
7 | import me.hao0.wepay.model.enums.WepayField;
8 | import me.hao0.wepay.model.pay.AppPayResponse;
9 | import me.hao0.wepay.model.pay.JsPayRequest;
10 | import me.hao0.wepay.model.pay.JsPayResponse;
11 | import me.hao0.wepay.model.pay.PayRequest;
12 | import me.hao0.wepay.model.pay.QrPayRequest;
13 | import me.hao0.wepay.model.pay.QrPayResponse;
14 | import me.hao0.wepay.util.RandomStrs;
15 | import java.io.UnsupportedEncodingException;
16 | import java.net.URLEncoder;
17 | import java.util.Map;
18 | import java.util.TreeMap;
19 | import static me.hao0.common.util.Preconditions.*;
20 |
21 | /**
22 | * 支付组件
23 | * Author: haolin
24 | * Email: haolin.h0@gmail.com
25 | * Date: 26/11/15
26 | * @since 1.0.0
27 | */
28 | public final class Pays extends Component {
29 |
30 | /**
31 | * 统一下单接口
32 | */
33 | private static final String PAY_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
34 |
35 | /**
36 | * 联图二维码转换
37 | */
38 | private static final String LIANTU_URL = "http://qr.liantu.com/api.php?text=";
39 |
40 | protected Pays(Wepay wepay) {
41 | super(wepay);
42 | }
43 |
44 | /**
45 | * JS支付(公众号支付)
46 | * @param request 支付请求对象
47 | * @return JsPayResponse对象,或抛WepayException
48 | */
49 | public JsPayResponse jsPay(JsPayRequest request){
50 | checkJsPayParams(request);
51 | Map respData = doJsPay(request, TradeType.JSAPI);
52 | return buildJsPayResp(respData);
53 | }
54 |
55 | /**
56 | * 动态二维码支付(NATIVE)
57 | * @param request 支付请求对象
58 | * @return 使用联图生成的二维码链接,或抛WepayException
59 | */
60 | public QrPayResponse qrPay(QrPayRequest request){
61 | return qrPay(request, Boolean.TRUE);
62 | }
63 |
64 | /**
65 | * 动态二维码支付(NATIVE)
66 | * @param request 支付请求对象
67 | * @param convert 是否转换为二维码图片链接(使用联图)
68 | * @return 可访问的二维码链接,或抛WepayException
69 | */
70 | public QrPayResponse qrPay(QrPayRequest request, Boolean convert){
71 |
72 | checkPayParams(request);
73 |
74 | Map respData = doQrPay(request, TradeType.NATIVE);
75 |
76 | String codeUrl = String.valueOf(respData.get(WepayField.CODE_URL));
77 | if (convert){
78 | try {
79 | codeUrl = LIANTU_URL + URLEncoder.encode(codeUrl, "UTF-8");
80 | } catch (UnsupportedEncodingException e) {
81 | throw new WepayException(e);
82 | }
83 | }
84 |
85 | String prepayId = String.valueOf(respData.get(WepayField.PREPAY_ID));
86 |
87 | QrPayResponse resp = new QrPayResponse();
88 | resp.setCodeUrl(codeUrl);
89 | resp.setPrepayId(prepayId);
90 |
91 | return resp;
92 | }
93 |
94 | /**
95 | * app支付
96 | * @param request 支付请求对象
97 | * @return AppPayResponse对象,或抛WepayException
98 | */
99 | public AppPayResponse appPay(PayRequest request){
100 | checkPayParams(request);
101 | Map respData = doAppPay(request, TradeType.APP);
102 | return buildAppPayResp(respData);
103 | }
104 |
105 | /**
106 | * JS支付
107 | * @param request 支付信息
108 | * @return 支付结果
109 | */
110 | private Map doJsPay(JsPayRequest request, TradeType tradeType){
111 | Map payParams = buildPayParams(request, tradeType);
112 | payParams.put(WepayField.OPEN_ID, request.getOpenId());
113 | return doPay(payParams);
114 | }
115 |
116 | /**
117 | * APP支付
118 | * @param request 支付信
119 | * @return 支付结
120 | */
121 | private Map doAppPay(PayRequest request, TradeType tradeType){
122 | Map payParams = buildPayParams(request, tradeType);
123 | return doPay(payParams);
124 | }
125 |
126 | /**
127 | * 二维码支付
128 | * @param request 支付信息
129 | * @return 支付结果
130 | */
131 | private Map doQrPay(QrPayRequest request, TradeType tradeType){
132 | Map payParams = buildPayParams(request, tradeType);
133 | putIfNotEmpty(payParams, WepayField.PRODUCT_ID, request.getProductId());
134 | return doPay(payParams);
135 | }
136 |
137 | private Map doPay(Map payParams) {
138 | buildSignParams(payParams);
139 | return doPost(PAY_URL, payParams);
140 | }
141 |
142 | private JsPayResponse buildJsPayResp(Map data) {
143 |
144 | String appId = wepay.getAppId();
145 | String nonceStr = RandomStrs.generate(16);
146 | String timeStamp = String.valueOf(Dates.now().getTime() / 1000);
147 | String pkg = WepayField.PREPAY_ID + "=" +
148 | data.get(WepayField.PREPAY_ID);
149 |
150 | String signing =
151 | WepayField.APPID + "=" + appId +
152 | "&"+ WepayField.NONCESTR2 +"=" + nonceStr +
153 | "&" + WepayField.PKG + "=" + pkg +
154 | "&" + WepayField.SIGN_TYPE + "=MD5" +
155 | "&" + WepayField.TIME_STAMP + "=" + timeStamp +
156 | "&" + WepayField.KEY + "=" + wepay.getAppKey();
157 |
158 | String signed = MD5.generate(signing, false).toUpperCase();
159 |
160 | return new JsPayResponse(appId, timeStamp, nonceStr, pkg, "MD5", signed);
161 | }
162 |
163 | private AppPayResponse buildAppPayResp(Map data) {
164 | String appId = wepay.getAppId();
165 | String partnerId= wepay.getMchId();
166 | String nonceStr = RandomStrs.generate(16);
167 | String timeStamp = String.valueOf(Dates.now().getTime() / 1000);
168 | String prepayId = String.valueOf(data.get(WepayField.PREPAY_ID));
169 |
170 | String signing =
171 | WepayField.APP_ID + "=" + appId +
172 | "&"+ WepayField.NONCESTR +"=" + nonceStr +
173 | "&" + WepayField.PKG + "=Sign=WXPay" +
174 | "&" + WepayField.PARTNERID + "=" + partnerId +
175 | "&" + WepayField.PREPAYID + "=" + prepayId +
176 | "&" + WepayField.TIMESTAMP + "=" + timeStamp +
177 | "&" + WepayField.KEY + "=" + wepay.getAppKey();
178 |
179 | String signed = MD5.generate(signing, false).toUpperCase();
180 |
181 | return new AppPayResponse(appId, partnerId, prepayId, timeStamp, nonceStr, signed);
182 | }
183 |
184 | /**
185 | * 检查支付参数合法性
186 | * @param request 支付请求对象
187 | */
188 | private void checkJsPayParams(JsPayRequest request) {
189 | checkPayParams(request);
190 | checkNotNullAndEmpty(request.getOpenId(), "openId");
191 | }
192 |
193 | private void checkPayParams(PayRequest request) {
194 | checkNotNull(request, "pay detail can't be null");
195 | checkNotNullAndEmpty(request.getBody(), "body");
196 | checkNotNullAndEmpty(request.getOutTradeNo(), "outTradeNo");
197 | Integer totalFee = request.getTotalFee();
198 | checkArgument(totalFee != null && totalFee > 0, "totalFee must > 0");
199 | checkNotNullAndEmpty(request.getClientIp(), "clientId");
200 | checkNotNullAndEmpty(request.getNotifyUrl(), "notifyUrl");
201 | checkNotNull(request.getFeeType(), "feeType can't be null");
202 | checkNotNullAndEmpty(request.getTimeStart(), "timeStart");
203 | }
204 |
205 | /**
206 | * 构建公共支付参数
207 | * @param request 支付请求对象
208 | * @param tradeType 交易类型
209 | * @return 支付MAP参数
210 | */
211 | private Map buildPayParams(PayRequest request, TradeType tradeType) {
212 | Map payParams = new TreeMap<>();
213 |
214 | // 配置参数
215 | buildConfigParams(payParams);
216 |
217 | // 业务必需参数
218 | put(payParams, WepayField.BODY, request.getBody());
219 | put(payParams, WepayField.OUT_TRADE_NO, request.getOutTradeNo());
220 | put(payParams, WepayField.TOTAL_FEE, request.getTotalFee() + "");
221 | put(payParams, WepayField.SPBILL_CREATE_IP, request.getClientIp());
222 | put(payParams, WepayField.NOTIFY_URL, request.getNotifyUrl());
223 | put(payParams, WepayField.FEE_TYPE, request.getFeeType().type());
224 | put(payParams, WepayField.NONCE_STR, RandomStrs.generate(16));
225 | put(payParams, WepayField.TIME_START, request.getTimeStart());
226 | put(payParams, WepayField.TRADE_TYPE, tradeType.type());
227 |
228 | // 业务可选参数
229 | putIfNotEmpty(payParams, WepayField.DEVICE_INFO, request.getDeviceInfo());
230 | putIfNotEmpty(payParams, WepayField.ATTACH, request.getAttach());
231 | putIfNotEmpty(payParams, WepayField.DETAIL, request.getDetail());
232 | putIfNotEmpty(payParams, WepayField.GOODS_TAG, request.getGoodsTag());
233 | putIfNotEmpty(payParams, WepayField.TIME_EXPIRE, request.getTimeExpire());
234 | putIfNotEmpty(payParams, WepayField.LIMIT_PAY, request.getLimitPay());
235 |
236 | return payParams;
237 | }
238 | }
239 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/core/Refunds.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.core;
2 |
3 | import me.hao0.common.util.Strings;
4 | import me.hao0.wepay.model.enums.FeeType;
5 | import me.hao0.wepay.model.enums.RefundChannel;
6 | import me.hao0.wepay.model.enums.RefundStatus;
7 | import me.hao0.wepay.model.enums.WepayField;
8 | import me.hao0.wepay.model.refund.RefundApplyRequest;
9 | import me.hao0.wepay.model.refund.RefundApplyResponse;
10 | import me.hao0.wepay.model.common.Coupon;
11 | import me.hao0.wepay.model.refund.RefundItem;
12 | import me.hao0.wepay.model.refund.RefundQueryResponse;
13 | import me.hao0.wepay.util.RandomStrs;
14 |
15 | import java.util.ArrayList;
16 | import java.util.List;
17 | import java.util.Map;
18 | import java.util.TreeMap;
19 |
20 | import static me.hao0.common.util.Preconditions.*;
21 |
22 | /**
23 | * 退款组件
24 | * Author: haolin
25 | * Email: haolin.h0@gmail.com
26 | * Date: 27/11/15
27 | * @since 1.0.0
28 | */
29 | public final class Refunds extends Component {
30 |
31 | /**
32 | * 申请退款
33 | */
34 | private static final String APPLY = "https://api.mch.weixin.qq.com/secapi/pay/refund";
35 |
36 | /**
37 | * 查询退款
38 | */
39 | private static final String QUERY = "https://api.mch.weixin.qq.com/pay/refundquery";
40 |
41 | Refunds(Wepay wepay) {
42 | super(wepay);
43 | }
44 |
45 | /**
46 | * 申请退款
47 | * @param request 退款请求对象
48 | * @return RefundResponse对象,或抛WepayException
49 | */
50 | public RefundApplyResponse apply(RefundApplyRequest request){
51 | checkApplyParams(request);
52 | Map applyParams = buildApplyParams(request);
53 | return doHttpsPost(APPLY, applyParams, RefundApplyResponse.class);
54 | }
55 |
56 | /**
57 | * 通过商户订单号查询退款
58 | * @param outTradeNo 商户订单号
59 | * @return 退款查询对象,或抛WepayException
60 | */
61 | public RefundQueryResponse queryByOutTradeNo(String outTradeNo){
62 | Map queryParams = buildQueryParams(WepayField.OUT_TRADE_NO, outTradeNo);
63 | Map respData = doPost(QUERY, queryParams);
64 | return renderQueryResp(respData);
65 | }
66 |
67 | /**
68 | * 通过商户退款单号查询退款
69 | * @param outRefundNo 商户退款单号
70 | * @return 退款查询对象,或抛WepayException
71 | */
72 | public RefundQueryResponse queryByOutRefundNo(String outRefundNo){
73 | Map queryParams = buildQueryParams(WepayField.OUT_REFUND_NO, outRefundNo);
74 | Map respData = doPost(QUERY, queryParams);
75 | return renderQueryResp(respData);
76 | }
77 |
78 | /**
79 | * 通过微信订单号查询退款
80 | * @param transactionId 微信订单号
81 | * @return 退款查询对象,或抛WepayException
82 | */
83 | public RefundQueryResponse queryByTransactionId(String transactionId){
84 | Map queryParams = buildQueryParams(WepayField.TRANSACTION_ID, transactionId);
85 | Map respData = doPost(QUERY, queryParams);
86 | return renderQueryResp(respData);
87 | }
88 |
89 | /**
90 | * 通过微信退款单号查询退款
91 | * @param refundId 微信退款单号
92 | * @return 退款查询对象,或抛WepayException
93 | */
94 | public RefundQueryResponse queryByRefundId(String refundId){
95 | Map queryParams = buildQueryParams(WepayField.REFUND_ID, refundId);
96 | Map respData = doPost(QUERY, queryParams);
97 | return renderQueryResp(respData);
98 | }
99 |
100 | private RefundQueryResponse renderQueryResp(Map refundData) {
101 | RefundQueryResponse queryResp = new RefundQueryResponse();
102 |
103 | queryResp.setOutTradeNo((String)refundData.get(WepayField.OUT_TRADE_NO));
104 | queryResp.setTransactionId((String)refundData.get(WepayField.TRANSACTION_ID));
105 | queryResp.setTotalFee(Integer.parseInt((String)refundData.get(WepayField.TOTAL_FEE)));
106 | queryResp.setCashFee(Integer.parseInt((String) refundData.get(WepayField.CASH_FEE)));
107 | String feeType = (String)refundData.get(WepayField.FEE_TYPE);
108 | if (!Strings.isNullOrEmpty(feeType)){
109 | queryResp.setFeeType(FeeType.from(feeType));
110 | }
111 |
112 | Integer refundCount = Integer.parseInt((String) refundData.get(WepayField.REFUND_COUNT));
113 |
114 | List refundItems = new ArrayList<>();
115 | RefundItem refundItem;
116 | for (int refundIndex = 0; refundIndex < refundCount; refundIndex++){
117 | refundItem = renderRefundItem(refundData, refundIndex);
118 | refundItems.add(refundItem);
119 | }
120 | queryResp.setItems(refundItems);
121 |
122 | return queryResp;
123 | }
124 |
125 | private RefundItem renderRefundItem(Map refundData, int refundItemIndex) {
126 | RefundItem refundItem = new RefundItem();
127 | refundItem.setOutRefundNo((String)refundData.get(WepayField.OUT_REFUND_NO + "_" + refundItemIndex));
128 | refundItem.setRefundId((String)refundData.get(WepayField.REFUND_ID + "_" + refundItemIndex));
129 | refundItem.setChannel(RefundChannel.from((String) refundData.get(WepayField.REFUND_CHANNEL + "_" + refundItemIndex)));
130 | refundItem.setRefundFee(Integer.parseInt((String)refundData.get(WepayField.REFUND_FEE + "_" + refundItemIndex)));
131 | refundItem.setRefundStatus(RefundStatus.from((String)refundData.get(WepayField.REFUND_STATUS + "_" + refundItemIndex)));
132 |
133 | String settlementRefundFee = (String)refundData.get(WepayField.SETTLEMENT_REFUND_FEE + "_" + refundItemIndex);
134 | if (!Strings.isNullOrEmpty(settlementRefundFee)){
135 | refundItem.setSettlementRefundFee(Integer.parseInt(settlementRefundFee));
136 | }
137 |
138 | refundItem.setRefundRecvAccout((String)refundData.get(WepayField.REFUND_RECV_ACCOUNT + "_" + refundItemIndex));
139 |
140 | Object couponRefundFee = refundData.get(WepayField.COUPON_REFUND_FEE + "_" + refundItemIndex);
141 | if (couponRefundFee != null){
142 | refundItem.setCouponRefundFee(Integer.parseInt((String)couponRefundFee));
143 | }
144 | Object couponRefundCountObj = refundData.get(WepayField.COUPON_REFUND_COUNT + "_" + refundItemIndex);
145 | if (couponRefundCountObj != null){
146 | Integer couponRefundCount = Integer.parseInt((String)couponRefundCountObj);
147 | if (couponRefundCount > 0){
148 | List couponItems = new ArrayList<>();
149 | Coupon couponItem;
150 | for (int couponItemIndex = 0; couponItemIndex < couponRefundCount; couponItemIndex++){
151 | couponItem = Coupon.newCoupon(
152 | (String) refundData.get(WepayField.COUPON_REFUND_BATCH_ID + "_" + refundItemIndex + "_" + couponItemIndex),
153 | (String) refundData.get(WepayField.COUPON_REFUND_ID + "_" + refundItemIndex + "_" + couponItemIndex),
154 | Integer.parseInt((String) refundData.get(WepayField.COUPON_REFUND_FEE + "_" + refundItemIndex + "_" + couponItemIndex))
155 | );
156 | couponItems.add(couponItem);
157 | }
158 | refundItem.setCoupons(couponItems);
159 | }
160 | }
161 |
162 | return refundItem;
163 | }
164 |
165 | /**
166 | * 构建查询退款参数
167 | * @param queryFieldName 查询字段名
168 | * @param queryFieldValue 查询字段值
169 | * @return 查询参数
170 | */
171 | private Map buildQueryParams(String queryFieldName, String queryFieldValue) {
172 | checkNotNullAndEmpty(queryFieldValue, queryFieldName);
173 |
174 | Map queryParams = new TreeMap<>();
175 | buildConfigParams(queryParams);
176 | queryParams.put(WepayField.NONCE_STR, RandomStrs.generate(16));
177 | queryParams.put(queryFieldName, queryFieldValue);
178 | buildSignParams(queryParams);
179 |
180 | return queryParams;
181 | }
182 |
183 | /**
184 | * 校验退款参数
185 | * @param request 退款请求对象
186 | */
187 | private void checkApplyParams(RefundApplyRequest request) {
188 | checkNotNull(wepay.certs, "merchant certs can't be null before apply refund");
189 | checkNotNullAndEmpty(wepay.certPasswd, "certPasswd");
190 | checkNotNull(request, "apply request can't be null");
191 | if (Strings.isNullOrEmpty(request.getTransactionId())){
192 | checkNotNullAndEmpty(request.getOutTradeNo(), "transactionId && outTradeNo");
193 | }
194 | checkNotNullAndEmpty(request.getOutRefundNo(), "outRefundNo");
195 | checkNotNullAndEmpty(request.getOpUserId(), "opUserId");
196 | Integer totalFee = request.getTotalFee();
197 | Integer refundFee = request.getRefundFee();
198 | checkPositive(totalFee, "totalFee");
199 | checkPositive(refundFee, "refundFee");
200 | checkPositive(totalFee - refundFee, "totalFee - refundFee");
201 | }
202 |
203 | /**
204 | * 构建退款参数
205 | * @param request 退款请求
206 | * @return 退款参数
207 | */
208 | private Map buildApplyParams(RefundApplyRequest request) {
209 | Map refundParams = new TreeMap<>();
210 |
211 | // 配置参数
212 | buildConfigParams(refundParams);
213 |
214 | // 业务参数
215 | putIfNotEmpty(refundParams, WepayField.TRANSACTION_ID, request.getTransactionId());
216 | putIfNotEmpty(refundParams, WepayField.OUT_TRADE_NO, request.getOutTradeNo());
217 | put(refundParams, WepayField.OUT_REFUND_NO, request.getOutRefundNo());
218 | put(refundParams, WepayField.TOTAL_FEE, request.getTotalFee() + "");
219 | put(refundParams, WepayField.REFUND_FEE, request.getRefundFee() + "");
220 | put(refundParams, WepayField.NONCE_STR, RandomStrs.generate(16));
221 | put(refundParams, WepayField.OP_USER_ID, request.getOpUserId());
222 | putIfNotEmpty(refundParams, WepayField.DEVICE_INFO, request.getDeviceInfo());
223 | if (request.getRefundFeeType() != null){
224 | put(refundParams, WepayField.REFUND_FEE_TYPE, request.getRefundFeeType().type());
225 | }
226 |
227 | // 签名参数
228 | buildSignParams(refundParams);
229 |
230 | return refundParams;
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/core/Wepay.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.core;
2 |
3 | import me.hao0.common.util.Strings;
4 | import me.hao0.wepay.exception.WepayException;
5 | import javax.net.ssl.KeyManagerFactory;
6 | import javax.net.ssl.SSLContext;
7 | import javax.net.ssl.SSLSocketFactory;
8 | import java.io.ByteArrayInputStream;
9 | import java.io.InputStream;
10 | import java.security.KeyStore;
11 | import java.security.SecureRandom;
12 |
13 | /**
14 | * 微信支付核心类
15 | * Author: haolin
16 | * Email: haolin.h0@gmail.com
17 | * Date: 25/11/15
18 | * @since 1.0.0
19 | */
20 | public final class Wepay {
21 |
22 | /**
23 | * 微信APP ID
24 | */
25 | private final String appId;
26 |
27 | /**
28 | * 微信APP Key
29 | */
30 | private final String appKey;
31 |
32 | /**
33 | * 商户ID
34 | */
35 | private final String mchId;
36 |
37 | /**
38 | * 商户证书数据(p12)
39 | */
40 | byte[] certs;
41 |
42 | /**
43 | * 商户证书密码,默认为商户号mchId
44 | */
45 | String certPasswd;
46 |
47 | /**
48 | * 解析微信XML时, 使用的编码类型
49 | */
50 | String respEncode = "UTF-8";
51 |
52 | private SSLSocketFactory sslSocketFactory;
53 |
54 | /**
55 | * 支付组件
56 | */
57 | private Pays pays;
58 |
59 | /**
60 | * 订单组件
61 | */
62 | private Orders orders;
63 |
64 | /**
65 | * 退款组件
66 | */
67 | private Refunds refunds;
68 |
69 | /**
70 | * 通知组件
71 | */
72 | private Notifies notifies;
73 |
74 | /**
75 | * 账单组件
76 | */
77 | private Bills bills;
78 |
79 | Wepay(String appId, String appKey, String mchId){
80 | this.appId = appId;
81 | this.appKey = appKey;
82 | this.mchId = mchId;
83 | }
84 |
85 | public String getAppId() {
86 | return appId;
87 | }
88 |
89 | public String getAppKey() {
90 | return appKey;
91 | }
92 |
93 | public String getMchId() {
94 | return mchId;
95 | }
96 |
97 | public byte[] getCerts() {
98 | return certs;
99 | }
100 |
101 | public String getCertPasswd() {
102 | return certPasswd;
103 | }
104 |
105 | public String getRespEncode() {
106 | return respEncode;
107 | }
108 |
109 | public SSLSocketFactory getSslSocketFactory() {
110 | return sslSocketFactory;
111 | }
112 |
113 | /**
114 | * 初始化操作
115 | * @return this
116 | */
117 | public Wepay init(){
118 | pays = new Pays(this);
119 | orders = new Orders(this);
120 | refunds = new Refunds(this);
121 | notifies = new Notifies(this);
122 | bills = new Bills(this);
123 | if (certs != null && !Strings.isNullOrEmpty(certPasswd)){
124 | sslSocketFactory = initSSLSocketFactory();
125 | }
126 | return this;
127 | }
128 |
129 | private SSLSocketFactory initSSLSocketFactory() {
130 | try (InputStream certsInput = new ByteArrayInputStream(certs)){
131 |
132 | KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
133 |
134 | KeyStore keyStore = KeyStore.getInstance("PKCS12");
135 | keyStore.load(certsInput, certPasswd.toCharArray());
136 | certsInput.close();
137 |
138 | keyManagerFactory.init(keyStore, certPasswd.toCharArray());
139 | SSLContext context = SSLContext.getInstance("TLS");
140 | context.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom());
141 |
142 | return context.getSocketFactory();
143 |
144 | } catch (Exception e) {
145 | throw new WepayException(e);
146 | }
147 | }
148 |
149 | /**
150 | * 调用支付组件
151 | * @return 支付组件
152 | */
153 | public Pays pay(){
154 | return pays;
155 | }
156 |
157 | /**
158 | * 调用订单组件
159 | * @return 订单组件
160 | */
161 | public Orders order(){
162 | return orders;
163 | }
164 |
165 | /**
166 | * 调用退款组件
167 | * @return 退款组件
168 | */
169 | public Refunds refund(){
170 | return refunds;
171 | }
172 |
173 | /**
174 | * 调用通知组件
175 | * @return 通知组件
176 | */
177 | public Notifies notifies(){
178 | return notifies;
179 | }
180 |
181 | /**
182 | * 调用账单组件
183 | * @return 账单组件
184 | */
185 | public Bills bill(){
186 | return bills;
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/core/WepayBuilder.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.core;
2 |
3 | /**
4 | * Wepay构建器
5 | * Author: haolin
6 | * Email: haolin.h0@gmail.com
7 | * Date: 25/11/15
8 | * @since 1.0.0
9 | */
10 | public final class WepayBuilder {
11 |
12 | private Wepay wepay;
13 |
14 | private WepayBuilder(){}
15 |
16 | public static WepayBuilder newBuilder(String appId, String appSecret, String mchId){
17 | WepayBuilder builder = new WepayBuilder();
18 | builder.wepay = new Wepay(appId, appSecret, mchId);
19 | return builder;
20 | }
21 |
22 | /**
23 | * 设置证书密码
24 | * @param certPasswd 证书密码
25 | * @return this
26 | */
27 | public WepayBuilder certPasswd(String certPasswd){
28 | wepay.certPasswd = certPasswd;
29 | return this;
30 | }
31 |
32 | /**
33 | * 设置证书数据(p12文件)
34 | * @param certs 二进制数据
35 | * @return this
36 | */
37 | public WepayBuilder certs(byte[] certs){
38 | wepay.certs = certs;
39 | return this;
40 | }
41 |
42 | /**
43 | * 设置解析微信XML时, 使用的编码类型
44 | * @param encode 编码类型
45 | * @return this
46 | */
47 | public WepayBuilder respEncode(String encode){
48 | wepay.respEncode = encode;
49 | return this;
50 | }
51 |
52 | public Wepay build(){
53 | return wepay.init();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/exception/SignException.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.exception;
2 |
3 | /**
4 | * 签名异常
5 | * Author: haolin
6 | * Email: haolin.h0@gmail.com
7 | */
8 | public class SignException extends RuntimeException {
9 |
10 | public SignException() {
11 | super();
12 | }
13 |
14 | public SignException(String message) {
15 | super(message);
16 | }
17 |
18 | public SignException(String message, Throwable cause) {
19 | super(message, cause);
20 | }
21 |
22 | public SignException(Throwable cause) {
23 | super(cause);
24 | }
25 |
26 | protected SignException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
27 | super(message, cause, enableSuppression, writableStackTrace);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/exception/WepayException.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.exception;
2 |
3 | /**
4 | * 微信支付异常
5 | * Author: haolin
6 | * Email: haolin.h0@gmail.com
7 | * Date: 26/11/15
8 | * @since 1.0.0
9 | */
10 | public class WepayException extends RuntimeException {
11 |
12 | /**
13 | * 当微信发生错误时,对应的错误码
14 | */
15 | private String errorCode;
16 |
17 | /**
18 | * 当微信发生错误时,对应的错误消息
19 | */
20 | private String errorMsg;
21 |
22 | public WepayException(Throwable cause) {
23 | super(cause);
24 | }
25 |
26 | public WepayException(String errorCode, String errorMsg){
27 | super("[" + errorCode + "]"+ errorMsg);
28 | this.errorCode = errorCode;
29 | this.errorMsg = errorMsg;
30 | }
31 |
32 | public String getErrorCode() {
33 | return errorCode;
34 | }
35 |
36 | public String getErrorMsg() {
37 | return errorMsg;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/bill/Bill.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.bill;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5 | import me.hao0.wepay.model.enums.FeeType;
6 | import me.hao0.wepay.model.enums.TradeType;
7 | import me.hao0.wepay.model.enums.WepayField;
8 | import me.hao0.wepay.serializer.FeeTypeDeserializer;
9 | import me.hao0.wepay.serializer.TradeTypeDeserializer;
10 | import java.io.Serializable;
11 |
12 | /**
13 | * 交易成功账单
14 | * Author: haolin
15 | * Email: haolin.h0@gmail.com
16 | * Date: 4/12/15
17 | * @since 1.1.0
18 | */
19 | public class Bill implements Serializable {
20 |
21 | private static final long serialVersionUID = 2385619717854141289L;
22 |
23 | /**
24 | * 交易时间
25 | */
26 | @JsonProperty(WepayField.TRADE_TIME)
27 | private String tradeTime;
28 |
29 | /**
30 | * 公众帐号ID
31 | */
32 | @JsonProperty(WepayField.APP_ID)
33 | private String appId;
34 |
35 | /**
36 | * 商户ID
37 | */
38 | @JsonProperty(WepayField.MCH_ID)
39 | private String mchId;
40 |
41 | /**
42 | * 子商户ID
43 | */
44 | @JsonProperty(WepayField.SUB_MCH_ID)
45 | private String subMchId;
46 |
47 | /**
48 | * 设备号
49 | */
50 | @JsonProperty(WepayField.DEVICE_INFO)
51 | private String deviceInfo;
52 |
53 | /**
54 | * 微信订单号
55 | */
56 | @JsonProperty(WepayField.TRANSACTION_ID)
57 | private String transactionId;
58 |
59 | /**
60 | * 商户订单号
61 | */
62 | @JsonProperty(WepayField.OUT_TRADE_NO)
63 | private String outTradeNo;
64 |
65 | /**
66 | * 用户标识
67 | */
68 | @JsonProperty(WepayField.OPEN_ID)
69 | private String openId;
70 |
71 | /**
72 | * 交易类型
73 | */
74 | @JsonProperty(WepayField.TRADE_TYPE)
75 | @JsonDeserialize(using = TradeTypeDeserializer.class)
76 | private TradeType tradeType;
77 |
78 | /**
79 | * 交易状态
80 | */
81 | @JsonProperty(WepayField.TRADE_STATE)
82 | private String tradeState;
83 |
84 | /**
85 | * 付款银行
86 | */
87 | @JsonProperty(WepayField.BANK_TYPE)
88 | private String bankType;
89 |
90 | /**
91 | * 货币类型
92 | */
93 | @JsonProperty(WepayField.FEE_TYPE)
94 | @JsonDeserialize(using = FeeTypeDeserializer.class)
95 | private FeeType feeType;
96 |
97 | /**
98 | * 总金额
99 | */
100 | @JsonProperty(WepayField.TOTAL_FEE)
101 | private Float totalFee;
102 |
103 | /**
104 | * 企业红包金额
105 | */
106 | @JsonProperty(WepayField.ENTER_RED_PKG_FEE)
107 | private Float enterRedPkgFee;
108 |
109 | /**
110 | * 商品名称
111 | */
112 | private String body;
113 |
114 | /**
115 | * 商户数据包
116 | */
117 | @JsonProperty(WepayField.DATA_PKG)
118 | private String dataPkg;
119 |
120 | /**
121 | * 手续费
122 | */
123 | @JsonProperty(WepayField.COMMISSION_FEE)
124 | private String commissionFee;
125 |
126 | /**
127 | * 费率
128 | */
129 | @JsonProperty(WepayField.FEE_RATE)
130 | private String feeRate;
131 |
132 | public String getTradeTime() {
133 | return tradeTime;
134 | }
135 |
136 | public void setTradeTime(String tradeTime) {
137 | this.tradeTime = tradeTime;
138 | }
139 |
140 | public String getAppId() {
141 | return appId;
142 | }
143 |
144 | public void setAppId(String appId) {
145 | this.appId = appId;
146 | }
147 |
148 | public String getMchId() {
149 | return mchId;
150 | }
151 |
152 | public void setMchId(String mchId) {
153 | this.mchId = mchId;
154 | }
155 |
156 | public String getSubMchId() {
157 | return subMchId;
158 | }
159 |
160 | public void setSubMchId(String subMchId) {
161 | this.subMchId = subMchId;
162 | }
163 |
164 | public String getDeviceInfo() {
165 | return deviceInfo;
166 | }
167 |
168 | public void setDeviceInfo(String deviceInfo) {
169 | this.deviceInfo = deviceInfo;
170 | }
171 |
172 | public String getTransactionId() {
173 | return transactionId;
174 | }
175 |
176 | public void setTransactionId(String transactionId) {
177 | this.transactionId = transactionId;
178 | }
179 |
180 | public String getOutTradeNo() {
181 | return outTradeNo;
182 | }
183 |
184 | public void setOutTradeNo(String outTradeNo) {
185 | this.outTradeNo = outTradeNo;
186 | }
187 |
188 | public String getOpenId() {
189 | return openId;
190 | }
191 |
192 | public void setOpenId(String openId) {
193 | this.openId = openId;
194 | }
195 |
196 | public TradeType getTradeType() {
197 | return tradeType;
198 | }
199 |
200 | public void setTradeType(TradeType tradeType) {
201 | this.tradeType = tradeType;
202 | }
203 |
204 | public String getTradeState() {
205 | return tradeState;
206 | }
207 |
208 | public void setTradeState(String tradeState) {
209 | this.tradeState = tradeState;
210 | }
211 |
212 | public String getBankType() {
213 | return bankType;
214 | }
215 |
216 | public void setBankType(String bankType) {
217 | this.bankType = bankType;
218 | }
219 |
220 | public FeeType getFeeType() {
221 | return feeType;
222 | }
223 |
224 | public void setFeeType(FeeType feeType) {
225 | this.feeType = feeType;
226 | }
227 |
228 | public String getBody() {
229 | return body;
230 | }
231 |
232 | public void setBody(String body) {
233 | this.body = body;
234 | }
235 |
236 | public String getDataPkg() {
237 | return dataPkg;
238 | }
239 |
240 | public void setDataPkg(String dataPkg) {
241 | this.dataPkg = dataPkg;
242 | }
243 |
244 | public String getFeeRate() {
245 | return feeRate;
246 | }
247 |
248 | public void setFeeRate(String feeRate) {
249 | this.feeRate = feeRate;
250 | }
251 |
252 | public Float getTotalFee() {
253 | return totalFee;
254 | }
255 |
256 | public void setTotalFee(Float totalFee) {
257 | this.totalFee = totalFee;
258 | }
259 |
260 | public Float getEnterRedPkgFee() {
261 | return enterRedPkgFee;
262 | }
263 |
264 | public void setEnterRedPkgFee(Float enterRedPkgFee) {
265 | this.enterRedPkgFee = enterRedPkgFee;
266 | }
267 |
268 | public String getCommissionFee() {
269 | return commissionFee;
270 | }
271 |
272 | public void setCommissionFee(String commissionFee) {
273 | this.commissionFee = commissionFee;
274 | }
275 |
276 | @Override
277 | public String toString() {
278 | return "Bill{" +
279 | "tradeTime='" + tradeTime + '\'' +
280 | ", appId='" + appId + '\'' +
281 | ", mchId='" + mchId + '\'' +
282 | ", subMchId='" + subMchId + '\'' +
283 | ", deviceInfo='" + deviceInfo + '\'' +
284 | ", transactionId='" + transactionId + '\'' +
285 | ", outTradeNo='" + outTradeNo + '\'' +
286 | ", openId='" + openId + '\'' +
287 | ", tradeType=" + tradeType +
288 | ", tradeState='" + tradeState + '\'' +
289 | ", bankType='" + bankType + '\'' +
290 | ", feeType=" + feeType +
291 | ", totalFee=" + totalFee +
292 | ", enterRedPkgFee=" + enterRedPkgFee +
293 | ", body='" + body + '\'' +
294 | ", dataPkg='" + dataPkg + '\'' +
295 | ", commissionFee=" + commissionFee +
296 | ", feeRate='" + feeRate + '\'' +
297 | '}';
298 | }
299 | }
300 |
301 |
302 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/bill/BillCount.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.bill;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import me.hao0.wepay.model.enums.WepayField;
5 | import java.io.Serializable;
6 |
7 | /**
8 | * 账单统计
9 | * Author: haolin
10 | * Email: haolin.h0@gmail.com
11 | * Date: 4/12/15
12 | * @since 1.1.0
13 | */
14 | public class BillCount implements Serializable {
15 |
16 | private static final long serialVersionUID = 2827339255910413151L;
17 |
18 | /**
19 | * 总交易笔数
20 | */
21 | @JsonProperty(WepayField.TRADE_TOTAL_COUNT)
22 | private Integer tradeTotalCount;
23 |
24 | /**
25 | * 总交易额(元)
26 | */
27 | @JsonProperty(WepayField.TRADE_TOTAL_FEE)
28 | private Float tradeTotalFee;
29 |
30 | /**
31 | * 总退款金额(元)
32 | */
33 | @JsonProperty(WepayField.REFUND_TOTAL_FEE)
34 | private Float refundTotalFee;
35 |
36 | /**
37 | * 总代金券或立减优惠退款金额
38 | */
39 | @JsonProperty(WepayField.COUPON_REFUND_TOTAL_FEE)
40 | private Float couponRefundTotalFee;
41 |
42 | /**
43 | * 手续费总金额
44 | */
45 | @JsonProperty(WepayField.COMMISSION_TOTAL_FEE)
46 | private String commissionTotalFee;
47 |
48 | public Integer getTradeTotalCount() {
49 | return tradeTotalCount;
50 | }
51 |
52 | public void setTradeTotalCount(Integer tradeTotalCount) {
53 | this.tradeTotalCount = tradeTotalCount;
54 | }
55 |
56 | public Float getTradeTotalFee() {
57 | return tradeTotalFee;
58 | }
59 |
60 | public void setTradeTotalFee(Float tradeTotalFee) {
61 | this.tradeTotalFee = tradeTotalFee;
62 | }
63 |
64 | public Float getRefundTotalFee() {
65 | return refundTotalFee;
66 | }
67 |
68 | public void setRefundTotalFee(Float refundTotalFee) {
69 | this.refundTotalFee = refundTotalFee;
70 | }
71 |
72 | public Float getCouponRefundTotalFee() {
73 | return couponRefundTotalFee;
74 | }
75 |
76 | public void setCouponRefundTotalFee(Float couponRefundTotalFee) {
77 | this.couponRefundTotalFee = couponRefundTotalFee;
78 | }
79 |
80 | public String getCommissionTotalFee() {
81 | return commissionTotalFee;
82 | }
83 |
84 | public void setCommissionTotalFee(String commissionTotalFee) {
85 | this.commissionTotalFee = commissionTotalFee;
86 | }
87 |
88 | @Override
89 | public String toString() {
90 | return "BillCount{" +
91 | "tradeTotalCount=" + tradeTotalCount +
92 | ", tradeTotalFee=" + tradeTotalFee +
93 | ", refundTotalFee=" + refundTotalFee +
94 | ", couponRefundTotalFee=" + couponRefundTotalFee +
95 | ", commissionTotalFee=" + commissionTotalFee +
96 | '}';
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/bill/BillDetail.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.bill;
2 |
3 | import java.io.Serializable;
4 | import java.util.Collections;
5 | import java.util.List;
6 |
7 | /**
8 | * 账单信息
9 | * Author: haolin
10 | * Email: haolin.h0@gmail.com
11 | * Date: 4/12/15
12 | * @since 1.1.0
13 | */
14 | public class BillDetail implements Serializable {
15 |
16 | private static final long serialVersionUID = 2763506940046963037L;
17 |
18 | /**
19 | * 账单记录
20 | */
21 | private List bills;
22 |
23 | /**
24 | * 账单统计
25 | */
26 | private BillCount count;
27 |
28 | @SuppressWarnings("unchecked")
29 | private static final BillDetail EMPTY = (BillDetail)new BillDetail(Collections.emptyList(), null);
30 |
31 | public BillDetail(List bills, BillCount count) {
32 | this.bills = bills;
33 | this.count = count;
34 | }
35 |
36 | public List getBills() {
37 | return bills;
38 | }
39 |
40 | public void setBills(List bills) {
41 | this.bills = bills;
42 | }
43 |
44 | public BillCount getCount() {
45 | return count;
46 | }
47 |
48 | public void setCount(BillCount count) {
49 | this.count = count;
50 | }
51 |
52 | @SuppressWarnings("unchecked")
53 | public static BillDetail empty(){
54 | return EMPTY;
55 | }
56 |
57 | @Override
58 | public String toString() {
59 | return "BillDetail{" +
60 | "bills=" + bills +
61 | ", count=" + count +
62 | '}';
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/bill/BillFields.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.bill;
2 |
3 | import me.hao0.wepay.model.enums.WepayField;
4 | import java.util.ArrayList;
5 | import java.util.Arrays;
6 | import java.util.HashMap;
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | /**
11 | * 账单字段
12 | * Author: haolin
13 | * Email: haolin.h0@gmail.com
14 | * Date: 4/12/15
15 | * @since 1.1.0
16 | */
17 | public final class BillFields {
18 |
19 | /**
20 | * 账单公用起始字段
21 | */
22 | private static final List START_FIELDS = Arrays.asList(
23 | WepayField.TRADE_TIME, WepayField.APP_ID, WepayField.MCH_ID, WepayField.SUB_MCH_ID,
24 | WepayField.DEVICE_INFO, WepayField.TRANSACTION_ID, WepayField.OUT_TRADE_NO, WepayField.OPEN_ID,
25 | WepayField.TRADE_TYPE, WepayField.TRADE_STATE, WepayField.BANK_TYPE, WepayField.FEE_TYPE,
26 | WepayField.TOTAL_FEE, WepayField.ENTER_RED_PKG_FEE
27 | );
28 |
29 | private static final List END_FIELDS = Arrays.asList(
30 | WepayField.BODY, WepayField.DATA_PKG, WepayField.COMMISSION_FEE, WepayField.FEE_RATE
31 | );
32 |
33 | /**
34 | * 所有订单账单的字段集,顺序与微信返回数据保持一致
35 | */
36 | public static final List ALL = initAllFields();
37 |
38 | /**
39 | * 退款账单的字段集合,顺序与微信返回数据保持一致
40 | */
41 | public static final List REFUND = initRefundFields();
42 |
43 | /**
44 | * 成功账单的字段集合,顺序与微信返回数据保持一致
45 | */
46 | public static final List SUCCESS = initSuccessFields();
47 |
48 | /**
49 | * 账单统计的字段集合,顺序与微信返回数据保持一致
50 | */
51 | public static final List COUNT = Arrays.asList(
52 | WepayField.TRADE_TOTAL_COUNT, WepayField.TRADE_TOTAL_FEE,
53 | WepayField.REFUND_TOTAL_FEE, WepayField.COUPON_REFUND_TOTAL_FEE,
54 | WepayField.COMMISSION_TOTAL_FEE
55 | );
56 |
57 |
58 | private BillFields(){}
59 |
60 | private static List initAllFields() {
61 | List all = new ArrayList<>();
62 | startFields(all);
63 | initCommonRefundFields(all);
64 | endFields(all);
65 | return all;
66 | }
67 |
68 | private static List initRefundFields() {
69 | List refund = new ArrayList<>();
70 | startFields(refund);
71 | refund.add(WepayField.REFUND_APPLY_TIME);
72 | refund.add(WepayField.REFUND_SUCCESS_TIME);
73 | initCommonRefundFields(refund);
74 | endFields(refund);
75 | return refund;
76 | }
77 |
78 | private static void initCommonRefundFields(List fields){
79 | fields.add(WepayField.REFUND_ID);
80 | fields.add(WepayField.OUT_REFUND_NO);
81 | fields.add(WepayField.REFUND_FEE);
82 | fields.add(WepayField.ENTER_RED_PKG_REFUND_FEE);
83 | fields.add(WepayField.REFUND_CHANNEL);
84 | fields.add(WepayField.REFUND_STATUS);
85 | }
86 |
87 | private static List initSuccessFields() {
88 | List success = new ArrayList<>();
89 | startFields(success);
90 | endFields(success);
91 | return success;
92 | }
93 |
94 | private static void startFields(List fields) {
95 | for (String f : START_FIELDS){
96 | fields.add(f);
97 | }
98 | }
99 |
100 | private static void endFields(List fields) {
101 | for (String f : END_FIELDS){
102 | fields.add(f);
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/bill/CommonBill.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.bill;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5 | import me.hao0.wepay.model.enums.RefundChannel;
6 | import me.hao0.wepay.model.enums.WepayField;
7 | import me.hao0.wepay.serializer.RefundChannelDeserializer;
8 |
9 | /**
10 | * 普通账单
11 | * Author: haolin
12 | * Email: haolin.h0@gmail.com
13 | * Date: 4/12/15
14 | * @since 1.1.0
15 | */
16 | public class CommonBill extends Bill {
17 |
18 | private static final long serialVersionUID = -4518299029269484159L;
19 |
20 | /**
21 | * 微信退款单号
22 | */
23 | @JsonProperty(WepayField.REFUND_ID)
24 | private String refundId;
25 |
26 | /**
27 | * 商户退款单号
28 | */
29 | @JsonProperty(WepayField.OUT_REFUND_NO)
30 | private String outRefundNo;
31 |
32 | /**
33 | * 退款金额(元)
34 | */
35 | @JsonProperty(WepayField.REFUND_FEE)
36 | private Float refundFee;
37 |
38 | /**
39 | * 企业红包退款金额(元)
40 | */
41 | @JsonProperty(WepayField.ENTER_RED_PKG_REFUND_FEE)
42 | private Float enterRedPkgRefundFee;
43 |
44 | /**
45 | * 退款类型
46 | */
47 | @JsonProperty(WepayField.REFUND_CHANNEL)
48 | @JsonDeserialize(using = RefundChannelDeserializer.class)
49 | private RefundChannel channel;
50 |
51 | /**
52 | * 退款状态
53 | */
54 | @JsonProperty(WepayField.REFUND_STATUS)
55 | private String refundStatus;
56 |
57 | public String getRefundId() {
58 | return refundId;
59 | }
60 |
61 | public void setRefundId(String refundId) {
62 | this.refundId = refundId;
63 | }
64 |
65 | public String getOutRefundNo() {
66 | return outRefundNo;
67 | }
68 |
69 | public void setOutRefundNo(String outRefundNo) {
70 | this.outRefundNo = outRefundNo;
71 | }
72 |
73 | public Float getRefundFee() {
74 | return refundFee;
75 | }
76 |
77 | public void setRefundFee(Float refundFee) {
78 | this.refundFee = refundFee;
79 | }
80 |
81 | public Float getEnterRedPkgRefundFee() {
82 | return enterRedPkgRefundFee;
83 | }
84 |
85 | public void setEnterRedPkgRefundFee(Float enterRedPkgRefundFee) {
86 | this.enterRedPkgRefundFee = enterRedPkgRefundFee;
87 | }
88 |
89 | public RefundChannel getChannel() {
90 | return channel;
91 | }
92 |
93 | public void setChannel(RefundChannel channel) {
94 | this.channel = channel;
95 | }
96 |
97 | public String getRefundStatus() {
98 | return refundStatus;
99 | }
100 |
101 | public void setRefundStatus(String refundStatus) {
102 | this.refundStatus = refundStatus;
103 | }
104 |
105 | @Override
106 | public String toString() {
107 | return "CommonBill{" +
108 | "refundId='" + refundId + '\'' +
109 | ", outRefundNo='" + outRefundNo + '\'' +
110 | ", refundFee=" + refundFee +
111 | ", enterRedPkgRefundFee=" + enterRedPkgRefundFee +
112 | ", channel=" + channel +
113 | ", refundStatus='" + refundStatus + '\'' +
114 | "} " + super.toString();
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/bill/RefundBill.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.bill;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import me.hao0.wepay.model.enums.WepayField;
5 |
6 | /**
7 | * 退款账单
8 | * Author: haolin
9 | * Email: haolin.h0@gmail.com
10 | * Date: 4/12/15
11 | */
12 | public class RefundBill extends CommonBill {
13 |
14 | private static final long serialVersionUID = -6051679079124227683L;
15 |
16 | /**
17 | * 退款申请时间
18 | */
19 | @JsonProperty(WepayField.REFUND_APPLY_TIME)
20 | private String refundApplyTime;
21 |
22 | /**
23 | * 退款成功时间
24 | */
25 | @JsonProperty(WepayField.REFUND_SUCCESS_TIME)
26 | private String refundSuccessTime;
27 |
28 | public String getRefundApplyTime() {
29 | return refundApplyTime;
30 | }
31 |
32 | public void setRefundApplyTime(String refundApplyTime) {
33 | this.refundApplyTime = refundApplyTime;
34 | }
35 |
36 | public String getRefundSuccessTime() {
37 | return refundSuccessTime;
38 | }
39 |
40 | public void setRefundSuccessTime(String refundSuccessTime) {
41 | this.refundSuccessTime = refundSuccessTime;
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | return "RefundBill{" +
47 | "refundApplyTime='" + refundApplyTime + '\'' +
48 | ", refundSuccessTime='" + refundSuccessTime + '\'' +
49 | "} " + super.toString();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/common/Coupon.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.common;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 代金券
7 | * Author: haolin
8 | * Email: haolin.h0@gmail.com
9 | * Date: 1/12/15
10 | * @since 1.0.0
11 | */
12 | public class Coupon implements Serializable {
13 |
14 | private static final long serialVersionUID = -2006707624918389486L;
15 |
16 | /**
17 | * 代金券或立减优惠批次ID
18 | */
19 | private String batchId;
20 |
21 | /**
22 | * 代金券或立减优惠ID
23 | */
24 | private String id;
25 |
26 | /**
27 | * 单个代金券或立减优惠支付金额
28 | */
29 | private Integer fee;
30 |
31 | private Coupon(){}
32 |
33 | public String getBatchId() {
34 | return batchId;
35 | }
36 |
37 | public void setBatchId(String batchId) {
38 | this.batchId = batchId;
39 | }
40 |
41 | public String getId() {
42 | return id;
43 | }
44 |
45 | public void setId(String id) {
46 | this.id = id;
47 | }
48 |
49 | public Integer getFee() {
50 | return fee;
51 | }
52 |
53 | public void setFee(Integer fee) {
54 | this.fee = fee;
55 | }
56 |
57 | public static Coupon newCoupon(String batchId, String id, Integer fee){
58 | Coupon c = new Coupon();
59 | c.batchId = batchId;
60 | c.id = id;
61 | c.fee = fee;
62 | return c;
63 | }
64 |
65 | @Override
66 | public String toString() {
67 | return "RefundCouponItem{" +
68 | "batchId='" + batchId + '\'' +
69 | ", id='" + id + '\'' +
70 | ", fee=" + fee +
71 | '}';
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/enums/BillType.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.enums;
2 |
3 | /**
4 | * 账单类型
5 | * Author: haolin
6 | * Email: haolin.h0@gmail.com
7 | * Date: 4/12/15
8 | * @since 1.1.0
9 | */
10 | public enum BillType {
11 |
12 | /**
13 | * 所有订单信息
14 | */
15 | ALL("ALL"),
16 |
17 | /**
18 | * 成功支付的订单
19 | */
20 | SUCCESS("SUCCESS"),
21 |
22 | /**
23 | * 退款订单
24 | */
25 | REFUND("REFUND");
26 |
27 | private String type;
28 |
29 | private BillType(String type){
30 | this.type = type;
31 | }
32 |
33 | public String type(){
34 | return type;
35 | }
36 |
37 | public static BillType from(String t){
38 | for (BillType bt : BillType.values()){
39 | if (bt.type().equals(t)){
40 | return bt;
41 | }
42 | }
43 | throw new IllegalArgumentException("unknown bill type: " + t);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/enums/FeeType.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.enums;
2 |
3 | /**
4 | * 货币类型
5 | * Author: haolin
6 | * Email: haolin.h0@gmail.com
7 | * Date: 26/11/15
8 | * @since 1.0.0
9 | */
10 | public enum FeeType {
11 |
12 | /**
13 | * 人民币
14 | */
15 | CNY("CNY");
16 |
17 | private String type;
18 |
19 | private FeeType(String type){
20 | this.type = type;
21 | }
22 |
23 | public String type(){
24 | return type;
25 | }
26 |
27 | public static FeeType from(String t){
28 | for (FeeType ft : FeeType.values()){
29 | if (ft.type().equals(t)){
30 | return ft;
31 | }
32 | }
33 | throw new IllegalArgumentException("unknown fee type: " + t);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/enums/RefundChannel.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.enums;
2 |
3 | /**
4 | * 退款渠道
5 | * Author: haolin
6 | * Email: haolin.h0@gmail.com
7 | * Date: 26/11/15
8 | * @since 1.0.0
9 | */
10 | public enum RefundChannel {
11 |
12 | /**
13 | * 原路退款
14 | */
15 | ORIGINAL("ORIGINAL"),
16 |
17 | /**
18 | * 退款到余额
19 | */
20 | BALANCE("BALANCE");
21 |
22 | private String type;
23 |
24 | private RefundChannel(String type){
25 | this.type = type;
26 | }
27 |
28 | public String type(){
29 | return type;
30 | }
31 |
32 | public static RefundChannel from(String t){
33 | for (RefundChannel rc : RefundChannel.values()){
34 | if (rc.type().equals(t)){
35 | return rc;
36 | }
37 | }
38 | throw new IllegalArgumentException("unknown apply channel: " + t);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/enums/RefundStatus.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.enums;
2 |
3 | /**
4 | * @author haolin
5 | * @date 6/11/16
6 | * @mailto haolin.h0@gmail.com
7 | */
8 | public enum RefundStatus {
9 |
10 | /**
11 | * 退款成功
12 | */
13 | SUCCESS("SUCCESS"),
14 |
15 | /**
16 | * 退款失败
17 | */
18 | FAIL("FAIL"),
19 |
20 | /**
21 | * 退款处理中
22 | */
23 | PROCESSING("PROCESSING"),
24 |
25 | /**
26 | * 未确定,需要商户原退款单号重新发起
27 | */
28 | NOTSURE("NOTSURE"),
29 |
30 | /**
31 | * 转入代发,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,资金回流到商户的现金帐号,需要商户人工干预,通过线下或者财付通转账的方式进行退款。
32 | */
33 | CHANGE("CHANGE");
34 |
35 | private String value;
36 |
37 | RefundStatus(String value){
38 | this.value = value;
39 | }
40 |
41 | public String value(){
42 | return value;
43 | }
44 |
45 | public static RefundStatus from(String s){
46 | for (RefundStatus rs : RefundStatus.values()){
47 | if (rs.value().equals(s)){
48 | return rs;
49 | }
50 | }
51 | throw new IllegalArgumentException("unknown refund status: " + s);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/enums/TradeState.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.enums;
2 |
3 | /**
4 | * 交易状态
5 | * Author: haolin
6 | * Email: haolin.h0@gmail.com
7 | * Date: 26/11/15
8 | * @since 1.0.0
9 | */
10 | public enum TradeState {
11 |
12 | /**
13 | * 支付成功
14 | */
15 | SUCCESS("SUCCESS"),
16 |
17 | /**
18 | * 转入退款
19 | */
20 | REFUND("REFUND"),
21 |
22 | /**
23 | * 未支付
24 | */
25 | NOTPAY("NOTPAY"),
26 |
27 | /**
28 | * 已关闭
29 | */
30 | CLOSED("CLOSED"),
31 |
32 | /**
33 | * 已撤销(刷卡支付)
34 | */
35 | REVOKED("REVOKED"),
36 |
37 | /**
38 | * 已撤销(刷卡支付)
39 | */
40 | USERPAYING("USERPAYING"),
41 |
42 | /**
43 | * 支付失败(其他原因,如银行返回失败)
44 | */
45 | PAYERROR("PAYERROR");
46 |
47 | private String type;
48 |
49 | private TradeState(String type){
50 | this.type = type;
51 | }
52 |
53 | public String type(){
54 | return type;
55 | }
56 |
57 | public static TradeState from(String s){
58 | for (TradeState tt : TradeState.values()){
59 | if (tt.type().equals(s)){
60 | return tt;
61 | }
62 | }
63 | throw new IllegalArgumentException("unknown trade type: " + s);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/enums/TradeType.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.enums;
2 |
3 | /**
4 | * 交易类型
5 | * Author: haolin
6 | * Email: haolin.h0@gmail.com
7 | * Date: 26/11/15
8 | * @since 1.0.0
9 | */
10 | public enum TradeType {
11 |
12 | /**
13 | * 公众号支付
14 | */
15 | JSAPI("JSAPI"),
16 |
17 | /**
18 | * 原生扫码支付
19 | */
20 | NATIVE("NATIVE"),
21 |
22 | /**
23 | * APP支付
24 | */
25 | APP("APP"),
26 |
27 | /**
28 | * 刷卡支付
29 | */
30 | MICROPAY("MICROPAY");
31 |
32 |
33 | private String type;
34 |
35 | private TradeType(String type){
36 | this.type = type;
37 | }
38 |
39 | public String type(){
40 | return type;
41 | }
42 |
43 | public static TradeType from(String s){
44 | for (TradeType tt : TradeType.values()){
45 | if (tt.type().equals(s)){
46 | return tt;
47 | }
48 | }
49 | throw new IllegalArgumentException("unknown trade type: " + s);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/enums/WepayField.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.enums;
2 |
3 | import me.hao0.wepay.annotation.Optional;
4 |
5 | /**
6 | * 微信支付字段
7 | * Author: haolin
8 | * Email: haolin.h0@gmail.com
9 | * Date: 26/11/15
10 | * @since 1.0.0
11 | */
12 | public final class WepayField {
13 |
14 | /**
15 | * 成功标识
16 | */
17 | public static final String SUCCESS = "SUCCESS";
18 |
19 | /**
20 | * 响应结果
21 | */
22 | public static final String RETURN_CODE = "return_code";
23 |
24 | /**
25 | * 错误响应消息
26 | */
27 | public static final String RETURN_MSG = "return_msg";
28 |
29 | /**
30 | * 业务结果
31 | */
32 | public static final String RESULT_CODE = "result_code";
33 |
34 | /**
35 | * 业务错误码
36 | */
37 | public static final String ERR_CODE = "err_code";
38 |
39 | /**
40 | * 业务错误描述
41 | */
42 | public static final String ERR_CODE_DES = "err_code_des";
43 |
44 | /**
45 | * 公众帐号ID
46 | */
47 | public static final String APP_ID = "appid";
48 |
49 | /**
50 | * 公众帐号ID
51 | */
52 | public static final String APPID = "appId";
53 |
54 | /**
55 | * 微信支付分配的商户号
56 | */
57 | public static final String MCH_ID = "mch_id";
58 |
59 | /**
60 | * 终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB"
61 | */
62 | @Optional
63 | public static final String DEVICE_INFO = "device_info";
64 |
65 | /**
66 | * 随机字符串,不长于32位
67 | */
68 | public static final String NONCE_STR = "nonce_str";
69 |
70 | /**
71 | * 随机字符串,不长于32位
72 | */
73 | public static final String NONCESTR = "noncestr";
74 |
75 | /**
76 | * 随机字符串,不长于32位
77 | */
78 | public static final String NONCESTR2 = "nonceStr";
79 |
80 | /**
81 | * 签名
82 | */
83 | public static final String SIGN = "sign";
84 |
85 | /**
86 | * 签名类型
87 | */
88 | public static final String SIGN_TYPE = "signType";
89 |
90 | /**
91 | * 商品或支付单简要描述
92 | */
93 | public static final String BODY = "body";
94 |
95 | /**
96 | * 商品名称明细列表
97 | */
98 | @Optional
99 | public static final String DETAIL = "detail";
100 |
101 | /**
102 | * 附加数据
103 | * 在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
104 | */
105 | @Optional
106 | public static final String ATTACH = "attach";
107 |
108 | /**
109 | * 商户订单号
110 | * 商户系统内部的订单号,32个字符内、可包含字母
111 | */
112 | public static final String OUT_TRADE_NO = "out_trade_no";
113 |
114 | /**
115 | * 货币类型
116 | * 符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见
117 | */
118 | @Optional
119 | public static final String FEE_TYPE = "fee_type";
120 |
121 | /**
122 | * 订单总金额,单位为分
123 | */
124 | public static final String TOTAL_FEE = "total_fee";
125 |
126 | /**
127 | * 终端IP
128 | * APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
129 | */
130 | public static final String SPBILL_CREATE_IP = "spbill_create_ip";
131 |
132 | /**
133 | * 交易起始时间
134 | * 订单生成时间,格式为yyyyMMddHHmmss
135 | */
136 | public static final String TIME_START = "time_start";
137 |
138 | /**
139 | * 交易结束时间
140 | * 订单失效时间,格式为yyyyMMddHHmmss。
141 | * 注意:最短失效时间间隔必须大于5分钟
142 | */
143 | @Optional
144 | public static final String TIME_EXPIRE = "time_expire";
145 |
146 | /**
147 | * 商品标记,代金券或立减优惠功能的参数
148 | */
149 | @Optional
150 | public static final String GOODS_TAG = "goods_tag";
151 |
152 | /**
153 | * 接收微信支付异步通知回调地址
154 | */
155 | public static final String NOTIFY_URL = "notify_url";
156 |
157 | /**
158 | * 交易类型
159 | * @see TradeType
160 | */
161 | public static final String TRADE_TYPE = "trade_type";
162 |
163 | /**
164 | * 商品ID
165 | * trade_type=NATIVE且为静态链接支付,此参数必传。此id为二维码中包含的商品ID,商户自行定义
166 | */
167 | @Optional(any = false)
168 | public static final String PRODUCT_ID = "product_id";
169 |
170 | /**
171 | * 指定支付方式
172 | * no_credit--指定不能使用信用卡支付
173 | */
174 | @Optional
175 | public static final String LIMIT_PAY = "limit_pay";
176 |
177 | /**
178 | * 用户标识
179 | * trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识
180 | */
181 | @Optional(any = false)
182 | public static final String OPEN_ID = "openid";
183 |
184 | /**
185 | * 预支付ID
186 | */
187 | public static final String PREPAY_ID = "prepay_id";
188 |
189 | /**
190 | * 预支付ID
191 | */
192 | public static final String PREPAYID = "prepayid";
193 |
194 | /**
195 | * 二维码链接
196 | */
197 | public static final String CODE_URL = "code_url";
198 |
199 | /**
200 | * 微信订单号
201 | */
202 | public static final String TRANSACTION_ID = "transaction_id";
203 |
204 | /**
205 | * 是否关注
206 | */
207 | public static final String IS_SUBSCRIBE = "is_subscribe";
208 |
209 | /**
210 | * 银行
211 | */
212 | public static final String BANK_TYPE = "bank_type";
213 |
214 | /**
215 | * 支付完成时间
216 | */
217 | public static final String TIME_END = "time_end";
218 |
219 | /**
220 | * 交易状态
221 | */
222 | public static final String TRADE_STATE = "trade_state";
223 |
224 | /**
225 | * 交易状态描述
226 | */
227 | public static final String TRADE_STATE_DESC = "trade_state_desc";
228 |
229 | /**
230 | * 现金支付金额
231 | */
232 | public static final String CASH_FEE = "cash_fee";
233 |
234 | /**
235 | * 现金支付货币类型
236 | */
237 | public static final String CASH_FEE_TYPE = "cash_fee_type";
238 |
239 | /**
240 | * 代金券或立减优惠金额
241 | */
242 | public static final String COUPON_FEE = "coupon_fee";
243 |
244 | /**
245 | * 代金券或立减优惠使用数量
246 | */
247 | public static final String COUPON_COUNT = "coupon_count";
248 |
249 | /**
250 | * prepay_id=xxx
251 | */
252 | public static final String PKG = "package";
253 |
254 | /**
255 | * 时间戳
256 | */
257 | public static final String TIME_STAMP = "timeStamp";
258 |
259 | /**
260 | * 时间戳
261 | */
262 | public static final String TIMESTAMP = "timestamp";
263 |
264 | /**
265 | * 签名KEY
266 | */
267 | public static final String KEY = "key";
268 |
269 | /**
270 | * 商户唯一退款订单号
271 | */
272 | public static final String OUT_REFUND_NO = "out_refund_no";
273 |
274 | /**
275 | * 退款金额
276 | */
277 | public static final String REFUND_FEE = "refund_fee";
278 |
279 | /**
280 | * 操作员ID
281 | */
282 | public static final String OP_USER_ID = "op_user_id";
283 |
284 | /**
285 | * 微信退款单号
286 | */
287 | public static final String REFUND_ID = "refund_id";
288 |
289 | /**
290 | * 退款渠道
291 | * @see me.hao0.wepay.model.enums.RefundChannel
292 | */
293 | public static final String REFUND_CHANNEL = "refund_channel";
294 |
295 | /**
296 | * 现金退款金额
297 | */
298 | public static final String CASH_REFUND_FEE = "cash_refund_fee";
299 |
300 | /**
301 | * 代金券或立减优惠退款金额
302 | */
303 | public static final String COUPON_REFUND_FEE = "coupon_refund_fee";
304 |
305 | /**
306 | * 代金券或立减优惠使用数量
307 | */
308 | public static final String COUPON_REFUND_COUNT = "coupon_refund_count";
309 |
310 | /**
311 | * 代金券或立减优惠ID
312 | */
313 | public static final String COUPON_REFUND_ID = "coupon_refund_id";
314 |
315 | /**
316 | * 退款货币类型
317 | */
318 | public static final String REFUND_FEE_TYPE = "refund_fee_type";
319 |
320 | /**
321 | * 退款笔数
322 | */
323 | public static final String REFUND_COUNT = "refund_count";
324 |
325 | /**
326 | * 代金券或立减优惠批次ID
327 | */
328 | public static final String COUPON_REFUND_BATCH_ID = "coupon_refund_batch_id";
329 |
330 | /**
331 | * 商户号
332 | */
333 | public static final String PARTNER_ID = "partner_id";
334 |
335 | /**
336 | * 商户号
337 | */
338 | public static final String PARTNERID = "partnerid";
339 |
340 | /**
341 | * 代金券或立减优惠批次ID
342 | */
343 | public static final String COUPON_BATCH_ID = "coupon_batch_id";
344 |
345 | /**
346 | * 代金券或立减优惠ID
347 | */
348 | public static final String COUPON_ID = "coupon_id";
349 |
350 | /**
351 | * 账单类型
352 | */
353 | public static final String BILL_TYPE = "bill_type";
354 |
355 | /**
356 | * 账单日期
357 | */
358 | public static final String BILL_DATE = "bill_date";
359 |
360 | /**
361 | * 子商户ID
362 | */
363 | public static final String SUB_MCH_ID = "sub_mch_id";
364 |
365 | /**
366 | * 企业红包金额
367 | */
368 | public static final String ENTER_RED_PKG_FEE = "enter_ed_pkg_fee";
369 |
370 | /**
371 | * 商户数据包
372 | */
373 | public static final String DATA_PKG = "data_pkg";
374 |
375 | /**
376 | * 商户手续费
377 | */
378 | public static final String COMMISSION_FEE = "commission_fee";
379 |
380 | /**
381 | * 费率
382 | */
383 | public static final String FEE_RATE = "fee_rate";
384 |
385 | /**
386 | * 企业红包退款金额
387 | */
388 | public static final String ENTER_RED_PKG_REFUND_FEE = "enter_red_pkg_refund_fee";
389 |
390 | /**
391 | * 退款申请时间
392 | */
393 | public static final String REFUND_APPLY_TIME = "refund_apply_time";
394 |
395 | /**
396 | * 退款成功时间
397 | */
398 | public static final String REFUND_SUCCESS_TIME = "refund_success_time";
399 |
400 | /**
401 | * 交易时间
402 | */
403 | public static final String TRADE_TIME = "trade_time";
404 |
405 | /**
406 | * 退款状态
407 | */
408 | public static final String REFUND_STATUS = "refund_status";
409 |
410 | /**
411 | * 总交易笔数
412 | */
413 | public static final String TRADE_TOTAL_COUNT = "trade_total_count";
414 |
415 | /**
416 | * 总交易额
417 | */
418 | public static final String TRADE_TOTAL_FEE = "trade_total_fee";
419 |
420 | /**
421 | * 总退款金额
422 | */
423 | public static final String REFUND_TOTAL_FEE = "refund_total_fee";
424 |
425 | /**
426 | * 总代金券或立减优惠退款金额
427 | */
428 | public static final String COUPON_REFUND_TOTAL_FEE = "coupon_refund_total_fee";
429 |
430 | /**
431 | * 手续费总金额
432 | */
433 | public static final String COMMISSION_TOTAL_FEE = "commission_total_fee";
434 |
435 | /**
436 | * 退款金额
437 | */
438 | public static final String SETTLEMENT_REFUND_FEE = "settlement_refund_fee";
439 |
440 | /**
441 | * 退款入账账户
442 | * 1)退回银行卡:
443 | * {银行名称}{卡类型}{卡尾号}
444 | * 2)退回支付用户零钱:
445 | * 支付用户零钱
446 | */
447 | public static final String REFUND_RECV_ACCOUNT = "refund_recv_accout";
448 |
449 | }
450 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/order/WePayOrder.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.order;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
6 | import me.hao0.wepay.model.common.Coupon;
7 | import me.hao0.wepay.model.enums.FeeType;
8 | import me.hao0.wepay.model.enums.TradeState;
9 | import me.hao0.wepay.model.enums.TradeType;
10 | import me.hao0.wepay.model.enums.WepayField;
11 | import me.hao0.wepay.serializer.BooleanDeserializer;
12 | import me.hao0.wepay.serializer.DateDeserializer;
13 | import me.hao0.wepay.serializer.FeeTypeDeserializer;
14 | import me.hao0.wepay.serializer.TradeStateDeserializer;
15 | import me.hao0.wepay.serializer.TradeTypeDeserializer;
16 | import java.io.Serializable;
17 | import java.util.Date;
18 | import java.util.List;
19 |
20 | /**
21 | * 微信查询订单对象
22 | * Author: haolin
23 | * Email: haolin.h0@gmail.com
24 | * Date: 27/11/15
25 | * @since 1.0.0
26 | */
27 | public class WePayOrder implements Serializable {
28 |
29 | private static final long serialVersionUID = -3808893700552515824L;
30 |
31 | /**
32 | * 用户openId
33 | */
34 | @JsonProperty(WepayField.OPEN_ID)
35 | private String openId;
36 |
37 | /**
38 | * 用户是否关注公众号
39 | */
40 | @JsonProperty(WepayField.IS_SUBSCRIBE)
41 | @JsonDeserialize(using = BooleanDeserializer.class)
42 | private Boolean subscribe;
43 |
44 | /**
45 | * 交易类型
46 | */
47 | @JsonProperty(WepayField.TRADE_TYPE)
48 | @JsonDeserialize(using = TradeTypeDeserializer.class)
49 | private TradeType tradeType;
50 |
51 | /**
52 | * 银行类型
53 | */
54 | @JsonProperty(WepayField.BANK_TYPE)
55 | private String bankType;
56 |
57 | /**
58 | * 总金额
59 | */
60 | @JsonProperty(WepayField.TOTAL_FEE)
61 | private Integer totalFee;
62 |
63 | @JsonProperty(WepayField.FEE_TYPE)
64 | @JsonDeserialize(using = FeeTypeDeserializer.class)
65 | private FeeType feeType;
66 |
67 | /**
68 | * 微信订单好
69 | */
70 | @JsonProperty(WepayField.TRANSACTION_ID)
71 | private String transactionId;
72 |
73 | /**
74 | * 商户订单号
75 | */
76 | @JsonProperty(WepayField.OUT_TRADE_NO)
77 | private String outTradeNo;
78 |
79 | /**
80 | * 附加数据
81 | */
82 | private String attach;
83 |
84 | /**
85 | * 支付完成时间
86 | */
87 | @JsonProperty(WepayField.TIME_END)
88 | @JsonDeserialize(using = DateDeserializer.class)
89 | private Date timeEnd;
90 |
91 | /**
92 | * 交易状态
93 | */
94 | @JsonProperty(WepayField.TRADE_STATE)
95 | @JsonDeserialize(using = TradeStateDeserializer.class)
96 | private TradeState tradeState;
97 |
98 | /**
99 | * 交易状态描述
100 | */
101 | @JsonProperty(WepayField.TRADE_STATE_DESC)
102 | private String tradeStateDesc;
103 |
104 | /**
105 | * 现金支付金额
106 | */
107 | @JsonProperty(WepayField.CASH_FEE)
108 | private Integer cachFee;
109 |
110 | @JsonProperty(WepayField.CASH_FEE_TYPE)
111 | @JsonDeserialize(using = FeeTypeDeserializer.class)
112 | private FeeType cashFeeType;
113 |
114 | /**
115 | * 设备号
116 | */
117 | @JsonProperty(WepayField.DEVICE_INFO)
118 | private String deviceInfo;
119 |
120 | /**
121 | * 代金券或立减优惠金额(分)
122 | */
123 | @JsonProperty(WepayField.COUPON_FEE)
124 | private Integer couponFee;
125 |
126 | /**
127 | * 代金券或立减优惠使用数量
128 | */
129 | @JsonProperty(WepayField.COUPON_COUNT)
130 | private Integer couponCount;
131 |
132 | /**
133 | * 代金券或立减优惠明细
134 | */
135 | @JsonIgnore
136 | private List coupons;
137 |
138 | public String getOpenId() {
139 | return openId;
140 | }
141 |
142 | public void setOpenId(String openId) {
143 | this.openId = openId;
144 | }
145 |
146 | public Boolean getSubscribe() {
147 | return subscribe;
148 | }
149 |
150 | public void setSubscribe(Boolean subscribe) {
151 | this.subscribe = subscribe;
152 | }
153 |
154 | public TradeType getTradeType() {
155 | return tradeType;
156 | }
157 |
158 | public void setTradeType(TradeType tradeType) {
159 | this.tradeType = tradeType;
160 | }
161 |
162 | public String getBankType() {
163 | return bankType;
164 | }
165 |
166 | public void setBankType(String bankType) {
167 | this.bankType = bankType;
168 | }
169 |
170 | public Integer getTotalFee() {
171 | return totalFee;
172 | }
173 |
174 | public void setTotalFee(Integer totalFee) {
175 | this.totalFee = totalFee;
176 | }
177 |
178 | public FeeType getFeeType() {
179 | return feeType;
180 | }
181 |
182 | public void setFeeType(FeeType feeType) {
183 | this.feeType = feeType;
184 | }
185 |
186 | public String getTransactionId() {
187 | return transactionId;
188 | }
189 |
190 | public void setTransactionId(String transactionId) {
191 | this.transactionId = transactionId;
192 | }
193 |
194 | public String getOutTradeNo() {
195 | return outTradeNo;
196 | }
197 |
198 | public void setOutTradeNo(String outTradeNo) {
199 | this.outTradeNo = outTradeNo;
200 | }
201 |
202 | public String getAttach() {
203 | return attach;
204 | }
205 |
206 | public void setAttach(String attach) {
207 | this.attach = attach;
208 | }
209 |
210 | public Date getTimeEnd() {
211 | return timeEnd;
212 | }
213 |
214 | public void setTimeEnd(Date timeEnd) {
215 | this.timeEnd = timeEnd;
216 | }
217 |
218 | public TradeState getTradeState() {
219 | return tradeState;
220 | }
221 |
222 | public void setTradeState(TradeState tradeState) {
223 | this.tradeState = tradeState;
224 | }
225 |
226 | public String getTradeStateDesc() {
227 | return tradeStateDesc;
228 | }
229 |
230 | public void setTradeStateDesc(String tradeStateDesc) {
231 | this.tradeStateDesc = tradeStateDesc;
232 | }
233 |
234 | public Integer getCachFee() {
235 | return cachFee;
236 | }
237 |
238 | public void setCachFee(Integer cachFee) {
239 | this.cachFee = cachFee;
240 | }
241 |
242 | public FeeType getCashFeeType() {
243 | return cashFeeType;
244 | }
245 |
246 | public void setCashFeeType(FeeType cashFeeType) {
247 | this.cashFeeType = cashFeeType;
248 | }
249 |
250 | public String getDeviceInfo() {
251 | return deviceInfo;
252 | }
253 |
254 | public void setDeviceInfo(String deviceInfo) {
255 | this.deviceInfo = deviceInfo;
256 | }
257 |
258 | public Integer getCouponFee() {
259 | return couponFee;
260 | }
261 |
262 | public void setCouponFee(Integer couponFee) {
263 | this.couponFee = couponFee;
264 | }
265 |
266 | public Integer getCouponCount() {
267 | return couponCount;
268 | }
269 |
270 | public void setCouponCount(Integer couponCount) {
271 | this.couponCount = couponCount;
272 | }
273 |
274 | public List getCoupons() {
275 | return coupons;
276 | }
277 |
278 | public void setCoupons(List coupons) {
279 | this.coupons = coupons;
280 | }
281 |
282 | @Override
283 | public String toString() {
284 | return "WePayOrder{" +
285 | "openId='" + openId + '\'' +
286 | ", subscribe=" + subscribe +
287 | ", tradeType=" + tradeType +
288 | ", bankType='" + bankType + '\'' +
289 | ", totalFee=" + totalFee +
290 | ", feeType=" + feeType +
291 | ", transactionId='" + transactionId + '\'' +
292 | ", outTradeNo='" + outTradeNo + '\'' +
293 | ", attach='" + attach + '\'' +
294 | ", timeEnd=" + timeEnd +
295 | ", tradeState=" + tradeState +
296 | ", tradeStateDesc='" + tradeStateDesc + '\'' +
297 | ", cachFee=" + cachFee +
298 | ", cashFeeType=" + cashFeeType +
299 | ", deviceInfo='" + deviceInfo + '\'' +
300 | ", couponFee=" + couponFee +
301 | ", couponCount=" + couponCount +
302 | ", coupons=" + coupons +
303 | '}';
304 | }
305 | }
306 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/pay/AppPayResponse.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.pay;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 公众号支付响应对象
7 | * Author: haolin
8 | * Email: haolin.h0@gmail.com
9 | * Date: 26/11/15
10 | */
11 | public class AppPayResponse implements Serializable {
12 |
13 | private static final long serialVersionUID = 2540820967097836895L;
14 |
15 | /**
16 | * 微信APPID
17 | */
18 | private String appId;
19 |
20 | /**
21 | * 商户Id
22 | */
23 | private String partnerId;
24 |
25 | /**
26 | * 预支付ID
27 | */
28 | private String prepayId;
29 |
30 | /**
31 | * 时间戳(s)
32 | */
33 | private String timeStamp;
34 |
35 | /**
36 | * 随机字符串
37 | */
38 | private String nonceStr;
39 |
40 | /**
41 | * package
42 | */
43 | private String pkg = "Sign=WXPay";
44 |
45 | /**
46 | * 签名
47 | */
48 | private String paySign;
49 |
50 | public AppPayResponse(String appId, String partnerId, String prepayId, String timeStamp, String nonceStr, String paySign) {
51 | this.appId = appId;
52 | this.partnerId = partnerId;
53 | this.prepayId = prepayId;
54 | this.timeStamp = timeStamp;
55 | this.nonceStr = nonceStr;
56 | this.paySign = paySign;
57 | }
58 |
59 | public String getAppId() {
60 | return appId;
61 | }
62 |
63 | public String getTimeStamp() {
64 | return timeStamp;
65 | }
66 |
67 | public String getNonceStr() {
68 | return nonceStr;
69 | }
70 |
71 | public String getPkg() {
72 | return pkg;
73 | }
74 |
75 | public String getPaySign() {
76 | return paySign;
77 | }
78 |
79 | public String getPartnerId() {
80 | return partnerId;
81 | }
82 |
83 | public String getPrepayId() {
84 | return prepayId;
85 | }
86 |
87 | @Override
88 | public String toString() {
89 | return "AppPayResponse{" +
90 | "appId='" + appId + '\'' +
91 | ", partnerId='" + partnerId + '\'' +
92 | ", prepayId='" + prepayId + '\'' +
93 | ", timeStamp='" + timeStamp + '\'' +
94 | ", nonceStr='" + nonceStr + '\'' +
95 | ", pkg='" + pkg + '\'' +
96 | ", paySign='" + paySign + '\'' +
97 | '}';
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/pay/JsPayRequest.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.pay;
2 |
3 |
4 | /**
5 | * JS支付请求对象
6 | * Author: haolin
7 | * Email: haolin.h0@gmail.com
8 | * Date: 26/11/15
9 | * @since 1.0.0
10 | */
11 | public class JsPayRequest extends PayRequest {
12 |
13 | /**
14 | * 用户标识
15 | * {@link me.hao0.wepay.model.enums.WepayField#OPEN_ID}
16 | */
17 | private String openId;
18 |
19 | public String getOpenId() {
20 | return openId;
21 | }
22 |
23 | public void setOpenId(String openId) {
24 | this.openId = openId;
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | return "JsPayRequest{" +
30 | "openId='" + openId + '\'' +
31 | "} " + super.toString();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/pay/JsPayResponse.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.pay;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 公众号支付响应对象
7 | * Author: haolin
8 | * Email: haolin.h0@gmail.com
9 | * Date: 26/11/15
10 | */
11 | public class JsPayResponse implements Serializable {
12 |
13 | private static final long serialVersionUID = 2540820967097836895L;
14 |
15 | /**
16 | * 微信APPID
17 | */
18 | private String appId;
19 |
20 | /**
21 | * 时间戳(s)
22 | */
23 | private String timeStamp;
24 |
25 | /**
26 | * 随机字符串
27 | */
28 | private String nonceStr;
29 |
30 | /**
31 | * 预支付ID串,如: prepare_id=xxx
32 | * 注意: JS前端调用时的字段名为package,与java关键字冲突
33 | */
34 | private String pkg;
35 |
36 | /**
37 | * 签名类型MD5
38 | */
39 | private String signType;
40 |
41 | /**
42 | * 签名
43 | */
44 | private String paySign;
45 |
46 | public JsPayResponse(String appId, String timeStamp, String nonceStr, String pkg, String signType, String paySign) {
47 | this.appId = appId;
48 | this.timeStamp = timeStamp;
49 | this.nonceStr = nonceStr;
50 | this.pkg = pkg;
51 | this.signType = signType;
52 | this.paySign = paySign;
53 | }
54 |
55 | public String getAppId() {
56 | return appId;
57 | }
58 |
59 | public String getTimeStamp() {
60 | return timeStamp;
61 | }
62 |
63 | public String getNonceStr() {
64 | return nonceStr;
65 | }
66 |
67 | public String getPkg() {
68 | return pkg;
69 | }
70 |
71 | public String getSignType() {
72 | return signType;
73 | }
74 |
75 | public String getPaySign() {
76 | return paySign;
77 | }
78 |
79 | @Override
80 | public String toString() {
81 | return "JsPayResponse{" +
82 | "appId='" + appId + '\'' +
83 | ", timeStamp='" + timeStamp + '\'' +
84 | ", nonceStr='" + nonceStr + '\'' +
85 | ", pkg='" + pkg + '\'' +
86 | ", signType='" + signType + '\'' +
87 | ", paySign='" + paySign + '\'' +
88 | '}';
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/pay/PayRequest.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.pay;
2 |
3 | import me.hao0.wepay.annotation.Optional;
4 | import me.hao0.wepay.model.enums.FeeType;
5 | import java.io.Serializable;
6 |
7 | /**
8 | * 支付请求对象
9 | * Author: haolin
10 | * Email: haolin.h0@gmail.com
11 | * Date: 26/11/15
12 | * @since 1.0.0
13 | */
14 | public class PayRequest implements Serializable {
15 |
16 | /**
17 | * 商品描述
18 | * {@link me.hao0.wepay.model.enums.WepayField#BODY}
19 | */
20 | private String body;
21 |
22 | /**
23 | * 业务系统唯一订单号
24 | * {@link me.hao0.wepay.model.enums.WepayField#OUT_TRADE_NO}
25 | */
26 | private String outTradeNo;
27 |
28 | /**
29 | * 总金额(分)
30 | * {@link me.hao0.wepay.model.enums.WepayField#TOTAL_FEE}
31 | */
32 | private Integer totalFee;
33 |
34 | /**
35 | * 客户端IP
36 | * {@link me.hao0.wepay.model.enums.WepayField#SPBILL_CREATE_IP}
37 | */
38 | private String clientIp;
39 |
40 | /**
41 | * 通知URL
42 | * {@link me.hao0.wepay.model.enums.WepayField#NOTIFY_URL}
43 | */
44 | private String notifyUrl;
45 |
46 | /**
47 | * 设备号
48 | * {@link me.hao0.wepay.model.enums.WepayField#DEVICE_INFO}
49 | */
50 | @Optional
51 | private String deviceInfo;
52 |
53 | /**
54 | * 附加信息
55 | * {@link me.hao0.wepay.model.enums.WepayField#ATTACH}
56 | */
57 | @Optional
58 | private String attach;
59 |
60 | /**
61 | * 商品详情
62 | * {@link me.hao0.wepay.model.enums.WepayField#DETAIL}
63 | */
64 | @Optional
65 | private String detail;
66 |
67 | /**
68 | * 货币类型
69 | * {@link me.hao0.wepay.model.enums.WepayField#FEE_TYPE}
70 | */
71 | private FeeType feeType = FeeType.CNY;
72 |
73 | /**
74 | * 交易开始时间
75 | * {@link me.hao0.wepay.model.enums.WepayField#TIME_START}
76 | */
77 | private String timeStart;
78 |
79 | /**
80 | * 交易结束时间
81 | * {@link me.hao0.wepay.model.enums.WepayField#TIME_EXPIRE}
82 | */
83 | @Optional
84 | private String timeExpire;
85 |
86 | /**
87 | * 商品标记
88 | * {@link me.hao0.wepay.model.enums.WepayField#GOODS_TAG}
89 | */
90 | @Optional
91 | private String goodsTag;
92 |
93 | /**
94 | * 指定支付方式
95 | * {@link me.hao0.wepay.model.enums.WepayField#LIMIT_PAY}
96 | */
97 | @Optional
98 | private String limitPay;
99 |
100 | public String getBody() {
101 | return body;
102 | }
103 |
104 | public void setBody(String body) {
105 | this.body = body;
106 | }
107 |
108 | public String getOutTradeNo() {
109 | return outTradeNo;
110 | }
111 |
112 | public void setOutTradeNo(String outTradeNo) {
113 | this.outTradeNo = outTradeNo;
114 | }
115 |
116 | public Integer getTotalFee() {
117 | return totalFee;
118 | }
119 |
120 | public void setTotalFee(Integer totalFee) {
121 | this.totalFee = totalFee;
122 | }
123 |
124 | public String getClientIp() {
125 | return clientIp;
126 | }
127 |
128 | public void setClientIp(String clientIp) {
129 | this.clientIp = clientIp;
130 | }
131 |
132 | public String getNotifyUrl() {
133 | return notifyUrl;
134 | }
135 |
136 | public void setNotifyUrl(String notifyUrl) {
137 | this.notifyUrl = notifyUrl;
138 | }
139 |
140 | public String getDeviceInfo() {
141 | return deviceInfo;
142 | }
143 |
144 | public void setDeviceInfo(String deviceInfo) {
145 | this.deviceInfo = deviceInfo;
146 | }
147 |
148 | public String getAttach() {
149 | return attach;
150 | }
151 |
152 | public void setAttach(String attach) {
153 | this.attach = attach;
154 | }
155 |
156 | public String getDetail() {
157 | return detail;
158 | }
159 |
160 | public void setDetail(String detail) {
161 | this.detail = detail;
162 | }
163 |
164 | public FeeType getFeeType() {
165 | return feeType;
166 | }
167 |
168 | public void setFeeType(FeeType feeType) {
169 | this.feeType = feeType;
170 | }
171 |
172 | public String getTimeStart() {
173 | return timeStart;
174 | }
175 |
176 | public void setTimeStart(String timeStart) {
177 | this.timeStart = timeStart;
178 | }
179 |
180 | public String getTimeExpire() {
181 | return timeExpire;
182 | }
183 |
184 | public void setTimeExpire(String timeExpire) {
185 | this.timeExpire = timeExpire;
186 | }
187 |
188 | public String getGoodsTag() {
189 | return goodsTag;
190 | }
191 |
192 | public void setGoodsTag(String goodsTag) {
193 | this.goodsTag = goodsTag;
194 | }
195 |
196 | public String getLimitPay() {
197 | return limitPay;
198 | }
199 |
200 | public void setLimitPay(String limitPay) {
201 | this.limitPay = limitPay;
202 | }
203 |
204 | @Override
205 | public String toString() {
206 | return "PayDetail{" +
207 | "body='" + body + '\'' +
208 | ", outTradeNo='" + outTradeNo + '\'' +
209 | ", totalFee=" + totalFee +
210 | ", clientIp='" + clientIp + '\'' +
211 | ", notifyUrl='" + notifyUrl + '\'' +
212 | ", deviceInfo='" + deviceInfo + '\'' +
213 | ", attach='" + attach + '\'' +
214 | ", detail='" + detail + '\'' +
215 | ", feeType=" + feeType +
216 | ", timeStart='" + timeStart + '\'' +
217 | ", timeExpire='" + timeExpire + '\'' +
218 | ", goodsTag='" + goodsTag + '\'' +
219 | ", limitPay='" + limitPay + '\'' +
220 | '}';
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/pay/QrPayRequest.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.pay;
2 |
3 |
4 | import me.hao0.wepay.annotation.Optional;
5 |
6 | /**
7 | * 二维码支付请求对象
8 | * Author: haolin
9 | * Email: haolin.h0@gmail.com
10 | * Date: 26/11/15
11 | * @since 1.0.0
12 | */
13 | public class QrPayRequest extends PayRequest {
14 |
15 | /**
16 | * 商品ID
17 | * {@link me.hao0.wepay.model.enums.WepayField#PRODUCT_ID}
18 | */
19 | @Optional(any = false)
20 | private String productId;
21 |
22 | public String getProductId() {
23 | return productId;
24 | }
25 |
26 | public void setProductId(String productId) {
27 | this.productId = productId;
28 | }
29 |
30 | @Override
31 | public String toString() {
32 | return "QrPayRequest{" +
33 | "productId='" + productId + '\'' +
34 | "} " + super.toString();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/pay/QrPayResponse.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.pay;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 二维码支付(NATIVE)响应结果
7 | * Author: haolin
8 | * Email: haolin.h0@gmail.com
9 | */
10 | public class QrPayResponse implements Serializable {
11 |
12 | private static final long serialVersionUID = 1383835653965951921L;
13 |
14 | /**
15 | * 预支付ID
16 | */
17 | private String prepayId;
18 |
19 | /**
20 | * 支付二维码链接
21 | */
22 | private String codeUrl;
23 |
24 | public String getPrepayId() {
25 | return prepayId;
26 | }
27 |
28 | public void setPrepayId(String prepayId) {
29 | this.prepayId = prepayId;
30 | }
31 |
32 | public String getCodeUrl() {
33 | return codeUrl;
34 | }
35 |
36 | public void setCodeUrl(String codeUrl) {
37 | this.codeUrl = codeUrl;
38 | }
39 |
40 | @Override
41 | public String toString() {
42 | return "QrPayResponse{" +
43 | "prepayId='" + prepayId + '\'' +
44 | ", codeUrl='" + codeUrl + '\'' +
45 | '}';
46 | }
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/refund/RefundApplyRequest.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.refund;
2 |
3 | import me.hao0.wepay.annotation.Optional;
4 | import me.hao0.wepay.model.enums.FeeType;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * 退款请求对象
10 | * Author: haolin
11 | * Email: haolin.h0@gmail.com
12 | * Date: 28/11/15
13 | * @since 1.0.0
14 | */
15 | public class RefundApplyRequest implements Serializable {
16 |
17 | private static final long serialVersionUID = 5046932866574485686L;
18 |
19 | /**
20 | * 设备号
21 | */
22 | @Optional
23 | private String deviceInfo;
24 |
25 | /**
26 | * 微信订单号,与outTradeNo二选一
27 | */
28 | private String transactionId;
29 |
30 | /**
31 | * 商户订单号,与transactionId二选一
32 | */
33 | private String outTradeNo;
34 |
35 | /**
36 | * 商户退款单号
37 | */
38 | private String outRefundNo;
39 |
40 | /**
41 | * 订单总金额
42 | */
43 | private Integer totalFee;
44 |
45 | /**
46 | * 退款金额
47 | */
48 | private Integer refundFee;
49 |
50 | /**
51 | * 货币类型
52 | */
53 | @Optional
54 | private FeeType refundFeeType = FeeType.CNY;
55 |
56 | /**
57 | * 操作员
58 | */
59 | private String opUserId;
60 |
61 | public String getDeviceInfo() {
62 | return deviceInfo;
63 | }
64 |
65 | public void setDeviceInfo(String deviceInfo) {
66 | this.deviceInfo = deviceInfo;
67 | }
68 |
69 | public String getTransactionId() {
70 | return transactionId;
71 | }
72 |
73 | public void setTransactionId(String transactionId) {
74 | this.transactionId = transactionId;
75 | }
76 |
77 | public String getOutTradeNo() {
78 | return outTradeNo;
79 | }
80 |
81 | public void setOutTradeNo(String outTradeNo) {
82 | this.outTradeNo = outTradeNo;
83 | }
84 |
85 | public String getOutRefundNo() {
86 | return outRefundNo;
87 | }
88 |
89 | public void setOutRefundNo(String outRefundNo) {
90 | this.outRefundNo = outRefundNo;
91 | }
92 |
93 | public Integer getTotalFee() {
94 | return totalFee;
95 | }
96 |
97 | public void setTotalFee(Integer totalFee) {
98 | this.totalFee = totalFee;
99 | }
100 |
101 | public Integer getRefundFee() {
102 | return refundFee;
103 | }
104 |
105 | public void setRefundFee(Integer refundFee) {
106 | this.refundFee = refundFee;
107 | }
108 |
109 | public FeeType getRefundFeeType() {
110 | return refundFeeType;
111 | }
112 |
113 | public void setRefundFeeType(FeeType refundFeeType) {
114 | this.refundFeeType = refundFeeType;
115 | }
116 |
117 | public String getOpUserId() {
118 | return opUserId;
119 | }
120 |
121 | public void setOpUserId(String opUserId) {
122 | this.opUserId = opUserId;
123 | }
124 |
125 | @Override
126 | public String toString() {
127 | return "RefundRequest{" +
128 | "deviceInfo='" + deviceInfo + '\'' +
129 | ", transactionId='" + transactionId + '\'' +
130 | ", outTradeNo='" + outTradeNo + '\'' +
131 | ", outRefundNo='" + outRefundNo + '\'' +
132 | ", totalFee=" + totalFee +
133 | ", refundFee=" + refundFee +
134 | ", refundFeeType=" + refundFeeType +
135 | ", opUserId='" + opUserId + '\'' +
136 | '}';
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/refund/RefundApplyResponse.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.refund;
2 |
3 | import com.fasterxml.jackson.annotation.JsonProperty;
4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5 | import me.hao0.wepay.annotation.Optional;
6 | import me.hao0.wepay.model.enums.FeeType;
7 | import me.hao0.wepay.model.enums.RefundChannel;
8 | import me.hao0.wepay.model.enums.WepayField;
9 | import me.hao0.wepay.serializer.FeeTypeDeserializer;
10 | import me.hao0.wepay.serializer.RefundChannelDeserializer;
11 |
12 | import java.io.Serializable;
13 |
14 | /**
15 | * 退款结果
16 | * Author: haolin
17 | * Email: haolin.h0@gmail.com
18 | * Date: 28/11/15
19 | * @since 1.0.0
20 | */
21 | public class RefundApplyResponse implements Serializable {
22 |
23 | private static final long serialVersionUID = -8303581191923588820L;
24 |
25 | /**
26 | * 设备号
27 | */
28 | @Optional
29 | @JsonProperty(WepayField.DEVICE_INFO)
30 | private String deviceInfo;
31 |
32 | /**
33 | * 随机字符串
34 | */
35 | @JsonProperty(WepayField.NONCE_STR)
36 | private String nonceStr;
37 |
38 | /**
39 | * 微信订单号
40 | */
41 | @JsonProperty(WepayField.TRANSACTION_ID)
42 | private String transactionId;
43 |
44 | /**
45 | * 商户订单号
46 | */
47 | @JsonProperty(WepayField.OUT_TRADE_NO)
48 | private String outTradeNo;
49 |
50 | /**
51 | * 商户退款单号
52 | */
53 | @JsonProperty(WepayField.OUT_REFUND_NO)
54 | private String outRefundNo;
55 |
56 | /**
57 | * 微信退款但号
58 | */
59 | @JsonProperty(WepayField.REFUND_ID)
60 | private String refundId;
61 |
62 | /**
63 | * 退款渠道
64 | */
65 | @JsonProperty(WepayField.REFUND_CHANNEL)
66 | @JsonDeserialize(using = RefundChannelDeserializer.class)
67 | private RefundChannel channel;
68 |
69 | /**
70 | * 退款金额
71 | */
72 | @JsonProperty(WepayField.REFUND_FEE)
73 | private Integer refundFee;
74 |
75 | /**
76 | * 订单总金额
77 | */
78 | @JsonProperty(WepayField.TOTAL_FEE)
79 | private Integer totalFee;
80 |
81 | /**
82 | * 货币类型
83 | */
84 | @JsonProperty(WepayField.FEE_TYPE)
85 | @JsonDeserialize(using = FeeTypeDeserializer.class)
86 | private FeeType feeType;
87 |
88 | /**
89 | * 现金支付金额
90 | */
91 | @JsonProperty(WepayField.CASH_FEE)
92 | private Integer cashFee;
93 |
94 | /**
95 | * 现金退款金额
96 | */
97 | @JsonProperty(WepayField.CASH_REFUND_FEE)
98 | private Integer cashRefundFee;
99 |
100 | /**
101 | * 代金券或立减优惠退款金额
102 | */
103 | @JsonProperty(WepayField.COUPON_REFUND_FEE)
104 | private Integer couponRefundFee;
105 |
106 | /**
107 | * 代金券或立减优惠使用数量
108 | */
109 | @JsonProperty(WepayField.COUPON_REFUND_COUNT)
110 | private Integer couponRefundCount;
111 |
112 | /**
113 | * 代金券或立减优惠ID
114 | */
115 | @JsonProperty(WepayField.COUPON_REFUND_ID)
116 | private Integer couponRefundId;
117 |
118 | public String getDeviceInfo() {
119 | return deviceInfo;
120 | }
121 |
122 | public void setDeviceInfo(String deviceInfo) {
123 | this.deviceInfo = deviceInfo;
124 | }
125 |
126 | public String getNonceStr() {
127 | return nonceStr;
128 | }
129 |
130 | public void setNonceStr(String nonceStr) {
131 | this.nonceStr = nonceStr;
132 | }
133 |
134 | public String getTransactionId() {
135 | return transactionId;
136 | }
137 |
138 | public void setTransactionId(String transactionId) {
139 | this.transactionId = transactionId;
140 | }
141 |
142 | public String getOutTradeNo() {
143 | return outTradeNo;
144 | }
145 |
146 | public void setOutTradeNo(String outTradeNo) {
147 | this.outTradeNo = outTradeNo;
148 | }
149 |
150 | public String getOutRefundNo() {
151 | return outRefundNo;
152 | }
153 |
154 | public void setOutRefundNo(String outRefundNo) {
155 | this.outRefundNo = outRefundNo;
156 | }
157 |
158 | public String getRefundId() {
159 | return refundId;
160 | }
161 |
162 | public void setRefundId(String refundId) {
163 | this.refundId = refundId;
164 | }
165 |
166 | public RefundChannel getChannel() {
167 | return channel;
168 | }
169 |
170 | public void setChannel(RefundChannel channel) {
171 | this.channel = channel;
172 | }
173 |
174 | public Integer getRefundFee() {
175 | return refundFee;
176 | }
177 |
178 | public void setRefundFee(Integer refundFee) {
179 | this.refundFee = refundFee;
180 | }
181 |
182 | public Integer getTotalFee() {
183 | return totalFee;
184 | }
185 |
186 | public void setTotalFee(Integer totalFee) {
187 | this.totalFee = totalFee;
188 | }
189 |
190 | public FeeType getFeeType() {
191 | return feeType;
192 | }
193 |
194 | public void setFeeType(FeeType feeType) {
195 | this.feeType = feeType;
196 | }
197 |
198 | public Integer getCashFee() {
199 | return cashFee;
200 | }
201 |
202 | public void setCashFee(Integer cashFee) {
203 | this.cashFee = cashFee;
204 | }
205 |
206 | public Integer getCashRefundFee() {
207 | return cashRefundFee;
208 | }
209 |
210 | public void setCashRefundFee(Integer cashRefundFee) {
211 | this.cashRefundFee = cashRefundFee;
212 | }
213 |
214 | public Integer getCouponRefundFee() {
215 | return couponRefundFee;
216 | }
217 |
218 | public void setCouponRefundFee(Integer couponRefundFee) {
219 | this.couponRefundFee = couponRefundFee;
220 | }
221 |
222 | public Integer getCouponRefundCount() {
223 | return couponRefundCount;
224 | }
225 |
226 | public void setCouponRefundCount(Integer couponRefundCount) {
227 | this.couponRefundCount = couponRefundCount;
228 | }
229 |
230 | public Integer getCouponRefundId() {
231 | return couponRefundId;
232 | }
233 |
234 | public void setCouponRefundId(Integer couponRefundId) {
235 | this.couponRefundId = couponRefundId;
236 | }
237 |
238 | @Override
239 | public String toString() {
240 | return "RefundResponse{" +
241 | "deviceInfo='" + deviceInfo + '\'' +
242 | ", nonceStr='" + nonceStr + '\'' +
243 | ", transactionId='" + transactionId + '\'' +
244 | ", outTradeNo='" + outTradeNo + '\'' +
245 | ", outRefundNo='" + outRefundNo + '\'' +
246 | ", refundId='" + refundId + '\'' +
247 | ", channel=" + channel +
248 | ", refundFee=" + refundFee +
249 | ", totalFee=" + totalFee +
250 | ", feeType=" + feeType +
251 | ", cashFee=" + cashFee +
252 | ", cashRefundFee=" + cashRefundFee +
253 | ", couponRefundFee=" + couponRefundFee +
254 | ", couponRefundCount=" + couponRefundCount +
255 | ", couponRefundId=" + couponRefundId +
256 | '}';
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/refund/RefundItem.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.refund;
2 |
3 | import me.hao0.wepay.model.common.Coupon;
4 | import me.hao0.wepay.model.enums.RefundChannel;
5 | import me.hao0.wepay.model.enums.RefundStatus;
6 | import java.io.Serializable;
7 | import java.util.List;
8 |
9 | /**
10 | * 单笔退款
11 | * Author: haolin
12 | * Email: haolin.h0@gmail.com
13 | * Date: 1/12/15
14 | * @since 1.0.0
15 | */
16 | public class RefundItem implements Serializable {
17 |
18 | private static final long serialVersionUID = -8803509387441693049L;
19 |
20 | /**
21 | * 商户退款单号
22 | */
23 | private String outRefundNo;
24 |
25 | /**
26 | * 微信退款单号
27 | */
28 | private String refundId;
29 |
30 | /**
31 | * 退款渠道
32 | */
33 | private RefundChannel channel;
34 |
35 | /**
36 | * 申请退款金额, 可以做部分退款
37 | */
38 | private Integer refundFee;
39 |
40 | /**
41 | * 退款金额, = 申请退款金额-非充值代金券退款金额,退款金额<=申请退款金额
42 | */
43 | private Integer settlementRefundFee;
44 |
45 | /**
46 | * 退款状态
47 | * @see RefundStatus
48 | */
49 | private RefundStatus refundStatus;
50 |
51 | /**
52 | * 取当前退款单的退款入账方
53 | * 1)退回银行卡:
54 | * {银行名称}{卡类型}{卡尾号}
55 | * 2)退回支付用户零钱:
56 | * 支付用户零钱
57 | */
58 | private String refundRecvAccout;
59 |
60 | /**
61 | * 代金券或立减优惠退款金额
62 | */
63 | private Integer couponRefundFee;
64 |
65 | /**
66 | * 代金券或立减优惠退款项
67 | */
68 | private List coupons;
69 |
70 | public String getOutRefundNo() {
71 | return outRefundNo;
72 | }
73 |
74 | public void setOutRefundNo(String outRefundNo) {
75 | this.outRefundNo = outRefundNo;
76 | }
77 |
78 | public String getRefundId() {
79 | return refundId;
80 | }
81 |
82 | public void setRefundId(String refundId) {
83 | this.refundId = refundId;
84 | }
85 |
86 | public RefundChannel getChannel() {
87 | return channel;
88 | }
89 |
90 | public void setChannel(RefundChannel channel) {
91 | this.channel = channel;
92 | }
93 |
94 | public Integer getRefundFee() {
95 | return refundFee;
96 | }
97 |
98 | public void setRefundFee(Integer refundFee) {
99 | this.refundFee = refundFee;
100 | }
101 |
102 | public Integer getSettlementRefundFee() {
103 | return settlementRefundFee;
104 | }
105 |
106 | public void setSettlementRefundFee(Integer settlementRefundFee) {
107 | this.settlementRefundFee = settlementRefundFee;
108 | }
109 |
110 | public RefundStatus getRefundStatus() {
111 | return refundStatus;
112 | }
113 |
114 | public void setRefundStatus(RefundStatus refundStatus) {
115 | this.refundStatus = refundStatus;
116 | }
117 |
118 | public String getRefundRecvAccout() {
119 | return refundRecvAccout;
120 | }
121 |
122 | public void setRefundRecvAccout(String refundRecvAccout) {
123 | this.refundRecvAccout = refundRecvAccout;
124 | }
125 |
126 | public Integer getCouponRefundFee() {
127 | return couponRefundFee;
128 | }
129 |
130 | public void setCouponRefundFee(Integer couponRefundFee) {
131 | this.couponRefundFee = couponRefundFee;
132 | }
133 |
134 | public List getCoupons() {
135 | return coupons;
136 | }
137 |
138 | public void setCoupons(List coupons) {
139 | this.coupons = coupons;
140 | }
141 |
142 | @Override
143 | public String toString() {
144 | return "RefundItem{" +
145 | "outRefundNo='" + outRefundNo + '\'' +
146 | ", refundId='" + refundId + '\'' +
147 | ", channel=" + channel +
148 | ", refundFee=" + refundFee +
149 | ", settlementRefundFee=" + settlementRefundFee +
150 | ", refundStatus=" + refundStatus +
151 | ", refundRecvAccout='" + refundRecvAccout + '\'' +
152 | ", couponRefundFee=" + couponRefundFee +
153 | ", coupons=" + coupons +
154 | '}';
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/model/refund/RefundQueryResponse.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.model.refund;
2 |
3 | import me.hao0.wepay.model.enums.FeeType;
4 |
5 | import java.io.Serializable;
6 | import java.util.List;
7 |
8 | /**
9 | * 退款查询对象
10 | * Author: haolin
11 | * Email: haolin.h0@gmail.com
12 | * Date: 1/12/15
13 | * @since 1.0.0
14 | */
15 | public class RefundQueryResponse implements Serializable {
16 |
17 | private static final long serialVersionUID = -3559898607397949643L;
18 |
19 | /**
20 | * 微信订单号
21 | */
22 | private String transactionId;
23 |
24 | /**
25 | * 商户订单号
26 | */
27 | private String outTradeNo;
28 |
29 | /**
30 | * 总金额
31 | */
32 | private Integer totalFee;
33 |
34 | /**
35 | * 货币类型
36 | */
37 | private FeeType feeType;
38 |
39 | /**
40 | * 现金支付金额
41 | */
42 | private Integer cashFee;
43 |
44 | /**
45 | * 退款项
46 | */
47 | private List items;
48 |
49 | public String getTransactionId() {
50 | return transactionId;
51 | }
52 |
53 | public void setTransactionId(String transactionId) {
54 | this.transactionId = transactionId;
55 | }
56 |
57 | public String getOutTradeNo() {
58 | return outTradeNo;
59 | }
60 |
61 | public void setOutTradeNo(String outTradeNo) {
62 | this.outTradeNo = outTradeNo;
63 | }
64 |
65 | public Integer getTotalFee() {
66 | return totalFee;
67 | }
68 |
69 | public void setTotalFee(Integer totalFee) {
70 | this.totalFee = totalFee;
71 | }
72 |
73 | public FeeType getFeeType() {
74 | return feeType;
75 | }
76 |
77 | public void setFeeType(FeeType feeType) {
78 | this.feeType = feeType;
79 | }
80 |
81 | public Integer getCashFee() {
82 | return cashFee;
83 | }
84 |
85 | public void setCashFee(Integer cashFee) {
86 | this.cashFee = cashFee;
87 | }
88 |
89 | public List getItems() {
90 | return items;
91 | }
92 |
93 | public void setItems(List items) {
94 | this.items = items;
95 | }
96 |
97 | @Override
98 | public String toString() {
99 | return "RefundQueryResponse{" +
100 | "transactionId='" + transactionId + '\'' +
101 | ", outTradeNo='" + outTradeNo + '\'' +
102 | ", totalFee=" + totalFee +
103 | ", feeType=" + feeType +
104 | ", cashFee=" + cashFee +
105 | ", items=" + items +
106 | '}';
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/serializer/BooleanDeserializer.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.serializer;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.databind.DeserializationContext;
5 | import com.fasterxml.jackson.databind.JsonDeserializer;
6 |
7 | import java.io.IOException;
8 |
9 | /**
10 | * 布尔反序列化器
11 | * Author: haolin
12 | * Email: haolin.h0@gmail.com
13 | * Date: 27/11/15
14 | * @since 1.0.0
15 | */
16 | public class BooleanDeserializer extends JsonDeserializer {
17 |
18 | @Override
19 | public Boolean deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
20 | String r = jp.getValueAsString();
21 | return "Y".equals(r);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/serializer/DateDeserializer.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.serializer;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.databind.DeserializationContext;
5 | import com.fasterxml.jackson.databind.JsonDeserializer;
6 | import me.hao0.common.date.Dates;
7 |
8 | import java.io.IOException;
9 | import java.util.Date;
10 |
11 | /**
12 | * 日期反序列化器
13 | */
14 | public class DateDeserializer extends JsonDeserializer {
15 |
16 | @Override
17 | public Date deserialize(JsonParser parser, DeserializationContext context)
18 | throws IOException {
19 | return Dates.toDate(parser.getValueAsString(), "yyyyMMddHHmmss");
20 | }
21 | }
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/serializer/FeeTypeDeserializer.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.serializer;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.core.JsonProcessingException;
5 | import com.fasterxml.jackson.databind.DeserializationContext;
6 | import com.fasterxml.jackson.databind.JsonDeserializer;
7 | import me.hao0.wepay.model.enums.FeeType;
8 | import java.io.IOException;
9 |
10 | /**
11 | * 交易类型反序列化器
12 | * Author: haolin
13 | * Email: haolin.h0@gmail.com
14 | * Date: 27/11/15
15 | * @since 1.0.0
16 | */
17 | public class FeeTypeDeserializer extends JsonDeserializer {
18 |
19 | @Override
20 | public FeeType deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
21 | return FeeType.from(jp.getValueAsString());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/serializer/RefundChannelDeserializer.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.serializer;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.databind.DeserializationContext;
5 | import com.fasterxml.jackson.databind.JsonDeserializer;
6 | import me.hao0.common.util.Strings;
7 | import me.hao0.wepay.model.enums.RefundChannel;
8 |
9 | import java.io.IOException;
10 |
11 | /**
12 | * 退款渠道反序列化器
13 | * Author: haolin
14 | * Email: haolin.h0@gmail.com
15 | * Date: 27/11/15
16 | * @since 1.0.0
17 | */
18 | public class RefundChannelDeserializer extends JsonDeserializer {
19 |
20 | @Override
21 | public RefundChannel deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
22 | String val = jp.getValueAsString();
23 | if (Strings.isNullOrEmpty(val)){
24 | return null;
25 | }
26 | return RefundChannel.from(val);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/serializer/TradeStateDeserializer.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.serializer;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.core.JsonProcessingException;
5 | import com.fasterxml.jackson.databind.DeserializationContext;
6 | import com.fasterxml.jackson.databind.JsonDeserializer;
7 | import me.hao0.wepay.model.enums.TradeState;
8 |
9 | import java.io.IOException;
10 |
11 | /**
12 | * 交易状态反序列化器
13 | * Author: haolin
14 | * Email: haolin.h0@gmail.com
15 | * Date: 27/11/15
16 | * @since 1.0.0
17 | */
18 | public class TradeStateDeserializer extends JsonDeserializer {
19 |
20 | @Override
21 | public TradeState deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
22 | return TradeState.from(jp.getValueAsString());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/serializer/TradeTypeDeserializer.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.serializer;
2 |
3 | import com.fasterxml.jackson.core.JsonParser;
4 | import com.fasterxml.jackson.core.JsonProcessingException;
5 | import com.fasterxml.jackson.databind.DeserializationContext;
6 | import com.fasterxml.jackson.databind.JsonDeserializer;
7 | import me.hao0.wepay.model.enums.TradeType;
8 |
9 | import java.io.IOException;
10 |
11 | /**
12 | * 交易类型反序列化器
13 | * Author: haolin
14 | * Email: haolin.h0@gmail.com
15 | * Date: 27/11/15
16 | * @since 1.0.0
17 | */
18 | public class TradeTypeDeserializer extends JsonDeserializer {
19 |
20 | @Override
21 | public TradeType deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
22 | return TradeType.from(jp.getValueAsString());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/util/Maps.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.util;
2 |
3 | import me.hao0.common.util.Strings;
4 | import me.hao0.common.xml.XmlReaders;
5 | import me.hao0.common.xml.XmlWriters;
6 | import org.w3c.dom.Node;
7 | import org.w3c.dom.NodeList;
8 | import java.util.Collections;
9 | import java.util.HashMap;
10 | import java.util.Map;
11 |
12 | /**
13 | * xml和map转换工具
14 | * Author: haolin
15 | * Email: haolin.h0@gmail.com
16 | * Date: 3/12/15
17 | * @since 1.0.0
18 | */
19 | public final class Maps {
20 |
21 | /**
22 | * 转换微信XML为Map(仅支持2级)
23 | * @param xml xml内容
24 | * @return Map对象
25 | */
26 | public static Map toMap(String xml){
27 | xml = xml.replaceAll("(\\r|\\n)", "");
28 | if (Strings.isNullOrEmpty(xml)){
29 | return Collections.emptyMap();
30 | }
31 | XmlReaders readers = XmlReaders.create(xml);
32 | return toMap(readers);
33 | }
34 |
35 | /**
36 | * 转换微信XML为Map(仅支持2级)
37 | * @param readers xmlReaders
38 | * @return Map对象
39 | */
40 | public static Map toMap(XmlReaders readers){
41 | Node root = readers.getNode("xml");
42 | if (root == null){
43 | return Collections.emptyMap();
44 | }
45 | NodeList children = root.getChildNodes();
46 | if (children.getLength() == 0){
47 | return Collections.emptyMap();
48 | }
49 | Map data = new HashMap<>(children.getLength());
50 | Node n;
51 | for (int i = 0; i params) {
64 | XmlWriters writers = XmlWriters.create();
65 | for (Map.Entry param : params.entrySet()){
66 | if (!Strings.isNullOrEmpty(param.getValue())){
67 | writers.element(param.getKey(), param.getValue());
68 | }
69 | }
70 | return writers.build();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/wepay-core/src/main/java/me/hao0/wepay/util/RandomStrs.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.util;
2 |
3 | import java.util.Random;
4 |
5 | /**
6 | * 随机字符串工具
7 | * Author: haolin
8 | * Email: haolin.h0@gmail.com
9 | * Date: 26/11/15
10 | * @since 1.0.0
11 | */
12 | public final class RandomStrs {
13 |
14 | private static final String seed = "abcdefghijklmnopqrstuvwxyz0123456789";
15 |
16 | private static final Random random = new Random();
17 |
18 | /**
19 | * 生成随机字符串
20 | * @param length 长度
21 | * @return 长度为length的字符串
22 | */
23 | public static String generate(Integer length) {
24 | StringBuilder sb = new StringBuilder();
25 | for (int i = 0; i < length; i++) {
26 | int number = random.nextInt(seed.length());
27 | sb.append(seed.charAt(number));
28 | }
29 | return sb.toString();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/wepay-core/src/test/java/me/hao0/wepay/WepayTest.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay;
2 |
3 | import me.hao0.common.date.Dates;
4 | import me.hao0.wepay.core.Wepay;
5 | import me.hao0.wepay.core.WepayBuilder;
6 | import me.hao0.wepay.model.bill.Bill;
7 | import me.hao0.wepay.model.bill.BillDetail;
8 | import me.hao0.wepay.model.bill.CommonBill;
9 | import me.hao0.wepay.model.bill.RefundBill;
10 | import me.hao0.wepay.model.order.WePayOrder;
11 | import me.hao0.wepay.model.pay.AppPayResponse;
12 | import me.hao0.wepay.model.pay.JsPayRequest;
13 | import me.hao0.wepay.model.pay.JsPayResponse;
14 | import me.hao0.wepay.model.pay.PayRequest;
15 | import me.hao0.wepay.model.pay.QrPayRequest;
16 | import me.hao0.wepay.model.pay.QrPayResponse;
17 | import me.hao0.wepay.model.refund.RefundApplyRequest;
18 | import me.hao0.wepay.model.refund.RefundApplyResponse;
19 | import me.hao0.wepay.model.refund.RefundQueryResponse;
20 | import org.junit.Before;
21 | import org.junit.Test;
22 | import java.io.IOException;
23 | import java.io.InputStream;
24 | import java.nio.file.Files;
25 | import java.nio.file.Path;
26 | import java.nio.file.Paths;
27 | import java.util.Properties;
28 | import static org.junit.Assert.*;
29 |
30 | /**
31 | * Author: haolin
32 | * Email: haolin.h0@gmail.com
33 | * Date: 25/11/15
34 | */
35 | public class WepayTest {
36 |
37 | private Wepay wepay;
38 |
39 | private String openId = "onN_8trIW7PSoXLMzMSWySb5jfdY";
40 |
41 | @Before
42 | public void init() throws IOException {
43 | Properties props = new Properties();
44 | InputStream in = Object.class.getResourceAsStream("/dev.properties");
45 | props.load(in);
46 | in.close();
47 |
48 | Path path = Paths.get("/Users/haolin/GitHub/wepay/wepay-core/src/test/resources/cert.p12");
49 | byte[] data = Files.readAllBytes(path);
50 |
51 | wepay = WepayBuilder.newBuilder(
52 | props.getProperty("appId"),
53 | props.getProperty("appKey"),
54 | props.getProperty("mchId"))
55 | //.certPasswd(props.getProperty("mchId"))
56 | //.certs(data)
57 | .build();
58 |
59 |
60 | }
61 |
62 | @Test
63 | public void testJsPay(){
64 | JsPayRequest request = new JsPayRequest();
65 | request.setBody("测试订单");
66 | request.setClientIp("127.0.0.1");
67 | request.setTotalFee(1);
68 | request.setNotifyUrl("http://www.xxx.com/notify");
69 | request.setOpenId(openId);
70 | request.setOutTradeNo("TEST12345678js");
71 | request.setTimeStart(Dates.now("yyyyMMddHHmmss"));
72 | JsPayResponse resp = wepay.pay().jsPay(request);
73 | assertNotNull(resp);
74 | System.out.println(resp);
75 | }
76 |
77 | @Test
78 | public void testQrPay(){
79 | QrPayRequest request = new QrPayRequest();
80 | request.setBody("测试订单");
81 | request.setClientIp("127.0.0.1");
82 | request.setTotalFee(1);
83 | request.setNotifyUrl("http://www.xxx.com/notify");
84 | request.setOutTradeNo("TEST1122334455");
85 | request.setTimeStart(Dates.now("yyyyMMddHHmmss"));
86 | QrPayResponse resp = wepay.pay().qrPay(request);
87 | assertNotNull(resp);
88 | System.out.println(resp);
89 | }
90 |
91 | @Test
92 | public void testQrPayConvert(){
93 | QrPayRequest request = new QrPayRequest();
94 | request.setBody("测试订单");
95 | request.setClientIp("127.0.0.1");
96 | request.setTotalFee(1);
97 | request.setNotifyUrl("http://www.xxx.com/notify");
98 | request.setOutTradeNo("TEST3344520");
99 | request.setTimeStart(Dates.now("yyyyMMddHHmmss"));
100 | QrPayResponse resp = wepay.pay().qrPay(request, Boolean.TRUE);
101 | assertNotNull(resp);
102 | System.out.println(resp);
103 | }
104 |
105 | @Test
106 | public void testAppPay(){
107 | PayRequest request = new PayRequest();
108 | request.setBody("测试订单");
109 | request.setClientIp("127.0.0.1");
110 | request.setTotalFee(1);
111 | request.setNotifyUrl("http://www.xxx.com/notify");
112 | request.setOutTradeNo("TEST12345678app");
113 | request.setTimeStart(Dates.now("yyyyMMddHHmmss"));
114 | AppPayResponse resp = wepay.pay().appPay(request);
115 | assertNotNull(resp);
116 | System.out.println(resp);
117 | }
118 |
119 | @Test
120 | public void testQueryOrderByOutTradeNo(){
121 | WePayOrder order = wepay.order().queryByOutTradeNo("TEST3344520");
122 | assertNotNull(order);
123 | System.out.println(order);
124 | }
125 |
126 | @Test
127 | public void testQueryOrderByTransactionId(){
128 | WePayOrder order = wepay.order().queryByTransactionId("1000530784201510111158030445");
129 | assertNotNull(order);
130 | System.out.println(order);
131 | }
132 |
133 | @Test
134 | public void testCloseOrder(){
135 | assertTrue(wepay.order().closeOrder("TEST12345678"));
136 | }
137 |
138 | @Test
139 | public void testRefundApply(){
140 | RefundApplyRequest req = new RefundApplyRequest();
141 | req.setTransactionId("1003110578201512021860142525");
142 | req.setOutRefundNo("TEST3344520");
143 | req.setTotalFee(1);
144 | req.setRefundFee(1);
145 | req.setOpUserId(wepay.getMchId());
146 |
147 | RefundApplyResponse resp = wepay.refund().apply(req);
148 | assertNotNull(resp);
149 | System.out.println(resp);
150 | }
151 |
152 | @Test
153 | public void testRefundQuery(){
154 | RefundQueryResponse resp = wepay.refund().queryByOutTradeNo("TEST3344556677");
155 | assertNotNull(resp);
156 | System.out.println(resp);
157 |
158 | wepay.refund().queryByOutRefundNo("TEST3344556677");
159 | assertNotNull(resp);
160 | System.out.println(resp);
161 |
162 | wepay.refund().queryByTransactionId("1003110578201511281803217943");
163 | assertNotNull(resp);
164 | System.out.println(resp);
165 |
166 | wepay.refund().queryByRefundId("2003110578201512010090200506");
167 | assertNotNull(resp);
168 | System.out.println(resp);
169 |
170 | }
171 |
172 | @Test
173 | public void testQueryBill(){
174 | BillDetail allBill = wepay.bill().queryAll(null, "20151203");
175 | assertNotNull(allBill);
176 | assertEquals(allBill.getBills().size(), allBill.getCount().getTradeTotalCount().intValue());
177 | System.out.println(allBill.getBills().get(0));
178 | System.out.println(allBill.getCount());
179 |
180 | BillDetail successBill = wepay.bill().querySuccess(null, "20151203");
181 | assertNotNull(successBill);
182 | assertEquals(successBill.getBills().size(), successBill.getCount().getTradeTotalCount().intValue());
183 | System.out.println(successBill.getBills().get(0));
184 | System.out.println(successBill.getCount());
185 |
186 | BillDetail refundBill = wepay.bill().queryRefund(null, "20151203");
187 | assertNotNull(refundBill);
188 | assertEquals(refundBill.getBills().size(), refundBill.getCount().getTradeTotalCount().intValue());
189 | System.out.println(refundBill.getBills().get(0));
190 | System.out.println(refundBill.getCount());
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/wepay-demo/pom.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 | wepay
5 | me.hao0
6 | 1.3.2
7 |
8 | 4.0.0
9 | wepay-demo
10 | war
11 | wepay-demo Maven Webapp
12 | http://maven.apache.org
13 | 1.3.2
14 |
15 |
16 | 4.1.5.RELEASE
17 | 1.7
18 | 2.5
19 | 8.1.8.v20121106
20 |
21 |
22 |
23 |
24 |
25 | me.hao0
26 | wepay-core
27 | 1.3.2
28 |
29 |
30 |
31 | org.slf4j
32 | slf4j-api
33 | 1.7.2
34 |
35 |
36 |
37 | ch.qos.logback
38 | logback-core
39 | 1.1.2
40 |
41 |
42 |
43 | ch.qos.logback
44 | logback-classic
45 | 1.1.2
46 |
47 |
48 |
49 | com.google.guava
50 | guava
51 | 18.0
52 |
53 |
54 |
55 | javax.servlet
56 | servlet-api
57 | ${servlet.version}
58 | provided
59 |
60 |
61 |
62 | org.springframework
63 | spring-webmvc
64 | ${spring.version}
65 |
66 |
67 |
68 |
69 | wepay-demo
70 |
71 |
72 |
73 | src/main/resources
74 | true
75 |
76 | **/*.p12
77 |
78 |
79 |
80 | src/main/resources
81 | false
82 |
83 | **/*.p12
84 |
85 |
86 |
87 |
88 |
89 | org.apache.maven.plugins
90 | maven-compiler-plugin
91 |
92 | ${compile.version}
93 | ${compile.version}
94 | true
95 |
96 |
97 |
98 | org.mortbay.jetty
99 | jetty-maven-plugin
100 | ${jetty.version}
101 |
102 |
103 | /
104 |
105 |
106 |
107 |
108 | org.apache.maven.plugins
109 | maven-deploy-plugin
110 | 2.8.2
111 |
112 | true
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/wepay-demo/src/main/java/me/hao0/wepay/demo/controller/Notifies.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.demo.controller;
2 |
3 | import com.google.common.base.Throwables;
4 | import me.hao0.wepay.demo.support.WepaySupport;
5 | import me.hao0.wepay.util.Maps;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.web.bind.annotation.RequestMapping;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import javax.servlet.http.HttpServletRequest;
12 | import java.io.BufferedReader;
13 | import java.io.IOException;
14 | import java.util.Map;
15 |
16 | /**
17 | * 通知
18 | * Author: haolin
19 | * Email: haolin.h0@gmail.com
20 | * Date: 2/12/15
21 | */
22 | @RestController
23 | @RequestMapping("/notifies")
24 | public class Notifies {
25 |
26 | private static final Logger logger = LoggerFactory.getLogger(Notifies.class);
27 |
28 | @Autowired
29 | private WepaySupport wepaySupport;
30 |
31 | /**
32 | * 支付成功通知
33 | * @param request 请求对象
34 | * @return 处理结果
35 | */
36 | @RequestMapping("/paid")
37 | public String paid(HttpServletRequest request){
38 |
39 | String notifyXml = getPostRequestBody(request);
40 | if (notifyXml.isEmpty()){
41 | return wepaySupport.notifyNotOk("body为空");
42 | }
43 |
44 | Map notifyParams = Maps.toMap(notifyXml);
45 |
46 | if (wepaySupport.verifySign(notifyParams)){
47 |
48 | // TODO business logic
49 |
50 | logger.info("verify sign success: {}", notifyParams);
51 |
52 | return wepaySupport.notifyOk();
53 | } else {
54 |
55 | logger.error("verify sign failed: {}", notifyParams);
56 | return wepaySupport.notifyNotOk("签名失败");
57 | }
58 | }
59 |
60 | public static String getPostRequestBody(HttpServletRequest req) {
61 | if (req.getMethod().equals("POST")) {
62 | StringBuilder sb = new StringBuilder();
63 | try (BufferedReader br = req.getReader()) {
64 | char[] charBuffer = new char[128];
65 | int bytesRead;
66 | while ((bytesRead = br.read(charBuffer)) != -1) {
67 | sb.append(charBuffer, 0, bytesRead);
68 | }
69 | } catch (IOException e) {
70 | logger.warn("failed to read request body, cause: {}", Throwables.getStackTraceAsString(e));
71 | }
72 | return sb.toString();
73 | }
74 | return "";
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/wepay-demo/src/main/java/me/hao0/wepay/demo/controller/Pays.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.demo.controller;
2 |
3 | import me.hao0.wepay.demo.support.WepaySupport;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.stereotype.Controller;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RequestParam;
10 | import javax.servlet.http.HttpServletResponse;
11 | import java.io.IOException;
12 |
13 | /**
14 | * 支付
15 | * Author: haolin
16 | * Email: haolin.h0@gmail.com
17 | * Date: 2/12/15
18 | */
19 | @Controller
20 | @RequestMapping("/pays/")
21 | public class Pays {
22 |
23 | private static final Logger log = LoggerFactory.getLogger(Pays.class);
24 |
25 | @Autowired
26 | private WepaySupport wepaySupport;
27 |
28 | /**
29 | * 二维码支付
30 | * @param orderNumber 商户订单号
31 | */
32 | @RequestMapping(value = "/qrpay")
33 | public void qrPay(
34 | @RequestParam("orderNumber") String orderNumber,
35 | HttpServletResponse response){
36 | try {
37 | String qrUrl = wepaySupport.qrPay(orderNumber);
38 | response.sendRedirect(qrUrl);
39 | } catch (IOException e) {
40 | log.error("failed to qr pay(orderNumber={}), cause: {}",
41 | orderNumber, e.getMessage());
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/wepay-demo/src/main/java/me/hao0/wepay/demo/controller/Refunds.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.demo.controller;
2 |
3 | import me.hao0.wepay.demo.support.WepaySupport;
4 | import me.hao0.wepay.model.refund.RefundApplyResponse;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Controller;
7 | import org.springframework.web.bind.annotation.RequestMapping;
8 | import org.springframework.web.bind.annotation.RequestParam;
9 | import org.springframework.web.bind.annotation.ResponseBody;
10 |
11 | /**
12 | * Author: haolin
13 | * Email: haolin.h0@gmail.com
14 | * Date: 3/12/15
15 | */
16 | @Controller
17 | @RequestMapping("/refunds")
18 | public class Refunds {
19 |
20 | @Autowired
21 | private WepaySupport wepaySupport;
22 |
23 | /**
24 | * 退款申请
25 | * @param orderNumber 商户订单号
26 | */
27 | @RequestMapping("/apply")
28 | @ResponseBody
29 | public RefundApplyResponse apply(@RequestParam("orderNumber") String orderNumber){
30 | return wepaySupport.refundApply(orderNumber);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/wepay-demo/src/main/java/me/hao0/wepay/demo/support/WepaySupport.java:
--------------------------------------------------------------------------------
1 | package me.hao0.wepay.demo.support;
2 |
3 | import com.google.common.io.ByteStreams;
4 | import me.hao0.common.date.Dates;
5 | import me.hao0.wepay.core.Wepay;
6 | import me.hao0.wepay.core.WepayBuilder;
7 | import me.hao0.wepay.model.pay.QrPayRequest;
8 | import me.hao0.wepay.model.refund.RefundApplyRequest;
9 | import me.hao0.wepay.model.refund.RefundApplyResponse;
10 | import org.springframework.beans.factory.annotation.Value;
11 | import org.springframework.stereotype.Component;
12 | import javax.annotation.PostConstruct;
13 | import java.io.InputStream;
14 | import java.util.Map;
15 |
16 | /**
17 | * Author: haolin
18 | * Email: haolin.h0@gmail.com
19 | * Date: 2/12/15
20 | */
21 | @Component
22 | public class WepaySupport {
23 |
24 | @Value("${appId}")
25 | private String appId;
26 |
27 | @Value("${appKey}")
28 | private String appKey;
29 |
30 | @Value("${mchId}")
31 | private String mchId;
32 |
33 | @Value("${payNotifyUrl}")
34 | private String payNotifyUrl;
35 |
36 | private Wepay wepay;
37 |
38 | @PostConstruct
39 | public void initWepay() {
40 | try(InputStream in = this.getClass().getClassLoader().getResourceAsStream("cert.p12")) {
41 | // 加载证书文件
42 | byte[] certs = ByteStreams.toByteArray(in);
43 | wepay = WepayBuilder.newBuilder(appId, appKey, mchId)
44 | .certPasswd(mchId)
45 | .certs(certs)
46 | .build();
47 | } catch (Exception e) {
48 | throw new RuntimeException(e);
49 | }
50 | }
51 |
52 | /**
53 | * 动态二维码支付
54 | * @param orderNumber 订单号
55 | * @return 二维码链接
56 | */
57 | public String qrPay(String orderNumber){
58 | QrPayRequest request = new QrPayRequest();
59 | request.setBody("测试订单");
60 | request.setClientIp("127.0.0.1");
61 | request.setTotalFee(1);
62 | request.setNotifyUrl(payNotifyUrl);
63 | request.setOutTradeNo(orderNumber);
64 | request.setTimeStart(Dates.now("yyyyMMddHHmmss"));
65 | return wepay.pay().qrPay(request).getCodeUrl();
66 | }
67 |
68 | /**
69 | * 校验签名
70 | * @param params 参数(包含sign)
71 | * @return 校验成功返回true,反之false
72 | */
73 | public Boolean verifySign(Map params){
74 | return wepay.notifies().verifySign(params);
75 | }
76 |
77 | /**
78 | * 通知成功
79 | */
80 | public String notifyOk(){
81 | return wepay.notifies().ok();
82 | }
83 |
84 | /**
85 | * 通知不成功
86 | * @param errMsg 错误消息
87 | */
88 | public String notifyNotOk(String errMsg){
89 | return wepay.notifies().notOk(errMsg);
90 | }
91 |
92 | public RefundApplyResponse refundApply(String orderNumber){
93 | RefundApplyRequest req = new RefundApplyRequest();
94 | req.setOutTradeNo(orderNumber);
95 | req.setOutRefundNo(orderNumber);
96 | req.setTotalFee(1);
97 | req.setRefundFee(1);
98 | req.setOpUserId(wepay.getMchId());
99 | return wepay.refund().apply(req);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/wepay-demo/src/main/resources/app-example.properties:
--------------------------------------------------------------------------------
1 | appId=
2 | appKey=
3 | mchId=
4 | payNotifyUrl=${your_domain}/notifies/paid
--------------------------------------------------------------------------------
/wepay-demo/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | %date{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/wepay-demo/src/main/resources/spring/root-context.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | classpath*:/app.properties
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/wepay-demo/src/main/resources/spring/web-context.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/wepay-demo/src/main/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | wepay-demo
7 |
8 |
9 | contextConfigLocation
10 |
11 | classpath*:/spring/root-context.xml
12 |
13 |
14 |
15 |
16 | defaultHtmlEscape
17 | true
18 |
19 |
20 |
21 | org.springframework.web.context.ContextLoaderListener
22 |
23 |
24 |
25 | DispatcherServlet
26 | org.springframework.web.servlet.DispatcherServlet
27 |
28 | contextConfigLocation
29 | classpath*:/spring/web-context.xml
30 |
31 | 1
32 |
33 |
34 | DispatcherServlet
35 | /
36 |
37 |
38 |
39 | encodingFilter
40 | org.springframework.web.filter.CharacterEncodingFilter
41 |
42 | encoding
43 | UTF-8
44 |
45 |
46 | forceEncoding
47 | true
48 |
49 |
50 |
51 | encodingFilter
52 | /*
53 |
54 |
55 |
--------------------------------------------------------------------------------