mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-03-10 00:13:40 +08:00
Compare commits
38 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0423e6849d | ||
|
|
833ff70680 | ||
|
|
373c1e65cb | ||
|
|
b44dd2e347 | ||
|
|
b6c3d74cba | ||
|
|
0452a05dd4 | ||
|
|
4828a314e9 | ||
|
|
3f0b8d4e2b | ||
|
|
dd407141b0 | ||
|
|
b225afbd68 | ||
|
|
5604a16ae8 | ||
|
|
25309e06ad | ||
|
|
5ac9922f8d | ||
|
|
03790d64bc | ||
|
|
1f0dbcc2aa | ||
|
|
404102a4c8 | ||
|
|
5decfcb917 | ||
|
|
44a95578d9 | ||
|
|
2bf31411c0 | ||
|
|
71fbc2b1e8 | ||
|
|
15b7460d92 | ||
|
|
933840e3b2 | ||
|
|
5da939647c | ||
|
|
22ec3f0eca | ||
|
|
410cc9dfd7 | ||
|
|
783c89523d | ||
|
|
3e48dc7f83 | ||
|
|
f3c1422354 | ||
|
|
d65e2f27a9 | ||
|
|
c3b16228c0 | ||
|
|
24ebc91dca | ||
|
|
1e003ee571 | ||
|
|
8e5ee97378 | ||
|
|
704fba4d85 | ||
|
|
b0daf8428e | ||
|
|
ab1c150feb | ||
|
|
b4b73ad40a | ||
|
|
be0dd8b692 |
@@ -28,7 +28,7 @@ $ git push
|
||||
* 定期使用项目仓库内容更新自己仓库内容。
|
||||
|
||||
```bash
|
||||
$ git remote add upstream https://github.com/Wechat-Group/WxJava
|
||||
$ git remote add upstream https://github.com/binarywang/WxJava
|
||||
$ git fetch upstream
|
||||
$ git checkout develop
|
||||
$ git rebase upstream/develop
|
||||
|
||||
13
README.md
13
README.md
@@ -21,24 +21,29 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle" colspan="3">
|
||||
<td align="center" valign="middle" colspan="2">
|
||||
<a href="https://www.jeequan.com/product/jeepay.html" target="_blank">
|
||||
<img height="120" src="https://jeequan.oss-cn-beijing.aliyuncs.com/jeepay/img/wxjava_jeepay.png" alt="计全支付Jeepay,开源支付系统">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle" colspan="1">
|
||||
<a href="https://www.mall4j.com/cn/?statId=9" target="_blank">
|
||||
<img height="120" src="https://img.mall4j.com/mall.png" alt="Mall4j">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="middle">
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://mp.weixin.qq.com/mp/homepage?__biz=MzI3MzAwMzk4OA==&hid=1&sn=f31af3bf562b116b061c9ab4edf70b61&scene=18#wechat_redirect" target="_blank">
|
||||
<img height="120" src="https://gitee.com/binary/weixin-java-tools/raw/develop/images/qrcodes/mp.png" alt="mp qrcode">
|
||||
</a>
|
||||
</td>
|
||||
<td valign="middle">
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.diboot.com?from=wxjava" target="_blank">
|
||||
<img height="120" src="https://www.diboot.com/img/diboot_ad.png" alt="diboot低代码开发平台"/>
|
||||
</a>
|
||||
</td>
|
||||
<td align="right" valign="middle">
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.iyque.cn/" target="_blank">
|
||||
<img height="120" src="https://iyque-1251309172.cos.ap-nanjing.myqcloud.com/advert/wxjava.jpg" alt="aliyun ad">
|
||||
</a>
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>WxJava - Weixin/Wechat Java SDK</name>
|
||||
<description>微信开发Java SDK</description>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<packaging>pom</packaging>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-solon-plugins</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<packaging>pom</packaging>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ public class WxPayAutoConfiguration {
|
||||
payConfig.setPrivateCertPath(StringUtils.trimToNull(this.properties.getPrivateCertPath()));
|
||||
payConfig.setCertSerialNo(StringUtils.trimToNull(this.properties.getCertSerialNo()));
|
||||
payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiv3Key()));
|
||||
payConfig.setPublicKeyId(StringUtils.trimToNull(this.properties.getPublicKeyId()));
|
||||
payConfig.setPublicKeyPath(StringUtils.trimToNull(this.properties.getPublicKeyPath()));
|
||||
|
||||
wxPayService.setConfig(payConfig);
|
||||
return wxPayService;
|
||||
|
||||
@@ -73,7 +73,17 @@ public class WxPayProperties {
|
||||
* apiv3 商户apiclient_cert.pem
|
||||
*/
|
||||
private String privateCertPath;
|
||||
|
||||
|
||||
/**
|
||||
* 公钥ID
|
||||
*/
|
||||
private String publicKeyId;
|
||||
|
||||
/**
|
||||
* pub_key.pem证书文件的绝对路径或者以classpath:开头的类路径.
|
||||
*/
|
||||
private String publicKeyPath;
|
||||
|
||||
/**
|
||||
* 微信支付是否使用仿真测试环境.
|
||||
* 默认不使用
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>wx-java-spring-boot-starters</artifactId>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>weixin-graal</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>weixin-java-channel</artifactId>
|
||||
|
||||
@@ -42,4 +42,8 @@ public class OrderCommissionInfo implements Serializable {
|
||||
/** 达人openfinderid */
|
||||
@JsonProperty("openfinderid")
|
||||
private String openFinderId;
|
||||
|
||||
/** 新带货平台 id */
|
||||
@JsonProperty("talent_id")
|
||||
private String talentId;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>weixin-java-common</artifactId>
|
||||
|
||||
@@ -59,7 +59,7 @@ public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder {
|
||||
* 设置为负数是使用系统默认设置(非3000ms的默认值,而是httpClient的默认设置).
|
||||
* </p>
|
||||
*/
|
||||
private int connectionRequestTimeout = -1;
|
||||
private int connectionRequestTimeout = 3000;
|
||||
|
||||
/**
|
||||
* 建立链接的超时时间,默认为5000ms.由于是在链接池获取链接,此设置应该并不起什么作用
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>weixin-java-cp</artifactId>
|
||||
|
||||
@@ -36,4 +36,12 @@ public interface WxCpAgentWorkBenchService {
|
||||
* @throws WxErrorException the wx error exception
|
||||
*/
|
||||
void setWorkBenchData(WxCpAgentWorkBench wxCpAgentWorkBench) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* Batch sets work bench data.
|
||||
*
|
||||
* @param wxCpAgentWorkBench the wx cp agent work bench
|
||||
* @throws WxErrorException the wx error exception
|
||||
*/
|
||||
void batchSetWorkBenchData(WxCpAgentWorkBench wxCpAgentWorkBench) throws WxErrorException;
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ public interface WxCpExternalContactService {
|
||||
* 用户需要妥善存储返回的config_id,config_id丢失可能导致用户无法编辑或删除「联系我」。
|
||||
* 临时会话模式不占用「联系我」数量,但每日最多添加10万个,并且仅支持单人。
|
||||
* 临时会话模式的二维码,添加好友完成后该二维码即刻失效。
|
||||
* <a href="https://developer.work.weixin.qq.com/document/path/92228">文档地址</a>
|
||||
* </pre>
|
||||
*
|
||||
* @param info 客户联系「联系我」方式
|
||||
@@ -59,6 +60,25 @@ public interface WxCpExternalContactService {
|
||||
*/
|
||||
WxCpContactWayInfo getContactWay(String configId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获取企业已配置的「联系我」列表
|
||||
*
|
||||
* <pre>
|
||||
* 获取企业配置的「联系我」二维码和「联系我」小程序插件列表。不包含临时会话。
|
||||
* 注意,<b>该接口仅可获取2021年7月10日以后创建的「联系我」</b>
|
||||
* </pre>
|
||||
*
|
||||
* 文档地址: <a href="https://developer.work.weixin.qq.com/document/path/92228#%E8%8E%B7%E5%8F%96%E4%BC%81%E4%B8%9A%E5%B7%B2%E9%85%8D%E7%BD%AE%E7%9A%84%E3%80%8C%E8%81%94%E7%B3%BB%E6%88%91%E3%80%8D%E5%88%97%E8%A1%A8">获取企业已配置的「联系我」列表</a>
|
||||
*
|
||||
* @param startTime 「联系我」创建起始时间戳, 默认为90天前
|
||||
* @param endTime 「联系我」创建结束时间戳, 默认为当前时间
|
||||
* @param cursor 分页查询使用的游标,为上次请求返回的 next_cursor
|
||||
* @param limit 每次查询的分页大小,默认为100条,最多支持1000条
|
||||
* @return contact way configId
|
||||
* @throws WxErrorException the wx error exception
|
||||
*/
|
||||
WxCpContactWayList listContactWay(Long startTime, Long endTime, String cursor, Long limit) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 更新企业已配置的「联系我」方式
|
||||
*
|
||||
|
||||
@@ -75,6 +75,19 @@ public interface WxCpKfService {
|
||||
*/
|
||||
WxCpKfServicerOpResp addServicer(String openKfid, List<String> userIdList) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 接待人员管理
|
||||
* 添加指定客服账号的接待人员,每个客服账号目前最多可添加2000个接待人员,20个部门。
|
||||
* userid_list和department_id_list至少需要填其中一个
|
||||
*
|
||||
* @param openKfid 客服帐号ID
|
||||
* @param userIdList 接待人员userid列表。第三方应用填密文userid,即open_userid 可填充个数:1 ~ 100。超过100个需分批调用。
|
||||
* @param departmentIdList 接待人员部门id列表 可填充个数:0 ~ 20。
|
||||
* @return 添加客服账号结果 wx cp kf servicer op resp
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
WxCpKfServicerOpResp addServicer(String openKfid, List<String> userIdList,List<String> departmentIdList) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 接待人员管理
|
||||
* 从客服帐号删除接待人员
|
||||
@@ -86,6 +99,19 @@ public interface WxCpKfService {
|
||||
*/
|
||||
WxCpKfServicerOpResp delServicer(String openKfid, List<String> userIdList) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 接待人员管理
|
||||
* 从客服帐号删除接待人员
|
||||
* userid_list和department_id_list至少需要填其中一个
|
||||
*
|
||||
* @param openKfid 客服帐号ID
|
||||
* @param userIdList 接待人员userid列表。第三方应用填密文userid,即open_userid 可填充个数:1 ~ 100。超过100个需分批调用。
|
||||
* @param departmentIdList 接待人员部门id列表 可填充个数:0 ~ 100。超过100个需分批调用。
|
||||
* @return 删除客服账号结果 wx cp kf servicer op resp
|
||||
* @throws WxErrorException 异常
|
||||
*/
|
||||
WxCpKfServicerOpResp delServicer(String openKfid, List<String> userIdList, List<String> departmentIdList) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 接待人员管理
|
||||
* 获取某个客服帐号的接待人员列表
|
||||
|
||||
@@ -334,7 +334,7 @@ public interface WxCpSchoolUserService {
|
||||
* 请求方式:GET(HTTPS)
|
||||
* 请求地址:https://qyapi.weixin.qq.com/cgi-bin/school/department/list?access_token=ACCESS_TOKEN&id=ID
|
||||
*
|
||||
* @param id the id
|
||||
* @param id 部门id。获取指定部门及其下的子部门。 如果不填,默认获取全量组织架构
|
||||
* @return wx cp department list
|
||||
* @throws WxErrorException the wx error exception
|
||||
*/
|
||||
|
||||
@@ -38,4 +38,10 @@ public class WxCpAgentWorkBenchServiceImpl implements WxCpAgentWorkBenchService
|
||||
final String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WORKBENCH_DATA_SET));
|
||||
this.mainService.post(url, wxCpAgentWorkBench.toUserDataString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void batchSetWorkBenchData(WxCpAgentWorkBench wxCpAgentWorkBench) throws WxErrorException {
|
||||
final String url = String.format(this.mainService.getWxCpConfigStorage().getApiUrl(WORKBENCH_BATCH_DATA_SET));
|
||||
this.mainService.post(url, wxCpAgentWorkBench.toBatchUserDataString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,17 @@ public class WxCpExternalContactServiceImpl implements WxCpExternalContactServic
|
||||
return WxCpContactWayInfo.fromJson(this.mainService.post(url, json.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpContactWayList listContactWay(Long startTime, Long endTime, String cursor, Long limit) throws WxErrorException {
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("start_time", startTime);
|
||||
json.addProperty("end_time", endTime);
|
||||
json.addProperty("cursor", cursor);
|
||||
json.addProperty("limit", limit);
|
||||
final String url = this.mainService.getWxCpConfigStorage().getApiUrl(LIST_CONTACT_WAY);
|
||||
return WxCpContactWayList.fromJson(this.mainService.post(url, json.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpBaseResp updateContactWay(WxCpContactWayInfo info) throws WxErrorException {
|
||||
if (StringUtils.isBlank(info.getContactWay().getConfigId())) {
|
||||
|
||||
@@ -70,23 +70,62 @@ public class WxCpKfServiceImpl implements WxCpKfService {
|
||||
|
||||
@Override
|
||||
public WxCpKfServicerOpResp addServicer(String openKfid, List<String> userIdList) throws WxErrorException {
|
||||
return servicerOp(openKfid, userIdList, SERVICER_ADD);
|
||||
return servicerOp(openKfid, userIdList, null, SERVICER_ADD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpKfServicerOpResp addServicer(String openKfId, List<String> userIdList, List<String> departmentIdList) throws WxErrorException {
|
||||
validateParameters(SERVICER_ADD, userIdList, departmentIdList);
|
||||
return servicerOp(openKfId, userIdList, departmentIdList, SERVICER_ADD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxCpKfServicerOpResp delServicer(String openKfid, List<String> userIdList) throws WxErrorException {
|
||||
return servicerOp(openKfid, userIdList, SERVICER_DEL);
|
||||
return servicerOp(openKfid, userIdList, null, SERVICER_DEL);
|
||||
}
|
||||
|
||||
private WxCpKfServicerOpResp servicerOp(String openKfid, List<String> userIdList, String uri) throws WxErrorException {
|
||||
@Override
|
||||
public WxCpKfServicerOpResp delServicer(String openKfid, List<String> userIdList, List<String> departmentIdList) throws WxErrorException {
|
||||
validateParameters(SERVICER_DEL, userIdList, departmentIdList);
|
||||
return servicerOp(openKfid, userIdList, departmentIdList, SERVICER_DEL);
|
||||
}
|
||||
|
||||
private void validateParameters(String uri, List<String> userIdList, List<String> departmentIdList) {
|
||||
if ((userIdList == null || userIdList.isEmpty()) && (departmentIdList == null || departmentIdList.isEmpty())) {
|
||||
throw new IllegalArgumentException("userid_list和department_id_list至少需要填其中一个");
|
||||
}
|
||||
if (SERVICER_DEL.equals(uri)) {
|
||||
if (userIdList != null && userIdList.size() > 100) {
|
||||
throw new IllegalArgumentException("可填充个数:0 ~ 100。超过100个需分批调用。");
|
||||
}
|
||||
if (departmentIdList != null && departmentIdList.size() > 100) {
|
||||
throw new IllegalArgumentException("可填充个数:0 ~ 100。超过100个需分批调用。");
|
||||
}
|
||||
} else {
|
||||
if (userIdList != null && userIdList.size() > 100) {
|
||||
throw new IllegalArgumentException("可填充个数:0 ~ 100。超过100个需分批调用。");
|
||||
}
|
||||
if (departmentIdList != null && departmentIdList.size() > 20) {
|
||||
throw new IllegalArgumentException("可填充个数:0 ~ 20。");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private WxCpKfServicerOpResp servicerOp(String openKfid, List<String> userIdList, List<String> departmentIdList, String uri) throws WxErrorException {
|
||||
String url = cpService.getWxCpConfigStorage().getApiUrl(uri);
|
||||
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("open_kfid", openKfid);
|
||||
JsonArray userIdArray = new JsonArray();
|
||||
userIdList.forEach(userIdArray::add);
|
||||
json.add("userid_list", userIdArray);
|
||||
|
||||
if (userIdList != null && !userIdList.isEmpty()) {
|
||||
JsonArray userIdArray = new JsonArray();
|
||||
userIdList.forEach(userIdArray::add);
|
||||
json.add("userid_list", userIdArray);
|
||||
}
|
||||
if (departmentIdList != null && !departmentIdList.isEmpty()) {
|
||||
JsonArray departmentIdArray = new JsonArray();
|
||||
departmentIdList.forEach(departmentIdArray::add);
|
||||
json.add("department_id_list", departmentIdArray);
|
||||
}
|
||||
String responseContent = cpService.post(url, json.toString());
|
||||
return WxCpKfServicerOpResp.fromJson(responseContent);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import me.chanjar.weixin.cp.bean.WxCpUserDetail;
|
||||
import me.chanjar.weixin.cp.bean.workbench.WxCpSecondVerificationInfo;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static me.chanjar.weixin.common.api.WxConsts.OAuth2Scope.*;
|
||||
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.OAuth2.*;
|
||||
|
||||
@@ -74,9 +76,9 @@ public class WxCpOAuth2ServiceImpl implements WxCpOAuth2Service {
|
||||
JsonObject jo = GsonParser.parse(responseText);
|
||||
|
||||
return WxCpOauth2UserInfo.builder()
|
||||
.userId(GsonHelper.getString(jo, "UserId"))
|
||||
.userId(Optional.ofNullable(GsonHelper.getString(jo, "UserId")).orElse(GsonHelper.getString(jo, "userid")))
|
||||
.deviceId(GsonHelper.getString(jo, "DeviceId"))
|
||||
.openId(GsonHelper.getString(jo, "OpenId"))
|
||||
.openId(Optional.ofNullable(GsonHelper.getString(jo, "OpenId")).orElse(GsonHelper.getString(jo, "openid")))
|
||||
.userTicket(GsonHelper.getString(jo, "user_ticket"))
|
||||
.expiresIn(GsonHelper.getString(jo, "expires_in"))
|
||||
.externalUserId(GsonHelper.getString(jo, "external_userid"))
|
||||
|
||||
@@ -16,6 +16,7 @@ import me.chanjar.weixin.cp.bean.school.user.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.ExternalContact.*;
|
||||
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.School.*;
|
||||
@@ -246,7 +247,7 @@ public class WxCpSchoolUserServiceImpl implements WxCpSchoolUserService {
|
||||
|
||||
@Override
|
||||
public WxCpDepartmentList listDepartment(Integer id) throws WxErrorException {
|
||||
String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST) + id;
|
||||
String apiUrl = Objects.isNull(id) ? this.cpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST) : String.format("%s?id=%s", this.cpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), id);
|
||||
String responseContent = this.cpService.get(apiUrl, null);
|
||||
return WxCpDepartmentList.fromJson(responseContent);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||
import me.chanjar.weixin.cp.bean.workbench.WorkBenchKeyData;
|
||||
import me.chanjar.weixin.cp.bean.workbench.WorkBenchList;
|
||||
import me.chanjar.weixin.cp.constant.WxCpConsts;
|
||||
@@ -33,6 +34,10 @@ public class WxCpAgentWorkBench implements Serializable {
|
||||
* 用户的userid
|
||||
*/
|
||||
private String userId;
|
||||
/**
|
||||
* 用户的userIds
|
||||
*/
|
||||
private List<String> useridList;
|
||||
/**
|
||||
* 应用id
|
||||
*/
|
||||
@@ -58,6 +63,15 @@ public class WxCpAgentWorkBench implements Serializable {
|
||||
* 参考示例:<a href="wxwork://openurl?url=https%3A%2F%2Fwork.weixin.qq.com%2F">今日要闻</a>
|
||||
*/
|
||||
private Boolean enableWebviewClick;
|
||||
/**
|
||||
* 高度。可以有两种选择:single_row与double_row。当为single_row时,高度为106px(如果隐藏标题则为147px)。
|
||||
* 当为double_row时,高度固定为171px(如果隐藏标题则为212px)。默认值为double_row
|
||||
*/
|
||||
private String height;
|
||||
/**
|
||||
* 是否要隐藏展示了应用名称的标题部分,默认值为false。
|
||||
*/
|
||||
private Boolean hideTitle;
|
||||
|
||||
private List<WorkBenchKeyData> keyDataList;
|
||||
|
||||
@@ -93,6 +107,20 @@ public class WxCpAgentWorkBench implements Serializable {
|
||||
return userDataObject.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成批量用户数据Json字符串
|
||||
*
|
||||
* @return the string
|
||||
*/
|
||||
public String toBatchUserDataString() {
|
||||
JsonObject userDataObject = new JsonObject();
|
||||
userDataObject.addProperty("agentid", this.agentId);
|
||||
JsonArray useridList = WxGsonBuilder.create().toJsonTree(this.useridList).getAsJsonArray();
|
||||
userDataObject.add("userid_list", useridList);
|
||||
this.handleBatch(userDataObject);
|
||||
return userDataObject.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理不用类型的工作台数据
|
||||
*/
|
||||
@@ -140,9 +168,9 @@ public class WxCpAgentWorkBench implements Serializable {
|
||||
webview.addProperty("url", this.url);
|
||||
webview.addProperty("jump_url", this.jumpUrl);
|
||||
webview.addProperty("pagepath", this.pagePath);
|
||||
if (null != this.enableWebviewClick) {
|
||||
webview.addProperty("enable_webview_click", this.enableWebviewClick);
|
||||
}
|
||||
webview.addProperty("enable_webview_click", this.enableWebviewClick);
|
||||
webview.addProperty("height", this.height);
|
||||
webview.addProperty("hide_title", this.hideTitle);
|
||||
templateObject.add("webview", webview);
|
||||
break;
|
||||
}
|
||||
@@ -152,4 +180,75 @@ public class WxCpAgentWorkBench implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理不用类型的工作台数据
|
||||
*/
|
||||
private void handleBatch(JsonObject templateObject) {
|
||||
switch (this.getType()) {
|
||||
case WxCpConsts.WorkBenchType.KEYDATA: {
|
||||
JsonArray keyDataArray = new JsonArray();
|
||||
JsonObject itemsObject = new JsonObject();
|
||||
for (WorkBenchKeyData keyDataItem : this.keyDataList) {
|
||||
JsonObject keyDataObject = new JsonObject();
|
||||
keyDataObject.addProperty("key", keyDataItem.getKey());
|
||||
keyDataObject.addProperty("data", keyDataItem.getData());
|
||||
keyDataObject.addProperty("jump_url", keyDataItem.getJumpUrl());
|
||||
keyDataObject.addProperty("pagepath", keyDataItem.getPagePath());
|
||||
keyDataArray.add(keyDataObject);
|
||||
}
|
||||
itemsObject.add("items", keyDataArray);
|
||||
JsonObject dataObject = new JsonObject();
|
||||
dataObject.addProperty("type", WxCpConsts.WorkBenchType.KEYDATA);
|
||||
dataObject.add("keydata", itemsObject);
|
||||
templateObject.add("data", dataObject);
|
||||
break;
|
||||
}
|
||||
case WxCpConsts.WorkBenchType.IMAGE: {
|
||||
JsonObject image = new JsonObject();
|
||||
image.addProperty("url", this.url);
|
||||
image.addProperty("jump_url", this.jumpUrl);
|
||||
image.addProperty("pagepath", this.pagePath);
|
||||
JsonObject dataObject = new JsonObject();
|
||||
dataObject.addProperty("type", WxCpConsts.WorkBenchType.IMAGE);
|
||||
dataObject.add("image", image);
|
||||
templateObject.add("data", dataObject);
|
||||
break;
|
||||
}
|
||||
case WxCpConsts.WorkBenchType.LIST: {
|
||||
JsonArray listArray = new JsonArray();
|
||||
JsonObject itemsObject = new JsonObject();
|
||||
for (WorkBenchList listItem : this.lists) {
|
||||
JsonObject listObject = new JsonObject();
|
||||
listObject.addProperty("title", listItem.getTitle());
|
||||
listObject.addProperty("jump_url", listItem.getJumpUrl());
|
||||
listObject.addProperty("pagepath", listItem.getPagePath());
|
||||
listArray.add(listObject);
|
||||
}
|
||||
itemsObject.add("items", listArray);
|
||||
JsonObject dataObject = new JsonObject();
|
||||
dataObject.addProperty("type", WxCpConsts.WorkBenchType.LIST);
|
||||
dataObject.add("list", itemsObject);
|
||||
templateObject.add("data", dataObject);
|
||||
break;
|
||||
}
|
||||
case WxCpConsts.WorkBenchType.WEBVIEW: {
|
||||
JsonObject webview = new JsonObject();
|
||||
webview.addProperty("url", this.url);
|
||||
webview.addProperty("jump_url", this.jumpUrl);
|
||||
webview.addProperty("pagepath", this.pagePath);
|
||||
webview.addProperty("enable_webview_click", this.enableWebviewClick);
|
||||
webview.addProperty("height", this.height);
|
||||
webview.addProperty("hide_title", this.hideTitle);
|
||||
JsonObject dataObject = new JsonObject();
|
||||
dataObject.addProperty("type", WxCpConsts.WorkBenchType.WEBVIEW);
|
||||
dataObject.add("webview", webview);
|
||||
templateObject.add("data", dataObject);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -152,6 +152,13 @@ public class WxCpContactWayInfo implements Serializable {
|
||||
@SerializedName("unionid")
|
||||
private String unionId;
|
||||
|
||||
|
||||
/**
|
||||
*非必填,是否开启同一外部企业客户只能添加同一个员工,默认为否,开启后,同一个企业的客户会优先添加到同一个跟进人
|
||||
*/
|
||||
@SerializedName("is_exclusive")
|
||||
private boolean isExclusive;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 非必填
|
||||
|
||||
63
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayList.java
vendored
Normal file
63
weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/external/WxCpContactWayList.java
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package me.chanjar.weixin.cp.bean.external;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 「联系我」方式 列表返回对象
|
||||
*
|
||||
* @author <a href="https://github.com/imyzt">imyzt</a>
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class WxCpContactWayList extends WxCpBaseResp implements Serializable {
|
||||
private static final long serialVersionUID = -8697184659526210472L;
|
||||
|
||||
@SerializedName("contact_way")
|
||||
private List<ContactWay> contactWay;
|
||||
|
||||
/**
|
||||
* The type Contact way.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public static class ContactWay implements Serializable {
|
||||
private static final long serialVersionUID = -8697184659526210472L;
|
||||
|
||||
/**
|
||||
* 联系方式的配置id
|
||||
*/
|
||||
@SerializedName("config_id")
|
||||
private String configId;
|
||||
}
|
||||
|
||||
/**
|
||||
* From json wx cp contact way list.
|
||||
*
|
||||
* @param json the json
|
||||
* @return the wx cp contact way list
|
||||
*/
|
||||
public static WxCpContactWayList fromJson(String json) {
|
||||
return WxCpGsonBuilder.create().fromJson(json, WxCpContactWayList.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* To json string.
|
||||
*
|
||||
* @return the string
|
||||
*/
|
||||
public String toJson() {
|
||||
return WxCpGsonBuilder.create().toJson(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
import me.chanjar.weixin.cp.bean.oa.templatedata.TemplateTips;
|
||||
import me.chanjar.weixin.cp.bean.oa.templatedata.TemplateTitle;
|
||||
import me.chanjar.weixin.cp.bean.oa.templatedata.control.*;
|
||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||
@@ -94,6 +95,9 @@ public class WxCpOaApprovalTemplateResult implements Serializable {
|
||||
@SerializedName("vacation_list")
|
||||
private TemplateVacation vacationList;
|
||||
|
||||
@SerializedName("tips")
|
||||
private TemplateTips tips;
|
||||
|
||||
}
|
||||
|
||||
@Data
|
||||
|
||||
@@ -37,4 +37,6 @@ public class TemplateConfig implements Serializable {
|
||||
@SerializedName("vacation_list")
|
||||
private TemplateVacation vacationList;
|
||||
|
||||
private TemplateTips tips;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package me.chanjar.weixin.cp.bean.oa.templatedata;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author mrsiu@msn.com
|
||||
* @version 1.0
|
||||
* @date 2025/1/16 09:40
|
||||
*/
|
||||
@Data
|
||||
public class TemplateTips {
|
||||
|
||||
@SerializedName("tips_content")
|
||||
private List<TemplateTipsContent> tipsContent;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package me.chanjar.weixin.cp.bean.oa.templatedata;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author mrsiu@msn.com
|
||||
* @version 1.0
|
||||
* @date 2025/1/16 09:42
|
||||
*/
|
||||
@Data
|
||||
public class TemplateTipsContent {
|
||||
|
||||
private TemplateTipsText text;
|
||||
private String lang;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package me.chanjar.weixin.cp.bean.oa.templatedata;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author mrsiu@msn.com
|
||||
* @version 1.0
|
||||
* @date 2025/1/16 09:45
|
||||
*/
|
||||
@Data
|
||||
public class TemplateTipsSubText {
|
||||
private Integer type;
|
||||
private TemplateTipsSubTextContent content;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package me.chanjar.weixin.cp.bean.oa.templatedata;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author mrsiu@msn.com
|
||||
* @version 1.0
|
||||
* @date 2025/1/16 09:46
|
||||
*/
|
||||
@Data
|
||||
public class TemplateTipsSubTextContent {
|
||||
@SerializedName("plain_text")
|
||||
private TemplateTipsSubTextContentPlainText plainText;
|
||||
private TemplateTipsSubTextContentLink link;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package me.chanjar.weixin.cp.bean.oa.templatedata;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author mrsiu@msn.com
|
||||
* @version 1.0
|
||||
* @date 2025/1/16 09:49
|
||||
*/
|
||||
@Data
|
||||
public class TemplateTipsSubTextContentLink {
|
||||
private String title;
|
||||
private String url;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package me.chanjar.weixin.cp.bean.oa.templatedata;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author mrsiu@msn.com
|
||||
* @date 2025/1/16 09:47
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class TemplateTipsSubTextContentPlainText {
|
||||
private String content;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package me.chanjar.weixin.cp.bean.oa.templatedata;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author mrsiu@msn.com
|
||||
* @date 2025/1/16 09:43
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class TemplateTipsText {
|
||||
@SerializedName("sub_text")
|
||||
private List<TemplateTipsSubText> subText;
|
||||
}
|
||||
@@ -130,6 +130,10 @@ public interface WxCpApiPathConsts {
|
||||
* The constant WORKBENCH_DATA_SET.
|
||||
*/
|
||||
String WORKBENCH_DATA_SET = "/cgi-bin/agent/set_workbench_data";
|
||||
/**
|
||||
* The constant WORKBENCH_BATCH_DATA_SET.
|
||||
*/
|
||||
String WORKBENCH_BATCH_DATA_SET = "/cgi-bin/agent/batch_set_workbench_data";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -691,7 +695,7 @@ public interface WxCpApiPathConsts {
|
||||
/**
|
||||
* The constant DEPARTMENT_LIST.
|
||||
*/
|
||||
String DEPARTMENT_LIST = "/cgi-bin/school/department/list?id=";
|
||||
String DEPARTMENT_LIST = "/cgi-bin/school/department/list";
|
||||
|
||||
/**
|
||||
* The constant GET_PAYMENT_RESULT.
|
||||
@@ -1085,6 +1089,10 @@ public interface WxCpApiPathConsts {
|
||||
* The constant GET_CONTACT_WAY.
|
||||
*/
|
||||
String GET_CONTACT_WAY = "/cgi-bin/externalcontact/get_contact_way";
|
||||
/**
|
||||
* The constant LIST_CONTACT_WAY.
|
||||
*/
|
||||
String LIST_CONTACT_WAY = "/cgi-bin/externalcontact/list_contact_way";
|
||||
/**
|
||||
* The constant UPDATE_CONTACT_WAY.
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,9 @@ import static org.testng.Assert.assertNotNull;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
@@ -90,6 +93,20 @@ public class WxCpExternalContactServiceImplTest {
|
||||
assertNotNull(contactWayInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test list contact way.
|
||||
*
|
||||
* @throws WxErrorException the wx error exception
|
||||
*/
|
||||
@Test
|
||||
public void testListContactWay() throws WxErrorException {
|
||||
long startTime = LocalDateTime.now().minusDays(1).toEpochSecond(ZoneOffset.of("+8"));
|
||||
long endTime = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
|
||||
WxCpContactWayList wxCpContactWayList = this.wxCpService.getExternalContactService().listContactWay(startTime, endTime, null, 100L);
|
||||
System.out.println(wxCpContactWayList.toJson());
|
||||
assertNotNull(wxCpContactWayList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test update contact way.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
package me.chanjar.weixin.cp.api.impl;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.cp.api.WxCpService;
|
||||
import me.chanjar.weixin.cp.bean.school.user.WxCpDepartmentList;
|
||||
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
|
||||
import org.mockito.Mockito;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.School.DEPARTMENT_LIST;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
public class WxCpSchoolUserServiceImplTest {
|
||||
|
||||
|
||||
String allDeptListJson = "{\n" +
|
||||
"\t\"errcode\": 0,\n" +
|
||||
"\t\"errmsg\": \"ok\",\n" +
|
||||
"\t\"departments\": [\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"name\": \"一年级\",\n" +
|
||||
"\t\t\t\"parentid\": 1,\n" +
|
||||
"\t\t\t\"id\": 2,\n" +
|
||||
"\t\t\t\"type\":2,\n" +
|
||||
"\t\t\t\"register_year\":2018,\n" +
|
||||
"\t\t\t\"standard_grade\":1,\n" +
|
||||
"\t\t\t\"order\":1,\n" +
|
||||
"\t\t\t\"department_admins\": [\n" +
|
||||
"\t\t\t\t{\n" +
|
||||
"\t\t\t\t\t\"userid\": \"zhangsan\",\n" +
|
||||
"\t\t\t\t\t\"type\": 1\n" +
|
||||
"\t\t\t\t},\n" +
|
||||
"\t\t\t\t{\n" +
|
||||
"\t\t\t\t\t\"userid\": \"lisi\",\n" +
|
||||
"\t\t\t\t\t\"type\": 2\n" +
|
||||
"\t\t\t\t}\n" +
|
||||
"\t\t\t],\n" +
|
||||
" \"is_graduated\": 0\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"name\": \"一年级一班\",\n" +
|
||||
"\t\t\t\"parentid\": 1,\n" +
|
||||
"\t\t\t\"id\": 3,\n" +
|
||||
"\t\t\t\"type\": 1,\n" +
|
||||
"\t\t\t\"department_admins\": [\n" +
|
||||
"\t\t\t\t{\n" +
|
||||
"\t\t\t\t\t\"userid\": \"zhangsan\",\n" +
|
||||
"\t\t\t\t\t\"type\": 3,\n" +
|
||||
"\t\t\t\t\t\"subject\":\"语文\"\n" +
|
||||
"\t\t\t\t},\n" +
|
||||
"\t\t\t\t{\n" +
|
||||
"\t\t\t\t\t\"userid\": \"lisi\",\n" +
|
||||
"\t\t\t\t\t\"type\": 4,\n" +
|
||||
"\t\t\t\t\t\"subject\":\"数学\"\n" +
|
||||
"\t\t\t\t}\n" +
|
||||
"\t\t\t],\n" +
|
||||
"\t\t\t\"open_group_chat\": 1,\n" +
|
||||
" \"group_chat_id\": \"group_chat_id\"\n" +
|
||||
"\t\t}\n" +
|
||||
"\t]\n" +
|
||||
"}\n";
|
||||
|
||||
String deptId3Json = "{\n" +
|
||||
" \"errcode\": 0,\n" +
|
||||
" \"errmsg\": \"ok\",\n" +
|
||||
" \"departments\": [\n" +
|
||||
" {\n" +
|
||||
" \"name\": \"一年级一班\",\n" +
|
||||
" \"parentid\": 1,\n" +
|
||||
" \"id\": 3,\n" +
|
||||
" \"type\": 1,\n" +
|
||||
" \"department_admins\": [\n" +
|
||||
" {\n" +
|
||||
" \"userid\": \"zhangsan\",\n" +
|
||||
" \"type\": 3,\n" +
|
||||
" \"subject\":\"语文\"\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"userid\": \"lisi\",\n" +
|
||||
" \"type\": 4,\n" +
|
||||
" \"subject\":\"数学\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"open_group_chat\": 1,\n" +
|
||||
" \"group_chat_id\": \"group_chat_id\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
|
||||
String deptId2Json = "{\n" +
|
||||
" \"errcode\": 0,\n" +
|
||||
" \"errmsg\": \"ok\",\n" +
|
||||
" \"departments\": []\n" +
|
||||
"}\n";
|
||||
|
||||
|
||||
@Test
|
||||
public void testListDepartmentWhenIdIsNull() throws WxErrorException {
|
||||
|
||||
WxCpService mockCpService = Mockito.mock(WxCpService.class);
|
||||
WxCpSchoolUserServiceImpl wxCpSchoolUserService = new WxCpSchoolUserServiceImpl(mockCpService);
|
||||
Mockito.when(mockCpService.getWxCpConfigStorage()).thenReturn(new WxCpDefaultConfigImpl());
|
||||
Mockito.when(mockCpService.get(mockCpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), null)).thenReturn(allDeptListJson);
|
||||
WxCpDepartmentList wxCpDepartmentList = wxCpSchoolUserService.listDepartment(null);
|
||||
//WxCpDepartmentList没有重写Equals和Hashcode,不能直接比较
|
||||
Gson gson = new Gson();
|
||||
assertEquals(gson.toJson(wxCpDepartmentList), gson.toJson(gson.fromJson(allDeptListJson, WxCpDepartmentList.class)), "should be equal");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListDepartmentWhenIdIs2() throws WxErrorException {
|
||||
|
||||
WxCpService mockCpService = Mockito.mock(WxCpService.class);
|
||||
WxCpSchoolUserServiceImpl wxCpSchoolUserService = new WxCpSchoolUserServiceImpl(mockCpService);
|
||||
Mockito.when(mockCpService.getWxCpConfigStorage()).thenReturn(new WxCpDefaultConfigImpl());
|
||||
Gson gson = new Gson();
|
||||
int deptId = 2;
|
||||
Mockito.when(mockCpService.get(String.format("%s?id=%s", mockCpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), deptId), null)).thenReturn(deptId2Json);
|
||||
//WxCpDepartmentList没有重写Equals和Hashcode,不能直接比较
|
||||
assertEquals(gson.toJson(wxCpSchoolUserService.listDepartment(deptId)), gson.toJson(gson.fromJson(deptId2Json, WxCpDepartmentList.class)), "should be equal");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListDepartmentWhenIdIs3() throws WxErrorException {
|
||||
|
||||
WxCpService mockCpService = Mockito.mock(WxCpService.class);
|
||||
WxCpSchoolUserServiceImpl wxCpSchoolUserService = new WxCpSchoolUserServiceImpl(mockCpService);
|
||||
Mockito.when(mockCpService.getWxCpConfigStorage()).thenReturn(new WxCpDefaultConfigImpl());
|
||||
Gson gson = new Gson();
|
||||
int deptId = 3;
|
||||
Mockito.when(mockCpService.get(String.format("%s?id=%s", mockCpService.getWxCpConfigStorage().getApiUrl(DEPARTMENT_LIST), deptId), null)).thenReturn(deptId3Json);
|
||||
//WxCpDepartmentList没有重写Equals和Hashcode,不能直接比较
|
||||
assertEquals(gson.toJson(wxCpSchoolUserService.listDepartment(deptId)), gson.toJson(gson.fromJson(deptId3Json, WxCpDepartmentList.class)), "should be equal");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>weixin-java-miniapp</artifactId>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package cn.binarywang.wx.miniapp.api;
|
||||
|
||||
import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementGetOrderDetailPath;
|
||||
import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementResult;
|
||||
import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingInfoBaseResponse;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
|
||||
/**
|
||||
* @author xzh
|
||||
* @Description
|
||||
* @createTime 2025/01/16 15:20
|
||||
*/
|
||||
public interface WxMaOrderManagementService {
|
||||
|
||||
/**
|
||||
* 查询订单详情路径
|
||||
* 注意事项
|
||||
* 如果没有配置过订单详情路径,会返回成功,其中path为''。
|
||||
*
|
||||
* @return WxMaOrderManagementGetOrderDetailPath
|
||||
* @throws WxErrorException e
|
||||
*/
|
||||
WxMaOrderManagementGetOrderDetailPath getOrderDetailPath()
|
||||
throws WxErrorException;
|
||||
|
||||
|
||||
/**
|
||||
* 配置订单详情路径
|
||||
* 注意事项
|
||||
* 调用接口前需要先完成订单中心授权协议签署。
|
||||
* 请确保配置的path可正常跳转到小程序,并且path必须包含字符串“${商品订单号}”。
|
||||
*
|
||||
* @param path 订单详情路径
|
||||
* @return WxMaOrderManagementResult
|
||||
* @throws WxErrorException e
|
||||
*/
|
||||
WxMaOrderManagementResult updateOrderDetailPath(String path)
|
||||
throws WxErrorException;
|
||||
|
||||
}
|
||||
@@ -550,6 +550,12 @@ public interface WxMaService extends WxService {
|
||||
* @return getWxMaOrderShippingService
|
||||
*/
|
||||
WxMaOrderShippingService getWxMaOrderShippingService();
|
||||
/**
|
||||
* 小程序订单管理服务
|
||||
*
|
||||
* @return WxMaOrderManagementService
|
||||
*/
|
||||
WxMaOrderManagementService getWxMaOrderManagementService();
|
||||
|
||||
/**
|
||||
* 小程序openApi管理
|
||||
|
||||
@@ -153,6 +153,9 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
|
||||
private final WxMaOrderShippingService wxMaOrderShippingService =
|
||||
new WxMaOrderShippingServiceImpl(this);
|
||||
|
||||
private final WxMaOrderManagementService wxMaOrderManagementService =
|
||||
new WxMaOrderManagementServiceImpl(this);
|
||||
|
||||
private final WxMaOpenApiService wxMaOpenApiService = new WxMaOpenApiServiceImpl(this);
|
||||
private final WxMaVodService wxMaVodService = new WxMaVodServiceImpl(this);
|
||||
private final WxMaXPayService wxMaXPayService = new WxMaXPayServiceImpl(this);
|
||||
@@ -817,6 +820,16 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
|
||||
return this.wxMaOrderShippingService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序订单管理服务
|
||||
*
|
||||
* @return WxMaOrderManagementService
|
||||
*/
|
||||
@Override
|
||||
public WxMaOrderManagementService getWxMaOrderManagementService() {
|
||||
return this.wxMaOrderManagementService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMaOpenApiService getWxMaOpenApiService() {
|
||||
return this.wxMaOpenApiService;
|
||||
|
||||
@@ -207,7 +207,7 @@ public class WxMaImmediateDeliveryServiceImpl implements WxMaImmediateDeliverySe
|
||||
|
||||
@Override
|
||||
public WxMaBaseResponse updateWaybillGoods(UpdateWaybillGoodsRequest request) throws WxErrorException {
|
||||
String responseContent = this.wxMaService.post(InstantDelivery.GET_DELIVERY_LIST_URL,request);
|
||||
String responseContent = this.wxMaService.post(InstantDelivery.UPDATE_WAYBILL_GOODS_URL,request);
|
||||
WxMaBaseResponse response = WxMaGsonBuilder.create().fromJson(responseContent, WxMaBaseResponse.class);
|
||||
if (response.getErrcode() == -1) {
|
||||
throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package cn.binarywang.wx.miniapp.api.impl;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaOrderManagementService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementGetOrderDetailPath;
|
||||
import cn.binarywang.wx.miniapp.bean.order.WxMaOrderManagementResult;
|
||||
import cn.binarywang.wx.miniapp.bean.shop.response.WxMaOrderShippingInfoBaseResponse;
|
||||
import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.enums.WxType;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.json.GsonHelper;
|
||||
import me.chanjar.weixin.common.util.json.GsonParser;
|
||||
|
||||
import static cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants.OrderManagement.*;
|
||||
|
||||
|
||||
/**
|
||||
* @author xzh
|
||||
* @Description
|
||||
* @createTime 2025/01/16 15:31
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class WxMaOrderManagementServiceImpl implements WxMaOrderManagementService {
|
||||
|
||||
private final WxMaService wxMaService;
|
||||
|
||||
/**
|
||||
* 查询订单详情路径
|
||||
* 注意事项
|
||||
* 如果没有配置过订单详情路径,会返回成功,其中path为''。
|
||||
*
|
||||
* @return WxMaOrderManagementGetOrderDetailPath
|
||||
* @throws WxErrorException e
|
||||
*/
|
||||
@Override
|
||||
public WxMaOrderManagementGetOrderDetailPath getOrderDetailPath() throws WxErrorException {
|
||||
return request(GET_ORDER_DETAIL_PATH, new Object(), WxMaOrderManagementGetOrderDetailPath.class);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置订单详情路径
|
||||
* 注意事项
|
||||
* 调用接口前需要先完成订单中心授权协议签署。
|
||||
* 请确保配置的path可正常跳转到小程序,并且path必须包含字符串“${商品订单号}”。
|
||||
*
|
||||
* @param path 订单详情路径
|
||||
* @return WxMaOrderManagementResult
|
||||
* @throws WxErrorException e
|
||||
*/
|
||||
@Override
|
||||
public WxMaOrderManagementResult updateOrderDetailPath(String path) throws WxErrorException {
|
||||
JsonObject jsonObject = GsonHelper.buildJsonObject("path", path);
|
||||
return request(UPDATE_ORDER_DETAIL_PATH, jsonObject, WxMaOrderManagementResult.class);
|
||||
|
||||
}
|
||||
|
||||
private <T> T request(String url, Object request, Class<T> resultT) throws WxErrorException {
|
||||
String responseContent = this.wxMaService.post(url, request);
|
||||
JsonObject jsonObject = GsonParser.parse(responseContent);
|
||||
if (jsonObject.get(WxConsts.ERR_CODE).getAsInt() != 0) {
|
||||
throw new WxErrorException(WxError.fromJson(responseContent, WxType.MiniApp));
|
||||
}
|
||||
return WxMaGsonBuilder.create().fromJson(responseContent, resultT);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ public class WxMaMessage implements Serializable {
|
||||
private static final long serialVersionUID = -3586245291677274914L;
|
||||
|
||||
/**
|
||||
* 使用dom4j解析的存放所有xml属性和值的map.
|
||||
* 使用dom4j解析的存放所有xml或json属性和值的map.
|
||||
*/
|
||||
private Map<String, Object> allFieldsMap;
|
||||
|
||||
@@ -287,6 +287,7 @@ public class WxMaMessage implements Serializable {
|
||||
}
|
||||
message.setUselessMsg(null);
|
||||
}
|
||||
message.setAllFieldsMap(WxMaGsonBuilder.create().fromJson(json, Map.class));
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.binarywang.wx.miniapp.bean.order;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author xzh
|
||||
* @Description
|
||||
* @createTime 2025/01/16 15:27
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class WxMaOrderManagementGetOrderDetailPath extends WxMaOrderManagementResult {
|
||||
private static final long serialVersionUID = -5288666524298706169L;
|
||||
|
||||
/**
|
||||
* 订单详情路径
|
||||
*/
|
||||
@SerializedName("path")
|
||||
private String path;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package cn.binarywang.wx.miniapp.bean.order;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author xzh
|
||||
* @Description
|
||||
* @createTime 2025/01/16 15:27
|
||||
*/
|
||||
@Data
|
||||
public class WxMaOrderManagementResult implements Serializable {
|
||||
private static final long serialVersionUID = 1468925151935770503L;
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
@SerializedName("errcode")
|
||||
private Integer errCode;
|
||||
|
||||
/**
|
||||
* 错误原因
|
||||
*/
|
||||
@SerializedName("errmsg")
|
||||
private String errMsg;
|
||||
}
|
||||
@@ -626,7 +626,7 @@ public class WxMaApiUrlConstants {
|
||||
String GET_DELIVERY_LIST_URL =
|
||||
"https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/get_delivery_list";
|
||||
|
||||
/** 获取运力id列表get_delivery_list 商户使用此接口获取所有运力id的列表 */
|
||||
/** 物流服务-查询组件-更新物品信息接口 update_waybill_goods 更新物品信息 */
|
||||
String UPDATE_WAYBILL_GOODS_URL =
|
||||
"https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/update_waybill_goods";
|
||||
|
||||
@@ -751,7 +751,7 @@ public class WxMaApiUrlConstants {
|
||||
* </pre>
|
||||
*/
|
||||
String UPLOAD_COMBINED_SHIPPING_INFO =
|
||||
"https://api.weixin.qq.com/wxa/sec/order/upload_combined_shipping_info";
|
||||
"https://api.weixin.qq.com/wxa/sec/order/upload_combined_shipping_info";
|
||||
|
||||
/**
|
||||
* 查询订单发货状态.
|
||||
@@ -779,7 +779,7 @@ public class WxMaApiUrlConstants {
|
||||
* </pre>
|
||||
*/
|
||||
String NOTIFY_CONFIRM_RECEIVE =
|
||||
"https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive";
|
||||
"https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive";
|
||||
|
||||
/**
|
||||
* 消息跳转路径设置接口.
|
||||
@@ -809,6 +809,35 @@ public class WxMaApiUrlConstants {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序订单管理
|
||||
*
|
||||
* <pre>
|
||||
* 文档地址: https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html
|
||||
* </pre>
|
||||
*/
|
||||
public interface OrderManagement {
|
||||
|
||||
/**
|
||||
* 配置订单详情路径.
|
||||
*
|
||||
* <pre>
|
||||
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html
|
||||
* </pre>
|
||||
*/
|
||||
String UPDATE_ORDER_DETAIL_PATH = "https://api.weixin.qq.com/wxa/sec/order/update_order_detail_path";
|
||||
|
||||
/**
|
||||
* 查询订单详情路径.
|
||||
*
|
||||
* <pre>
|
||||
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order_center/order_center.html
|
||||
* </pre>
|
||||
*/
|
||||
String GET_ORDER_DETAIL_PATH = "https://api.weixin.qq.com/wxa/sec/order/get_order_detail_path";
|
||||
|
||||
}
|
||||
|
||||
public interface Vod {
|
||||
String LIST_MEDIA_URL = "https://api.weixin.qq.com/wxa/sec/vod/listmedia";
|
||||
String GET_MEDIA_URL = "https://api.weixin.qq.com/wxa/sec/vod/getmedia";
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>weixin-java-mp</artifactId>
|
||||
|
||||
@@ -50,12 +50,12 @@ public class WxMpServiceOkHttpImpl extends BaseWxMpServiceImpl<OkHttpClient, OkH
|
||||
clientBuilder.proxy(getRequestHttpProxy().getProxy());
|
||||
|
||||
//设置授权
|
||||
clientBuilder.authenticator(new Authenticator() {
|
||||
clientBuilder.proxyAuthenticator(new Authenticator() {
|
||||
@Override
|
||||
public Request authenticate(Route route, Response response) throws IOException {
|
||||
String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword());
|
||||
return response.request().newBuilder()
|
||||
.header("Authorization", credential)
|
||||
.header("Proxy-Authorization", credential)
|
||||
.build();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -186,6 +186,22 @@ public class WxMpXmlMessage implements Serializable {
|
||||
@JacksonXmlCData
|
||||
private String unionId;
|
||||
|
||||
@XStreamAlias("ret")
|
||||
@JacksonXmlProperty(localName = "ret")
|
||||
private Integer ret;
|
||||
|
||||
@XStreamAlias("nickname")
|
||||
@JacksonXmlProperty(localName = "nickname")
|
||||
private String nickname;
|
||||
|
||||
@XStreamAlias("first")
|
||||
@JacksonXmlProperty(localName = "first")
|
||||
private String first;
|
||||
|
||||
@XStreamAlias("second")
|
||||
@JacksonXmlProperty(localName = "second")
|
||||
private String second;
|
||||
|
||||
///////////////////////////////////////
|
||||
// 群发消息返回的结果
|
||||
///////////////////////////////////////
|
||||
|
||||
@@ -17,7 +17,7 @@ import java.util.Map;
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
public class WxMpSubscribeMessage {
|
||||
public class WxMpSubscribeMessage implements Serializable {
|
||||
|
||||
/**
|
||||
* 接收者openid.
|
||||
|
||||
@@ -15,7 +15,7 @@ public class WxMpMapConfigImpl extends WxMpDefaultConfigImpl {
|
||||
|
||||
private static final long serialVersionUID = 5311395137835650104L;
|
||||
|
||||
private static final ConcurrentHashMap<String, String> CONCURRENT_HASH_MAP = new ConcurrentHashMap<>(1);
|
||||
private final ConcurrentHashMap<String, String> CONCURRENT_HASH_MAP = new ConcurrentHashMap<>(1);
|
||||
|
||||
private static final String MAP_KEY = "access_token";
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package me.chanjar.weixin.mp.api.impl;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.api.test.ApiTestModule;
|
||||
import me.chanjar.weixin.mp.config.impl.WxMpMapConfigImpl;
|
||||
import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* 测试 ConcurrentHashMap 保存配置信息
|
||||
* @author jimmyjimmy-sw
|
||||
*/
|
||||
@Test
|
||||
@Guice(modules = ApiTestModule.class)
|
||||
public class WxMpMapConfigImplTest {
|
||||
|
||||
@Inject
|
||||
private WxMpService wxService;
|
||||
|
||||
/**
|
||||
* 测试多租户保存 WxMpMapConfigImpl 到 WxMpService,切换之后能获取到租户各自AppId对应的token
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
@Test
|
||||
public void testAppidSwitch() throws WxErrorException {
|
||||
// 保存租户A的配置信息,并获取token
|
||||
WxMpMapConfigImpl configAppA = new WxMpMapConfigImpl();
|
||||
String appidA = "APPID_A";
|
||||
configAppA.setAppId(appidA);
|
||||
configAppA.setSecret("APP_SECRET_A");
|
||||
configAppA.useStableAccessToken(true);
|
||||
String tokenA = "TOKEN_A";
|
||||
configAppA.updateAccessToken(tokenA,60 * 60 * 1);
|
||||
wxService.addConfigStorage(appidA, configAppA);
|
||||
WxMpConfigStorageHolder.set(appidA);
|
||||
assertEquals(this.wxService.getAccessToken(),tokenA);
|
||||
|
||||
// 保存租户B的配置信息,并获取token
|
||||
WxMpMapConfigImpl configAppB = new WxMpMapConfigImpl();
|
||||
String appidB = "APPID_B";
|
||||
configAppB.setAppId(appidB);
|
||||
configAppB.setSecret("APP_SECRET_B");
|
||||
configAppB.useStableAccessToken(true);
|
||||
String tokenB = "TOKEN_B";
|
||||
configAppB.updateAccessToken(tokenB,60 * 60 * 1);
|
||||
wxService.addConfigStorage(appidB, configAppB);
|
||||
WxMpConfigStorageHolder.set(appidB);
|
||||
assertEquals(this.wxService.getAccessToken(),tokenB);
|
||||
|
||||
// 上下文切换到租户A 获取租户A的token
|
||||
WxMpConfigStorageHolder.set(appidA);
|
||||
assertEquals(this.wxService.getAccessToken(),tokenA);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@ package me.chanjar.weixin.mp.bean.subscribe;
|
||||
|
||||
import org.testng.annotations.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.testng.AssertJUnit.*;
|
||||
|
||||
/**
|
||||
@@ -43,4 +46,9 @@ public class WxMpSubscribeMessageTest {
|
||||
assertEquals(message.toJson(), actual);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWxMpSubscribeMessageIsSerializable() {
|
||||
assertTrue(Arrays.stream(WxMpSubscribeMessage.class.getInterfaces()).anyMatch(anInterface -> anInterface.isInstance(Serializable.class)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>weixin-java-open</artifactId>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>wx-java</artifactId>
|
||||
<version>4.7.1.B</version>
|
||||
<version>4.7.4.B</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -119,8 +119,8 @@ public class ApplySubjectConfirmCreateRequest implements Serializable {
|
||||
* IDENTIFICATION_TYPE_TAIWAN_RESIDENT:台湾居民证
|
||||
* 示例值:IDENTIFICATION_TYPE_IDCARD
|
||||
*/
|
||||
@SerializedName("id_doc_type")
|
||||
private IdTypeEnum idDocType;
|
||||
@SerializedName("identification_type")
|
||||
private IdTypeEnum identificationType;
|
||||
|
||||
/**
|
||||
* 法定代表人说明函
|
||||
@@ -414,13 +414,13 @@ public class ApplySubjectConfirmCreateRequest implements Serializable {
|
||||
* 若未传入将默认填写:false。
|
||||
* 示例值:true
|
||||
*/
|
||||
@SerializedName("finance_institution")
|
||||
@SerializedName("is_finance_institution")
|
||||
private Boolean financeInstitution;
|
||||
|
||||
/**
|
||||
* 营业执照
|
||||
*/
|
||||
@SerializedName("business_license_info")
|
||||
@SerializedName("business_licence_info")
|
||||
private ApplySubConfirmBusinessLicenseInfo businessLicenseInfo;
|
||||
/**
|
||||
* 登记证书
|
||||
@@ -736,8 +736,8 @@ public class ApplySubjectConfirmCreateRequest implements Serializable {
|
||||
* 参看微信支付提供的特殊行业id对照表
|
||||
* 示例值:100
|
||||
*/
|
||||
@SerializedName("finance_type")
|
||||
private Integer financeType;
|
||||
@SerializedName("category_id")
|
||||
private Integer categoryId;
|
||||
|
||||
/**
|
||||
* 行业经营许可证资质照片
|
||||
@@ -791,29 +791,10 @@ public class ApplySubjectConfirmCreateRequest implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 法人开户承诺函
|
||||
* 待确认商户号列表
|
||||
*/
|
||||
@SerializedName("legal_person_commitment")
|
||||
private String legalPersonCommitment;
|
||||
|
||||
/**
|
||||
* 法人开户意愿视频
|
||||
*/
|
||||
@SerializedName("legal_person_video")
|
||||
private String legalPersonVideo;
|
||||
|
||||
/**
|
||||
* 补充材料
|
||||
*/
|
||||
@SerializedName("business_addition_pics")
|
||||
private List<String> businessAdditionPics;
|
||||
|
||||
/**
|
||||
* 补充说明
|
||||
*/
|
||||
@SerializedName("business_addition_msg")
|
||||
private String businessAdditionMsg;
|
||||
|
||||
@SerializedName("confirm_mchid_list")
|
||||
private List<String> confirmMchidList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -327,4 +327,141 @@ public class ComplaintDetailResult implements Serializable {
|
||||
*/
|
||||
@SerializedName("user_tag_list")
|
||||
private String[] userTagList;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:补充信息
|
||||
* 是否必填:否
|
||||
* 描述: 用在特定行业或场景下返回的补充信息
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("additional_info")
|
||||
private AdditionalInfo additionalInfo;
|
||||
|
||||
@Data
|
||||
public static class AdditionalInfo implements Serializable {
|
||||
private static final long serialVersionUID = 7917816070738944147L;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:补充信息类型
|
||||
* 是否必填:否
|
||||
* 描述: 补充信息类型
|
||||
* 示例值:SHARE_POWER_TYPE: 充电宝投诉相关行业
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("type")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:充电宝投诉相关信息
|
||||
* 是否必填:否
|
||||
* 描述:当type为充电宝投诉相关时有值
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("share_power_info")
|
||||
private SharePowerInfo sharePowerInfo;
|
||||
|
||||
/**
|
||||
* 充电宝投诉相关信息
|
||||
*/
|
||||
@Data
|
||||
public static class SharePowerInfo implements Serializable {
|
||||
private static final long serialVersionUID = -2878382307459369354L;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:归还时间
|
||||
* 是否必填:否
|
||||
* 描述:遵循rfc3339标准格式,格式为yyyy-MM-DDTHH:mm:ss+TIMEZONE,
|
||||
* yyyy-MM-DD表示年月日,T出现在字符串中,表示time元素的开头,
|
||||
* HH:mm:ss表示时分秒,
|
||||
* TIMEZONE表示时区(+08:00表示东八区时间,领先UTC 8小时,即北京时间)。
|
||||
* 示例值:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("return_time")
|
||||
private String returnTime;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:归还地点信息
|
||||
* 是否必填:否
|
||||
* 描述: 归还地点信息
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("return_address_info")
|
||||
private ReturnAddressInfo returnAddressInfo;
|
||||
|
||||
@Data
|
||||
public static class ReturnAddressInfo implements Serializable {
|
||||
private static final long serialVersionUID = -7649986542568217256L;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:归还地点
|
||||
* 是否必填:否 string(256)
|
||||
* 描述:归还地点
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("return_address")
|
||||
private String returnAddress;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:归还地点经度
|
||||
* 是否必填:否 string(32)
|
||||
* 描述:经度,字符串,范围为-180~180,负数表示西经。使用GCJ-02坐标系
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("longitude")
|
||||
private String longitude;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:归还地点纬度
|
||||
* 是否必填:否 string(32)
|
||||
* 描述:纬度,字符串,范围为-90~90,负数表示南纬。使用GCJ-02坐标系
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("latitude")
|
||||
private String latitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:是否归还同一柜机
|
||||
* 是否必填:否
|
||||
* 描述:用户声明是否将充电宝归还至与借取时同一柜机
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("is_returned_to_same_machine")
|
||||
private Boolean isReturnedToSameMachine;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:是否在平台协助中
|
||||
* 是否必填:否
|
||||
* 描述:标识当前投诉单是否正处在平台协助流程中。
|
||||
* 注:在协助期间由微信支付客服为用户服务,期间商户向用户发送的留言用户不可见
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("in_platform_service")
|
||||
private Boolean inPlatformService;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:是否需即时服务用户
|
||||
* 是否必填:否
|
||||
* 描述:因用户诉求紧急度、用户界面差异等因素,部分投诉单建议商户更即时地响应用户诉求。
|
||||
* 如此处标识为“是”,建议商户提升服务时效,给用户带来更好的体验
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("need_immediate_service")
|
||||
private Boolean needImmediateService;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -142,20 +142,30 @@ public class NegotiationHistoryResult implements Serializable {
|
||||
* 是否必填:是
|
||||
* 描述:
|
||||
* 当前投诉协商记录的操作类型,对应枚举:
|
||||
* USER_CREATE_COMPLAINT:用户提交投诉
|
||||
* USER_CONTINUE_COMPLAINT:用户继续投诉
|
||||
* USER_RESPONSE:用户留言
|
||||
* PLATFORM_RESPONSE:平台留言
|
||||
* MERCHANT_RESPONSE:商户留言
|
||||
* MERCHANT_CONFIRM_COMPLETE:商户申请结单
|
||||
* COMPLAINT_FULL_REFUNDED:投诉单全额退款
|
||||
* USER_CREATE_COMPLAINT_SYSTEM_MESSAGE:用户提交投诉系统通知
|
||||
* COMPLAINT_FULL_REFUNDED_SYSTEM_MESSAGE:投诉单全额退款系统通知
|
||||
* USER_CONTINUE_COMPLAINT_SYSTEM_MESSAGE:用户继续投诉系统通知
|
||||
* MERCHANT_CONFIRM_COMPLETE_SYSTEM_MESSAGE:商户申请结单系统通知
|
||||
* USER_REVOKE_COMPLAINT:用户主动撤诉(只存在于历史投诉单的协商历史中)
|
||||
* PLATFORM_HELP_APPLICATION:平台问询
|
||||
* USER_APPLY_PLATFORM_HELP:申请协助
|
||||
* USER_CREATE_COMPLAINT: 用户提交投诉
|
||||
* USER_CONTINUE_COMPLAINT: 用户继续投诉
|
||||
* USER_RESPONSE: 用户留言
|
||||
* PLATFORM_RESPONSE: 平台留言
|
||||
* MERCHANT_RESPONSE: 商户留言
|
||||
* MERCHANT_CONFIRM_COMPLETE: 商户申请结单
|
||||
* USER_CREATE_COMPLAINT_SYSTEM_MESSAGE: 用户提交投诉系统通知
|
||||
* COMPLAINT_FULL_REFUNDED_SYSTEM_MESSAGE: 投诉单发起全额退款系统通知
|
||||
* USER_CONTINUE_COMPLAINT_SYSTEM_MESSAGE: 用户继续投诉系统通知
|
||||
* USER_REVOKE_COMPLAINT: 用户主动撤诉(只存在于历史投诉单的协商历史中)
|
||||
* USER_COMFIRM_COMPLAINT: 用户确认投诉解决(只存在于历史投诉单的协商历史中)
|
||||
* PLATFORM_HELP_APPLICATION: 平台催办
|
||||
* USER_APPLY_PLATFORM_HELP: 用户申请平台协助
|
||||
* MERCHANT_APPROVE_REFUND: 商户同意退款申请
|
||||
* MERCHANT_REFUSE_RERUND: 商户拒绝退款申请, 此时操作内容里展示拒绝原因
|
||||
* USER_SUBMIT_SATISFACTION: 用户提交满意度调查结果,此时操作内容里会展示满意度分数
|
||||
* SERVICE_ORDER_CANCEL: 服务订单已取消
|
||||
* SERVICE_ORDER_COMPLETE: 服务订单已完成
|
||||
* COMPLAINT_PARTIAL_REFUNDED_SYSTEM_MESSAGE: 投诉单发起部分退款系统通知
|
||||
* COMPLAINT_REFUND_RECEIVED_SYSTEM_MESSAGE: 投诉单退款到账系统通知
|
||||
* COMPLAINT_ENTRUSTED_REFUND_SYSTEM_MESSAGE: 投诉单受托退款系统通知
|
||||
* USER_APPLY_PLATFORM_SERVICE: 用户申请平台协助
|
||||
* USER_CANCEL_PLATFORM_SERVICE: 用户取消平台协助
|
||||
* PLATFORM_SERVICE_FINISHED: 客服结束平台协助
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("operate_type")
|
||||
@@ -179,11 +189,32 @@ public class NegotiationHistoryResult implements Serializable {
|
||||
* 描述:
|
||||
* 当前投诉协商记录提交的图片凭证(url格式),最多返回4张图片,url有效时间为1小时。如未查询到协商历史图片凭证,则返回空数组。
|
||||
* 注:本字段包含商户、微信支付客服在协商解决投诉时上传的图片凭证,若希望查看用户图片,请使用complaint_media_list字段并联系微信支付客服
|
||||
* 注:此字段不包含用户提交的图片凭证,建议统一使用complaint_media_list字段接收和请求资料凭证,未来该字段将废弃
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("image_list")
|
||||
private List<String> imageList;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:用户申请平台协助原因
|
||||
* 是否必填:否
|
||||
* 描述:用户此次申请平台协助时选择的申请协助原因
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("user_appy_platform_service_reason")
|
||||
private String userApplyPlatformServiceReason;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:用户申请平台协助原因描述
|
||||
* 是否必填:否
|
||||
* 描述:用户此次申请平台协助时填写的具体申请协助原因描述
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("user_appy_platform_service_reason_description")
|
||||
private String userApplyPlatformServiceReasonDescription;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,4 +94,57 @@ public class ResponseRequest implements Serializable {
|
||||
@SerializedName("jump_url_text")
|
||||
private String jumpUrlText;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:跳转小程序信息
|
||||
* 是否必填:否
|
||||
* 描述:商户可在回复中附加小程序信息,引导用户跳转至商户客诉处理小程序。
|
||||
* 注:配置小程序属于灰度功能,若有需要请联系对接的行业运营进行咨询。
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("mini_program_jump_info")
|
||||
private MiniProgramJumpInfo miniProgramJumpInfo;
|
||||
|
||||
|
||||
/**
|
||||
* 跳转小程序信息
|
||||
*/
|
||||
@Data
|
||||
public static class MiniProgramJumpInfo implements Serializable {
|
||||
private static final long serialVersionUID = 1169503275787468380L;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:跳转小程序APPID
|
||||
* 是否必填:是
|
||||
* 描述:商户可在回复中附加小程序页面路径,引导用户跳转至商户服务工具页面。
|
||||
* 该字段为小程序APPID。
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("appid")
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:跳转小程序页面PATH
|
||||
* 是否必填:是
|
||||
* 描述:商户可在回复中附加小程序页面路径,引导用户跳转至商户服务工具页面。
|
||||
* 该字段为小程序路径。
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("path")
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:跳转小程序页面名称
|
||||
* 是否必填:是
|
||||
* 描述:商户可在回复中附加小程序页面路径,引导用户跳转至商户服务工具页面。
|
||||
* 该字段为商户可自定义的页面名称。
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("text")
|
||||
private String text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class UpdateRefundProgressRequest implements Serializable {
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:拒绝退款原因
|
||||
* 是否必填:否
|
||||
* 是否必填:否 string(200)
|
||||
* 描述:在拒绝退款时返回拒绝退款的原因
|
||||
* </pre>
|
||||
*/
|
||||
@@ -72,7 +72,9 @@ public class UpdateRefundProgressRequest implements Serializable {
|
||||
* <pre>
|
||||
* 字段名:拒绝退款的举证图片列表
|
||||
* 是否必填:否
|
||||
* 描述:在拒绝退款时,如果有拒绝的图片举证,可以提供 最多上传4张图片, 传入调用“商户上传反馈图片”接口返回的media_id,最多上传4张图片凭证
|
||||
* 描述:在拒绝退款时,如果有拒绝的图片举证,可以提供 最多上传4张图片,
|
||||
* 传入调用“商户上传反馈图片”接口返回的media_id,最多上传4张图片凭证
|
||||
*
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName("reject_media_list")
|
||||
@@ -81,7 +83,7 @@ public class UpdateRefundProgressRequest implements Serializable {
|
||||
/**
|
||||
* <pre>
|
||||
* 字段名:备注
|
||||
* 是否必填:否
|
||||
* 是否必填:否 string(200)
|
||||
* 描述:任何需要向微信支付客服反馈的信息
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
@@ -47,13 +47,23 @@ public class ComplaintNotifyResult implements Serializable {
|
||||
* 是否必填:是
|
||||
* 描述:
|
||||
* 触发本次投诉通知回调的具体动作类型,枚举如下:
|
||||
* 常规通知:
|
||||
* CREATE_COMPLAINT:用户提交投诉
|
||||
* CONTINUE_COMPLAINT:用户继续投诉
|
||||
* USER_RESPONSE:用户新留言
|
||||
* RESPONSE_BY_PLATFORM:平台新留言
|
||||
* SELLER_REFUND:收款方全额退款
|
||||
* SELLER_REFUND:商户发起全额退款
|
||||
* MERCHANT_RESPONSE:商户新回复
|
||||
* MERCHANT_CONFIRM_COMPLETE:商户反馈处理完成
|
||||
* USER_APPLY_PLATFORM_SERVICE:用户申请平台协助
|
||||
* USER_CANCEL_PLATFORM_SERVICE:用户取消平台协助
|
||||
* PLATFORM_SERVICE_FINISHED:客服结束平台协助
|
||||
*
|
||||
* 申请退款单的附加通知:
|
||||
* 以下通知会更新投诉单状态,建议收到后查询投诉单详情。
|
||||
* MERCHANT_APPROVE_REFUND:商户同意退款
|
||||
* MERCHANT_REJECT_REFUND:商户驳回退款
|
||||
* REFUND_SUCCESS:退款到账
|
||||
* </pre>
|
||||
*/
|
||||
@SerializedName(value = "action_type")
|
||||
|
||||
@@ -250,6 +250,12 @@ public class WxPayUnifiedOrderV3Request implements Serializable {
|
||||
*/
|
||||
@SerializedName(value = "openid")
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 实名支付用户身份标识
|
||||
*/
|
||||
@SerializedName(value = "identity")
|
||||
private Identity identity;
|
||||
}
|
||||
|
||||
@Data
|
||||
@@ -572,4 +578,36 @@ public class WxPayUnifiedOrderV3Request implements Serializable {
|
||||
@SerializedName(value = "profit_sharing")
|
||||
private Boolean profitSharing;
|
||||
}
|
||||
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public static class Identity implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 证件类型
|
||||
* IDCARD:身份证
|
||||
* HONGKONG_MACAO:港澳回乡证
|
||||
* HONGKONG_MACAO_RESIDENT:港澳居住证
|
||||
* TAIWAN_RESIDENT:台湾居住证
|
||||
* FOREIGN_RESIDENT:外国人永居证
|
||||
* OVERSEA_PASSPORT:护照
|
||||
*/
|
||||
@SerializedName(value = "type")
|
||||
private String type;
|
||||
/**
|
||||
* 证件号
|
||||
* 证件号,如身份证号。
|
||||
* 示例值:43102119910910512X
|
||||
*/
|
||||
@SerializedName(value = "number")
|
||||
private String number;
|
||||
/**
|
||||
* 证件姓名。
|
||||
* 示例值:周星星
|
||||
*/
|
||||
@SerializedName(value = "name")
|
||||
private String name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.github.binarywang.wxpay.bean.transfer;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 商家转账到零钱撤销转账接口
|
||||
* 文档地址:https://pay.weixin.qq.com/doc/v3/merchant/4012716458
|
||||
* </pre>
|
||||
*
|
||||
* @author Nor
|
||||
* @date 2025/1/17
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class TransferBillsCancelResult implements Serializable {
|
||||
private static final long serialVersionUID = -4935840810530008418L;
|
||||
|
||||
/**
|
||||
* 【商户单号】 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
|
||||
*/
|
||||
@SerializedName("out_bill_no")
|
||||
private String outBillNo;
|
||||
|
||||
/**
|
||||
* 【微信转账单号】 微信转账单号,微信商家转账系统返回的唯一标识
|
||||
*/
|
||||
@SerializedName("transfer_bill_no")
|
||||
private String transferBillNo;
|
||||
|
||||
/**
|
||||
* 【单据状态】 商家转账订单状态
|
||||
* 可选取值
|
||||
* CANCELING: 商户撤销请求受理成功,该笔转账正在撤销中
|
||||
* CANCELLED: 转账撤销完成
|
||||
*/
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* 【最后一次单据状态变更时间】 按照使用rfc3339所定义的格式,格式为yyyy-MM-DDThh:mm:ss+TIMEZONE
|
||||
*/
|
||||
@SerializedName("update_time")
|
||||
private String updateTime;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.github.binarywang.wxpay.bean.transfer;
|
||||
|
||||
import com.github.binarywang.wxpay.constant.WxPayConstants;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 商家转账到零钱查询转账单接口
|
||||
* 文档地址:https://pay.weixin.qq.com/doc/v3/merchant/4012716457 https://pay.weixin.qq.com/doc/v3/merchant/4012716437
|
||||
* </pre>
|
||||
*
|
||||
* @author Nor
|
||||
* @date 2025/1/17
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class TransferBillsGetResult implements Serializable {
|
||||
private static final long serialVersionUID = -6376955113492371763L;
|
||||
|
||||
/**
|
||||
* 【商户号】 微信支付分配的商户号
|
||||
*/
|
||||
@SerializedName("mch_id")
|
||||
private String mchId;
|
||||
|
||||
/**
|
||||
* 【商户单号】 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
|
||||
*/
|
||||
@SerializedName("out_bill_no")
|
||||
private String outBillNo;
|
||||
|
||||
/**
|
||||
* 【商家转账订单号】 商家转账订单的主键,唯一定义此资源的标识
|
||||
*/
|
||||
@SerializedName("transfer_bill_no")
|
||||
private String transferBillNo;
|
||||
|
||||
/**
|
||||
* 【商户AppID】 申请商户号的AppID或商户号绑定的AppID(企业号corpid即为此AppID)
|
||||
*/
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 【单据状态】
|
||||
* 可选取值
|
||||
* ACCEPTED: 转账已受理
|
||||
* PROCESSING: 转账处理中,转账结果尚未明确,如一直处于此状态,建议检查账户余额是否足够
|
||||
* WAIT_USER_CONFIRM: 待收款用户确认,可拉起微信收款确认页面进行收款确认
|
||||
* TRANSFERING: 转账结果尚未明确,可拉起微信收款确认页面再次重试确认收款
|
||||
* SUCCESS: 转账成功
|
||||
* FAIL: 转账失败
|
||||
* CANCELING: 商户撤销请求受理成功,该笔转账正在撤销中
|
||||
* CANCELLED: 转账撤销完成
|
||||
*
|
||||
* @see WxPayConstants.TransformBillState
|
||||
*/
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* 【转账金额】 转账金额单位为“分”。
|
||||
*/
|
||||
@SerializedName("transfer_amount")
|
||||
private String transferAmount;
|
||||
|
||||
/**
|
||||
* 【转账备注】 单条转账备注(微信用户会收到该备注),UTF8编码,最多允许32个字符
|
||||
*/
|
||||
@SerializedName("transfer_remark")
|
||||
private String transferRemark;
|
||||
|
||||
/**
|
||||
* 【失败原因】 订单已失败或者已退资金时,返回失败原因
|
||||
*/
|
||||
@SerializedName("fail_reason")
|
||||
private String failReason;
|
||||
|
||||
/**
|
||||
* 【收款用户OpenID】 商户AppID下,某用户的OpenID
|
||||
*/
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 【收款用户姓名】 收款方真实姓名。支持标准RSA算法和国密算法,公钥由微信侧提供转账金额 >= 2,000元时,该笔明细必须填写若商户传入收款用户姓名,微信支付会校验用户OpenID与姓名是否一致,并提供电子回单
|
||||
*/
|
||||
@SerializedName("user_name")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 【单据创建时间】 单据受理成功时返回,按照使用rfc3339所定义的格式,格式为yyyy-MM-DDThh:mm:ss+TIMEZONE
|
||||
*/
|
||||
@SerializedName("create_time")
|
||||
private String createTime;
|
||||
|
||||
/**
|
||||
* 【最后一次状态变更时间】 单据最后更新时间,按照使用rfc3339所定义的格式,格式为yyyy-MM-DDThh:mm:ss+TIMEZONE
|
||||
*/
|
||||
@SerializedName("update_time")
|
||||
private String updateTime;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.github.binarywang.wxpay.bean.transfer;
|
||||
|
||||
import com.github.binarywang.wxpay.bean.notify.OriginNotifyResponse;
|
||||
import com.github.binarywang.wxpay.bean.notify.WxPayBaseNotifyV3Result;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 商家转账到零钱接口将转账结果通知用户
|
||||
* 文档地址:https://pay.weixin.qq.com/doc/v3/merchant/4012716434
|
||||
* </pre>
|
||||
*/
|
||||
@Data
|
||||
public class TransferBillsNotifyResult implements Serializable, WxPayBaseNotifyV3Result<TransferBillsNotifyResult.DecryptNotifyResult> {
|
||||
/**
|
||||
* 源数据
|
||||
*/
|
||||
private OriginNotifyResponse rawData;
|
||||
/**
|
||||
* 解密后的数据
|
||||
*/
|
||||
private TransferBillsNotifyResult.DecryptNotifyResult result;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public static class DecryptNotifyResult implements Serializable {
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
@SerializedName(value = "mch_id")
|
||||
private String mchId;
|
||||
/**
|
||||
* 商家批次单号
|
||||
*/
|
||||
@SerializedName(value = "out_bill_no")
|
||||
private String outBillNo;
|
||||
/**
|
||||
* 微信批次单号
|
||||
*/
|
||||
@SerializedName(value = "transfer_bill_no")
|
||||
private String transferBillNo;
|
||||
/**
|
||||
* 批次状态
|
||||
*/
|
||||
@SerializedName(value = "state")
|
||||
private String state;
|
||||
/**
|
||||
* 转账金额
|
||||
*/
|
||||
@SerializedName(value = "transfer_amount")
|
||||
private Integer transferAmount;
|
||||
|
||||
/**
|
||||
* 批次状态
|
||||
*/
|
||||
@SerializedName(value = "openid")
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 单据创建时间
|
||||
*/
|
||||
@SerializedName(value = "create_time")
|
||||
private String createTime;
|
||||
/**
|
||||
* 最后一次状态变更时间
|
||||
*/
|
||||
@SerializedName(value = "update_time")
|
||||
private String updateTime;
|
||||
/**
|
||||
* 错误原因
|
||||
*/
|
||||
@SerializedName(value = "fail_reason")
|
||||
private String failReason;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package com.github.binarywang.wxpay.bean.transfer;
|
||||
|
||||
import com.github.binarywang.wxpay.v3.SpecEncrypt;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 发起商家转账API参数
|
||||
*
|
||||
* @author allovine
|
||||
* created on 2025/1/15
|
||||
**/
|
||||
@Data
|
||||
@Builder(builderMethodName = "newBuilder")
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TransferBillsRequest implements Serializable {
|
||||
private static final long serialVersionUID = -2175582517588397437L;
|
||||
|
||||
/**
|
||||
* 直连商户的appid
|
||||
*/
|
||||
@SerializedName("appid")
|
||||
private String appid;
|
||||
|
||||
/**
|
||||
* 商户系统内部的商家单号
|
||||
*/
|
||||
@SerializedName("out_bill_no")
|
||||
private String outBillNo;
|
||||
|
||||
/**
|
||||
* 转账场景ID
|
||||
* 商户平台-产品中心-商家转账 申请
|
||||
* 佣金报酬 ID:1005
|
||||
*/
|
||||
@SerializedName("transfer_scene_id")
|
||||
private String transferSceneId;
|
||||
|
||||
/**
|
||||
* 用户在直连商户应用下的用户标示
|
||||
*/
|
||||
@SerializedName("openid")
|
||||
private String openid;
|
||||
|
||||
/**
|
||||
* 收款用户姓名
|
||||
*/
|
||||
@SpecEncrypt
|
||||
@SerializedName("user_name")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 转账金额
|
||||
*/
|
||||
@SerializedName("transfer_amount")
|
||||
private Integer transferAmount;
|
||||
|
||||
/**
|
||||
* 转账备注
|
||||
*/
|
||||
@SerializedName("transfer_remark")
|
||||
private String transferRemark;
|
||||
|
||||
/**
|
||||
* 异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的url,必须为https,不能携带参数
|
||||
*/
|
||||
@SerializedName("notify_url")
|
||||
private String notifyUrl;
|
||||
|
||||
/**
|
||||
* 用户收款感知
|
||||
*/
|
||||
@SerializedName("user_recv_perception")
|
||||
private String userRecvPerception;
|
||||
|
||||
|
||||
/**
|
||||
* 转账场景报备信息
|
||||
*/
|
||||
@SerializedName("transfer_scene_report_infos")
|
||||
private List<TransferSceneReportInfo> transferSceneReportInfos;
|
||||
|
||||
|
||||
@Data
|
||||
@Builder(builderMethodName = "newBuilder")
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public static class TransferSceneReportInfo {
|
||||
/**
|
||||
* 信息类型
|
||||
*/
|
||||
@SerializedName("info_type")
|
||||
private String infoType;
|
||||
|
||||
/**
|
||||
* 信息内容
|
||||
*/
|
||||
@SerializedName("info_content")
|
||||
private String infoContent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.github.binarywang.wxpay.bean.transfer;
|
||||
|
||||
import com.github.binarywang.wxpay.constant.WxPayConstants;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 商家转账结果
|
||||
*
|
||||
* @author allovine
|
||||
* created on 2025/1/15
|
||||
**/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class TransferBillsResult implements Serializable {
|
||||
private static final long serialVersionUID = -2175582517588397437L;
|
||||
|
||||
/**
|
||||
* 商户单号
|
||||
*/
|
||||
@SerializedName("out_bill_no")
|
||||
private String outBillNo;
|
||||
|
||||
/**
|
||||
* 微信转账单号
|
||||
*/
|
||||
@SerializedName("transfer_bill_no")
|
||||
private String transferBillNo;
|
||||
|
||||
/**
|
||||
* 单据创建时间
|
||||
*/
|
||||
@SerializedName("create_time")
|
||||
private String createTime;
|
||||
|
||||
/**
|
||||
* 单据状态
|
||||
*
|
||||
* @see WxPayConstants.TransformBillState
|
||||
*/
|
||||
@SerializedName("state")
|
||||
private String state;
|
||||
|
||||
/**
|
||||
* 失败原因
|
||||
*/
|
||||
@SerializedName("fail_reason")
|
||||
private String failReason;
|
||||
|
||||
/**
|
||||
* 跳转领取页面的package信息
|
||||
*/
|
||||
@SerializedName("package_info")
|
||||
private String packageInfo;
|
||||
}
|
||||
@@ -6,16 +6,6 @@ import com.github.binarywang.wxpay.util.ResourcesUtils;
|
||||
import com.github.binarywang.wxpay.v3.WxPayV3HttpClientBuilder;
|
||||
import com.github.binarywang.wxpay.v3.auth.*;
|
||||
import com.github.binarywang.wxpay.v3.util.PemUtils;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Optional;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.SneakyThrows;
|
||||
@@ -26,6 +16,18 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.ssl.SSLContexts;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Base64;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 微信支付配置
|
||||
*
|
||||
@@ -309,8 +311,8 @@ public class WxPayConfig {
|
||||
PublicKey publicKey = null;
|
||||
if (this.getPublicKeyString() != null || this.getPublicKeyPath() != null || this.publicKeyContent != null) {
|
||||
try (InputStream pubInputStream =
|
||||
this.loadConfigInputStream(this.getPublicKeyString(), this.getPublicKeyPath(),
|
||||
this.publicKeyContent, "publicKeyPath")) {
|
||||
this.loadConfigInputStream(this.getPublicKeyString(), this.getPublicKeyPath(),
|
||||
this.publicKeyContent, "publicKeyPath")) {
|
||||
publicKey = PemUtils.loadPublicKey(pubInputStream);
|
||||
}
|
||||
}
|
||||
@@ -318,16 +320,7 @@ public class WxPayConfig {
|
||||
//构造Http Proxy正向代理
|
||||
WxPayHttpProxy wxPayHttpProxy = getWxPayHttpProxy();
|
||||
|
||||
Verifier certificatesVerifier;
|
||||
if (publicKey == null) {
|
||||
certificatesVerifier =
|
||||
new AutoUpdateCertificatesVerifier(
|
||||
new WxPayCredentials(mchId, new PrivateKeySigner(certSerialNo, merchantPrivateKey)),
|
||||
this.getApiV3Key().getBytes(StandardCharsets.UTF_8), this.getCertAutoUpdateTime(),
|
||||
this.getPayBaseUrl(), wxPayHttpProxy);
|
||||
} else {
|
||||
certificatesVerifier = new PublicCertificateVerifier(publicKey, publicKeyId);
|
||||
}
|
||||
Verifier certificatesVerifier = getVerifier(merchantPrivateKey, wxPayHttpProxy, publicKey);
|
||||
|
||||
WxPayV3HttpClientBuilder wxPayV3HttpClientBuilder = WxPayV3HttpClientBuilder.create()
|
||||
.withMerchant(mchId, certSerialNo, merchantPrivateKey)
|
||||
@@ -353,6 +346,23 @@ public class WxPayConfig {
|
||||
}
|
||||
}
|
||||
|
||||
private Verifier getVerifier(PrivateKey merchantPrivateKey, WxPayHttpProxy wxPayHttpProxy, PublicKey publicKey) {
|
||||
Verifier certificatesVerifier = null;
|
||||
// 如果配置了平台证书,则初始化验证器以备v2版本接口验签(公钥灰度实现)
|
||||
if (this.getPrivateCertPath() != null && this.getPrivateKeyPath() != null) {
|
||||
certificatesVerifier = new AutoUpdateCertificatesVerifier(
|
||||
new WxPayCredentials(mchId, new PrivateKeySigner(certSerialNo, merchantPrivateKey)),
|
||||
this.getApiV3Key().getBytes(StandardCharsets.UTF_8), this.getCertAutoUpdateTime(),
|
||||
this.getPayBaseUrl(), wxPayHttpProxy);
|
||||
}
|
||||
if (publicKey != null) {
|
||||
Verifier publicCertificatesVerifier = new PublicCertificateVerifier(publicKey, publicKeyId);
|
||||
publicCertificatesVerifier.setOtherVerifier(certificatesVerifier);
|
||||
certificatesVerifier = publicCertificatesVerifier;
|
||||
}
|
||||
return certificatesVerifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化一个WxPayHttpProxy对象
|
||||
*
|
||||
@@ -365,21 +375,32 @@ public class WxPayConfig {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定参数加载输入流
|
||||
*
|
||||
* @param configString 证书内容进行Base64加密后的字符串
|
||||
* @param configPath 证书路径
|
||||
* @param configContent 证书内容的字节数组
|
||||
* @param certName 证书的标识
|
||||
* @return 输入流
|
||||
* @throws WxPayException 异常
|
||||
*/
|
||||
private InputStream loadConfigInputStream(String configString, String configPath, byte[] configContent,
|
||||
String fileName) throws WxPayException {
|
||||
InputStream inputStream;
|
||||
String certName) throws WxPayException {
|
||||
if (configContent != null) {
|
||||
inputStream = new ByteArrayInputStream(configContent);
|
||||
} else if (StringUtils.isNotEmpty(configString)) {
|
||||
configContent = configString.getBytes(StandardCharsets.UTF_8);
|
||||
inputStream = new ByteArrayInputStream(configContent);
|
||||
} else {
|
||||
if (StringUtils.isBlank(configPath)) {
|
||||
throw new WxPayException("请确保证书文件地址【" + fileName + "】或者内容已配置");
|
||||
}
|
||||
inputStream = this.loadConfigInputStream(configPath);
|
||||
return new ByteArrayInputStream(configContent);
|
||||
}
|
||||
return inputStream;
|
||||
|
||||
if (StringUtils.isNotEmpty(configString)) {
|
||||
configContent = Base64.getDecoder().decode(configString);
|
||||
return new ByteArrayInputStream(configContent);
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(configPath)) {
|
||||
throw new WxPayException(String.format("请确保【%s】的文件地址【%s】存在", certName, configPath));
|
||||
}
|
||||
|
||||
return this.loadConfigInputStream(configPath);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
|
||||
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
|
||||
import com.github.binarywang.wxpay.bean.result.WxPayMicropayResult;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.apache.commons.lang3.time.FastDateFormat;
|
||||
|
||||
import java.text.Format;
|
||||
@@ -353,4 +354,86 @@ public class WxPayConstants {
|
||||
public static final String PERSONAL_SUB_OPENID = "PERSONAL_SUB_OPENID";
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信商户转账订单状态
|
||||
*/
|
||||
@UtilityClass
|
||||
public static class TransformBillState {
|
||||
/**
|
||||
* 转账已受理
|
||||
*/
|
||||
public static final String ACCEPTED = "ACCEPTED";
|
||||
|
||||
/**
|
||||
* 转账处理中,转账结果尚未明确,如一直处于此状态,建议检查账户余额是否足够
|
||||
*/
|
||||
public static final String PROCESSING = "PROCESSING";
|
||||
|
||||
/**
|
||||
* 待收款用户确认,可拉起微信收款确认页面进行收款确认
|
||||
*/
|
||||
public static final String WAIT_USER_CONFIRM = "WAIT_USER_CONFIRM";
|
||||
|
||||
/**
|
||||
* 转账结果尚未明确,可拉起微信收款确认页面再次重试确认收款
|
||||
*/
|
||||
public static final String TRANSFERING = "TRANSFERING";
|
||||
|
||||
/**
|
||||
* 转账成功
|
||||
*/
|
||||
public static final String SUCCESS = "SUCCESS";
|
||||
|
||||
/**
|
||||
* 转账失败
|
||||
*/
|
||||
public static final String FAIL = "FAIL";
|
||||
|
||||
/**
|
||||
* 商户撤销请求受理成功,该笔转账正在撤销中
|
||||
*/
|
||||
public static final String CANCELING = "CANCELING";
|
||||
|
||||
/**
|
||||
* 转账撤销完成
|
||||
*/
|
||||
public static final String CANCELLED = "CANCELLED";
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 【转账场景ID】 该笔转账使用的转账场景,可前往“商户平台-产品中心-商家转账”中申请。
|
||||
*/
|
||||
@UtilityClass
|
||||
public static class TransformSceneId {
|
||||
/**
|
||||
* 现金营销
|
||||
*/
|
||||
public static final String CASH_MARKETING = "1001";
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户收款感知
|
||||
*
|
||||
* @see <a href="https://pay.weixin.qq.com/doc/v3/merchant/4012711988#3.3-%E5%8F%91%E8%B5%B7%E8%BD%AC%E8%B4%A6">官方文档</a>
|
||||
*/
|
||||
@UtilityClass
|
||||
public static class UserRecvPerception {
|
||||
/**
|
||||
* 转账场景 现金营销
|
||||
* 场景介绍 向参与营销活动的用户发放现金奖励
|
||||
*/
|
||||
public static class CASH_MARKETING {
|
||||
/**
|
||||
* 默认展示
|
||||
*/
|
||||
public static final String ACTIVITY = "活动奖励";
|
||||
|
||||
/**
|
||||
* 需在发起转账时,“用户收款感知”字段主动传入“现金奖励”才可展示
|
||||
*/
|
||||
public static final String CASH = "现金奖励";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ public interface ComplaintService {
|
||||
/**
|
||||
* <pre>
|
||||
* 商户上传反馈图片API
|
||||
* 文档详见: <a href="https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_10.shtml">...</a>
|
||||
* 文档详见: <a href="https://pay.weixin.qq.com/docs/merchant/apis/consumer-complaint/images/create-images.html">...</a>
|
||||
* 接口链接:https://api.mch.weixin.qq.com/v3/merchant-service/images/upload
|
||||
* </pre>
|
||||
*
|
||||
@@ -165,7 +165,7 @@ public interface ComplaintService {
|
||||
/**
|
||||
* <pre>
|
||||
* 商户上传反馈图片API
|
||||
* 文档详见: <a href="https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter10_2_10.shtml">...</a>
|
||||
* 文档详见: <a href="https://pay.weixin.qq.com/docs/merchant/apis/consumer-complaint/images/create-images.html">...</a>
|
||||
* 接口链接:https://api.mch.weixin.qq.com/v3/merchant-service/images/upload
|
||||
* </pre>
|
||||
*
|
||||
|
||||
@@ -111,4 +111,82 @@ public interface TransferService {
|
||||
*/
|
||||
TransferBatchDetailResult transferBatchesOutBatchNoDetail(String outBatchNo, String outDetailNo) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
*
|
||||
* 2025.1.15 开始新接口 发起商家转账API
|
||||
*
|
||||
* 请求方式:POST(HTTPS)
|
||||
* 请求地址:<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills">请求地址</a>
|
||||
*
|
||||
* 文档地址:<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716434">发起商家转账API</a>
|
||||
* </pre>
|
||||
*
|
||||
* @param request 转账请求参数
|
||||
* @return TransferBillsResult 转账结果
|
||||
* @throws WxPayException .
|
||||
*/
|
||||
TransferBillsResult transferBills(TransferBillsRequest request) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
*
|
||||
* 2025.1.15 开始新接口 撤销转账API
|
||||
*
|
||||
* 请求方式:POST(HTTPS)
|
||||
* 请求地址:<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/{out_bill_no}/cancel">请求地址</a>
|
||||
*
|
||||
* 文档地址:<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716458">商户撤销转账API</a>
|
||||
* </pre>
|
||||
*
|
||||
* @param outBillNo 【商户单号】 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
|
||||
* @return TransformBillsGetResult 转账单
|
||||
* @throws WxPayException .
|
||||
*/
|
||||
TransferBillsCancelResult transformBillsCancel(String outBillNo) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
*
|
||||
* 2025.1.15 开始新接口 发起商家转账API
|
||||
*
|
||||
* 请求方式:GET(HTTPS)
|
||||
* 请求地址:<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/{out_bill_no}">请求地址</a>
|
||||
*
|
||||
* 文档地址:<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716437">商户单号查询转账单API</a>
|
||||
* </pre>
|
||||
*
|
||||
* @param outBillNo 【商户单号】 商户系统内部的商家单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一
|
||||
* @return TransformBillsGetResult 转账单
|
||||
* @throws WxPayException .
|
||||
*/
|
||||
TransferBillsGetResult getBillsByOutBillNo(String outBillNo) throws WxPayException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
*
|
||||
* 2025.1.15 开始新接口 微信单号查询转账单API
|
||||
*
|
||||
* 请求方式:GET(HTTPS)
|
||||
* 请求地址:<a href="https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/transfer-bill-no/{transfer_bill_no}">请求地址</a>
|
||||
*
|
||||
* 文档地址:<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012716437">商户单号查询转账单API</a>
|
||||
* </pre>
|
||||
*
|
||||
* @param transferBillNo 【微信转账单号】 微信转账单号,微信商家转账系统返回的唯一标识
|
||||
* @return TransformBillsGetResult 转账单
|
||||
* @throws WxPayException .
|
||||
*/
|
||||
TransferBillsGetResult getBillsByTransferBillNo(String transferBillNo) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 2025.1.15 开始新接口 解析商家转账结果
|
||||
* 详见<a href="https://pay.weixin.qq.com/doc/v3/merchant/4012712115"></a>
|
||||
*
|
||||
* @param notifyData 通知数据
|
||||
* @param header 通知头部数据,不传则表示不校验头
|
||||
* @return the wx transfer notify result
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
TransferBillsNotifyResult parseTransferBillsNotifyResult(String notifyData, SignatureHeader header) throws WxPayException;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.github.binarywang.wxpay.bean.notify.*;
|
||||
import com.github.binarywang.wxpay.bean.request.*;
|
||||
import com.github.binarywang.wxpay.bean.result.*;
|
||||
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
|
||||
import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult;
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.constant.WxPayConstants;
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
@@ -38,16 +39,18 @@ public interface WxPayService {
|
||||
* Map里 加入新的 {@link WxPayConfig},适用于动态添加新的微信商户配置.
|
||||
*
|
||||
* @param mchId 商户id
|
||||
* @param appId 微信应用id
|
||||
* @param wxPayConfig 新的微信配置
|
||||
*/
|
||||
void addConfig(String mchId, WxPayConfig wxPayConfig);
|
||||
void addConfig(String mchId, String appId, WxPayConfig wxPayConfig);
|
||||
|
||||
/**
|
||||
* 从 Map中 移除 {@link String mchId} 所对应的 {@link WxPayConfig},适用于动态移除微信商户配置.
|
||||
* 从 Map中 移除 {@link String mchId} 和 {@link String appId} 所对应的 {@link WxPayConfig},适用于动态移除微信商户配置.
|
||||
*
|
||||
* @param mchId 对应商户的标识
|
||||
* @param appId 微信应用id
|
||||
*/
|
||||
void removeConfig(String mchId);
|
||||
void removeConfig(String mchId, String appId);
|
||||
|
||||
/**
|
||||
* 注入多个 {@link WxPayConfig} 的实现. 并为每个 {@link WxPayConfig} 赋予不同的 {@link String mchId} 值
|
||||
@@ -69,17 +72,19 @@ public interface WxPayService {
|
||||
* 进行相应的商户切换.
|
||||
*
|
||||
* @param mchId 商户标识
|
||||
* @param appId 微信应用id
|
||||
* @return 切换是否成功 boolean
|
||||
*/
|
||||
boolean switchover(String mchId);
|
||||
boolean switchover(String mchId, String appId);
|
||||
|
||||
/**
|
||||
* 进行相应的商户切换.
|
||||
*
|
||||
* @param mchId 商户标识
|
||||
* @param appId 微信应用id
|
||||
* @return 切换成功 ,则返回当前对象,方便链式调用,否则抛出异常
|
||||
*/
|
||||
WxPayService switchoverTo(String mchId);
|
||||
WxPayService switchoverTo(String mchId, String appId);
|
||||
|
||||
/**
|
||||
* 发送post请求,得到响应字节数组.
|
||||
@@ -616,10 +621,10 @@ public interface WxPayService {
|
||||
/**
|
||||
* 调用统一下单接口,并组装生成支付所需参数对象.
|
||||
*
|
||||
* @param <T> 请使用{@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段
|
||||
* @param <T> 请使用{@link WxPayUnifiedOrderV3Result}里的内部类或字段
|
||||
* @param tradeType the trade type
|
||||
* @param request 统一下单请求参数
|
||||
* @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段
|
||||
* @return 返回 {@link WxPayUnifiedOrderV3Result}里的内部类或字段
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
<T> T createOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException;
|
||||
@@ -627,10 +632,10 @@ public interface WxPayService {
|
||||
/**
|
||||
* 服务商模式调用统一下单接口,并组装生成支付所需参数对象.
|
||||
*
|
||||
* @param <T> 请使用{@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段
|
||||
* @param <T> 请使用{@link WxPayUnifiedOrderV3Result}里的内部类或字段
|
||||
* @param tradeType the trade type
|
||||
* @param request 统一下单请求参数
|
||||
* @return 返回 {@link com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result}里的内部类或字段
|
||||
* @return 返回 {@link WxPayUnifiedOrderV3Result}里的内部类或字段
|
||||
* @throws WxPayException the wx pay exception
|
||||
*/
|
||||
<T> T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException;
|
||||
@@ -991,6 +996,17 @@ public interface WxPayService {
|
||||
*/
|
||||
WxPayTransferBatchesNotifyV3Result parseTransferBatchesNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 解析商家转账批次回调通知
|
||||
* https://pay.weixin.qq.com/doc/v3/merchant/4012712115
|
||||
*
|
||||
* @param notifyData
|
||||
* @param header
|
||||
* @return
|
||||
* @throws WxPayException
|
||||
*/
|
||||
TransferBillsNotifyResult parseTransferBillsNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException;
|
||||
|
||||
/**
|
||||
* 解析服务商模式退款结果通知
|
||||
* 详见https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_1_11.shtml
|
||||
@@ -1603,7 +1619,8 @@ public interface WxPayService {
|
||||
|
||||
/**
|
||||
* 获取服务商直股份签约计划服务类
|
||||
* @return the partner pay score sign plan service
|
||||
*
|
||||
* @return the partner pay score sign plan service
|
||||
*/
|
||||
PartnerPayScoreSignPlanService getPartnerPayScoreSignPlanService();
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
|
||||
import com.github.binarywang.wxpay.bean.request.*;
|
||||
import com.github.binarywang.wxpay.bean.result.*;
|
||||
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
|
||||
import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult;
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.config.WxPayConfigHolder;
|
||||
import com.github.binarywang.wxpay.constant.WxPayConstants;
|
||||
import com.github.binarywang.wxpay.constant.WxPayConstants.SignType;
|
||||
import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType;
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
@@ -45,6 +45,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
import static com.github.binarywang.wxpay.constant.WxPayConstants.QUERY_COMMENT_DATE_FORMAT;
|
||||
@@ -121,7 +122,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
private final PartnerPayScoreService partnerPayScoreService = new PartnerPayScoreServiceImpl(this);
|
||||
|
||||
@Getter
|
||||
private final PartnerPayScoreSignPlanService partnerPayScoreSignPlanService=new PartnerPayScoreSignPlanServiceImpl(this);
|
||||
private final PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = new PartnerPayScoreSignPlanServiceImpl(this);
|
||||
|
||||
@Getter
|
||||
private final MerchantTransferService merchantTransferService = new MerchantTransferServiceImpl(this);
|
||||
@@ -129,7 +130,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
@Getter
|
||||
private final BrandMerchantTransferService brandMerchantTransferService = new BrandMerchantTransferServiceImpl(this);
|
||||
|
||||
protected Map<String, WxPayConfig> configMap = new HashMap<>();
|
||||
protected Map<String, WxPayConfig> configMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public WxPayConfig getConfig() {
|
||||
@@ -142,38 +143,37 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
|
||||
@Override
|
||||
public void setConfig(WxPayConfig config) {
|
||||
final String defaultMchId = config.getMchId();
|
||||
this.setMultiConfig(ImmutableMap.of(defaultMchId, config), defaultMchId);
|
||||
final String defaultKey = this.getConfigKey(config.getMchId(), config.getAppId());
|
||||
this.setMultiConfig(ImmutableMap.of(defaultKey, config), defaultKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addConfig(String mchId, WxPayConfig wxPayConfig) {
|
||||
public void addConfig(String mchId, String appId, WxPayConfig wxPayConfig) {
|
||||
synchronized (this) {
|
||||
if (this.configMap == null) {
|
||||
this.setConfig(wxPayConfig);
|
||||
} else {
|
||||
WxPayConfigHolder.set(mchId);
|
||||
this.configMap.put(mchId, wxPayConfig);
|
||||
String configKey = this.getConfigKey(mchId, appId);
|
||||
WxPayConfigHolder.set(configKey);
|
||||
this.configMap.put(configKey, wxPayConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeConfig(String mchId) {
|
||||
public void removeConfig(String mchId, String appId) {
|
||||
synchronized (this) {
|
||||
if (this.configMap.size() == 1) {
|
||||
this.configMap.remove(mchId);
|
||||
log.warn("已删除最后一个商户号配置:{},须立即使用setConfig或setMultiConfig添加配置", mchId);
|
||||
String configKey = this.getConfigKey(mchId, appId);
|
||||
this.configMap.remove(configKey);
|
||||
if (this.configMap.isEmpty()) {
|
||||
log.warn("已删除最后一个商户号配置:mchId[{}],appid[{}],须立即使用setConfig或setMultiConfig添加配置", mchId, appId);
|
||||
return;
|
||||
}
|
||||
if (WxPayConfigHolder.get().equals(mchId)) {
|
||||
this.configMap.remove(mchId);
|
||||
final String defaultMpId = this.configMap.keySet().iterator().next();
|
||||
WxPayConfigHolder.set(defaultMpId);
|
||||
log.warn("已删除默认商户号配置,商户号【{}】被设为默认配置", defaultMpId);
|
||||
return;
|
||||
if (WxPayConfigHolder.get().equals(configKey)) {
|
||||
final String nextConfigKey = this.configMap.keySet().iterator().next();
|
||||
WxPayConfigHolder.set(nextConfigKey);
|
||||
log.warn("已删除默认商户号配置,商户号【{}】被设为默认配置", nextConfigKey);
|
||||
}
|
||||
this.configMap.remove(mchId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,28 +183,34 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMultiConfig(Map<String, WxPayConfig> wxPayConfigs, String defaultMchId) {
|
||||
public void setMultiConfig(Map<String, WxPayConfig> wxPayConfigs, String defaultConfigKey) {
|
||||
this.configMap = Maps.newHashMap(wxPayConfigs);
|
||||
WxPayConfigHolder.set(defaultMchId);
|
||||
WxPayConfigHolder.set(defaultConfigKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean switchover(String mchId) {
|
||||
if (this.configMap.containsKey(mchId)) {
|
||||
WxPayConfigHolder.set(mchId);
|
||||
public boolean switchover(String mchId, String appId) {
|
||||
String configKey = this.getConfigKey(mchId, appId);
|
||||
if (this.configMap.containsKey(configKey)) {
|
||||
WxPayConfigHolder.set(configKey);
|
||||
return true;
|
||||
}
|
||||
log.error("无法找到对应【{}】的商户号配置信息,请核实!", mchId);
|
||||
log.error("无法找到对应mchId=【{}】,appId=【{}】的商户号配置信息,请核实!", mchId, appId);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayService switchoverTo(String mchId) {
|
||||
if (this.configMap.containsKey(mchId)) {
|
||||
WxPayConfigHolder.set(mchId);
|
||||
public WxPayService switchoverTo(String mchId, String appId) {
|
||||
String configKey = this.getConfigKey(mchId, appId);
|
||||
if (this.configMap.containsKey(configKey)) {
|
||||
WxPayConfigHolder.set(configKey);
|
||||
return this;
|
||||
}
|
||||
throw new WxRuntimeException(String.format("无法找到对应【%s】的商户号配置信息,请核实!", mchId));
|
||||
throw new WxRuntimeException(String.format("无法找到对应mchId=【%s】,appId=【%s】的商户号配置信息,请核实!", mchId, appId));
|
||||
}
|
||||
|
||||
private String getConfigKey(String mchId, String appId) {
|
||||
return mchId + "_" + appId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -301,7 +307,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
|
||||
@Override
|
||||
public WxPayRefundQueryV3Result refundPartnerQueryV3(WxPayRefundQueryV3Request request) throws WxPayException {
|
||||
String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", this.getPayBaseUrl(), request.getOutRefundNo(),request.getSubMchid());
|
||||
String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", this.getPayBaseUrl(), request.getOutRefundNo(), request.getSubMchid());
|
||||
String response = this.getV3(url);
|
||||
return GSON.fromJson(response, WxPayRefundQueryV3Result.class);
|
||||
}
|
||||
@@ -317,13 +323,13 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
log.debug("微信支付异步通知请求参数:{}", xmlData);
|
||||
WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData);
|
||||
if (signType == null) {
|
||||
this.switchover(result.getMchId(), result.getAppid());
|
||||
if (result.getSignType() != null) {
|
||||
// 如果解析的通知对象中signType有值,则使用它进行验签
|
||||
signType = result.getSignType();
|
||||
} else if (configMap.get(result.getMchId()).getSignType() != null) {
|
||||
} else if (this.getConfig().getSignType() != null) {
|
||||
// 如果配置中signType有值,则使用它进行验签
|
||||
signType = configMap.get(result.getMchId()).getSignType();
|
||||
this.switchover(result.getMchId());
|
||||
signType = this.getConfig().getSignType();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +352,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
*/
|
||||
private boolean verifyNotifySign(SignatureHeader header, String data) throws WxSignTestException {
|
||||
String wxPaySign = header.getSignature();
|
||||
if(wxPaySign.startsWith("WECHATPAY/SIGNTEST/")){
|
||||
if (wxPaySign.startsWith("WECHATPAY/SIGNTEST/")) {
|
||||
throw new WxSignTestException("微信支付签名探测流量");
|
||||
}
|
||||
String beforeSign = String.format("%s\n%s\n%s\n",
|
||||
@@ -420,7 +426,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
WxPayRefundNotifyResult result;
|
||||
if (XmlConfig.fastMode) {
|
||||
result = BaseWxPayResult.fromXML(xmlData, WxPayRefundNotifyResult.class);
|
||||
this.switchover(result.getMchId());
|
||||
this.switchover(result.getMchId(), result.getAppid());
|
||||
result.decryptReqInfo(this.getConfig().getMchKey());
|
||||
} else {
|
||||
result = WxPayRefundNotifyResult.fromXML(xmlData, this.getConfig().getMchKey());
|
||||
@@ -442,6 +448,11 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
return this.baseParseOrderNotifyV3Result(notifyData, header, WxPayTransferBatchesNotifyV3Result.class, WxPayTransferBatchesNotifyV3Result.DecryptNotifyResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransferBillsNotifyResult parseTransferBillsNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException {
|
||||
return this.baseParseOrderNotifyV3Result(notifyData, header, TransferBillsNotifyResult.class, TransferBillsNotifyResult.DecryptNotifyResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayPartnerRefundNotifyV3Result parsePartnerRefundNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException {
|
||||
return this.baseParseOrderNotifyV3Result(notifyData, header, WxPayPartnerRefundNotifyV3Result.class, WxPayPartnerRefundNotifyV3Result.DecryptNotifyResult.class);
|
||||
@@ -452,7 +463,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
try {
|
||||
log.debug("扫码支付回调通知请求参数:{}", xmlData);
|
||||
WxScanPayNotifyResult result = BaseWxPayResult.fromXML(xmlData, WxScanPayNotifyResult.class);
|
||||
this.switchover(result.getMchId());
|
||||
this.switchover(result.getMchId(), result.getAppid());
|
||||
log.debug("扫码支付回调通知解析后的对象:{}", result);
|
||||
result.checkResult(this, this.getConfig().getSignType(), false);
|
||||
return result;
|
||||
@@ -797,7 +808,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
@Override
|
||||
public <T> T combineTransactions(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException {
|
||||
CombineTransactionsResult result = this.combine(tradeType, request);
|
||||
return result.getPayInfo(tradeType, request.getCombineAppid(), request.getCombineAppid(), this.getConfig().getPrivateKey());
|
||||
return result.getPayInfo(tradeType, request.getCombineAppid(), request.getCombineMchid(), this.getConfig().getPrivateKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1300,7 +1311,7 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
@Override
|
||||
public WxPayFaceAuthInfoResult getWxPayFaceAuthInfo(WxPayFaceAuthInfoRequest request) throws WxPayException {
|
||||
if (StringUtils.isEmpty(request.getSignType())) {
|
||||
request.setSignType(WxPayConstants.SignType.MD5);
|
||||
request.setSignType(SignType.MD5);
|
||||
}
|
||||
|
||||
request.checkAndSign(this.getConfig());
|
||||
|
||||
@@ -48,8 +48,7 @@ public class TransferServiceImpl implements TransferService {
|
||||
if (request.getNeedQueryDetail()) {
|
||||
url = String.format("%s/v3/transfer/batches/batch-id/%s?need_query_detail=true&offset=%s&limit=%s&detail_status=%s",
|
||||
this.payService.getPayBaseUrl(), request.getBatchId(), request.getOffset(), request.getLimit(), request.getDetailStatus());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
url = String.format("%s/v3/transfer/batches/batch-id/%s?need_query_detail=false",
|
||||
this.payService.getPayBaseUrl(), request.getBatchId());
|
||||
}
|
||||
@@ -70,8 +69,7 @@ public class TransferServiceImpl implements TransferService {
|
||||
if (request.getNeedQueryDetail()) {
|
||||
url = String.format("%s/v3/transfer/batches/out-batch-no/%s?need_query_detail=true&offset=%s&limit=%s&detail_status=%s",
|
||||
this.payService.getPayBaseUrl(), request.getOutBatchNo(), request.getOffset(), request.getLimit(), request.getDetailStatus());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
url = String.format("%s/v3/transfer/batches/out-batch-no/%s?need_query_detail=false",
|
||||
this.payService.getPayBaseUrl(), request.getOutBatchNo());
|
||||
}
|
||||
@@ -85,4 +83,45 @@ public class TransferServiceImpl implements TransferService {
|
||||
String result = this.payService.getV3(url);
|
||||
return GSON.fromJson(result, TransferBatchDetailResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransferBillsResult transferBills(TransferBillsRequest request) throws WxPayException {
|
||||
String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills", this.payService.getPayBaseUrl());
|
||||
if (request.getUserName() != null && request.getUserName().length() > 0) {
|
||||
X509Certificate validCertificate = this.payService.getConfig().getVerifier().getValidCertificate();
|
||||
RsaCryptoUtil.encryptFields(request, validCertificate);
|
||||
}
|
||||
String result = this.payService.postV3WithWechatpaySerial(url, GSON.toJson(request));
|
||||
return GSON.fromJson(result, TransferBillsResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransferBillsCancelResult transformBillsCancel(String outBillNo) throws WxPayException {
|
||||
String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/%s/cancel",
|
||||
this.payService.getPayBaseUrl(), outBillNo);
|
||||
String result = this.payService.postV3(url, "");
|
||||
|
||||
return GSON.fromJson(result, TransferBillsCancelResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransferBillsGetResult getBillsByOutBillNo(String outBillNo) throws WxPayException {
|
||||
String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/%s",
|
||||
this.payService.getPayBaseUrl(), outBillNo);
|
||||
String result = this.payService.getV3(url);
|
||||
return GSON.fromJson(result, TransferBillsGetResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransferBillsGetResult getBillsByTransferBillNo(String transferBillNo) throws WxPayException {
|
||||
String url = String.format("%s/v3/fund-app/mch-transfer/transfer-bills/transfer-bill-no/%s",
|
||||
this.payService.getPayBaseUrl(), transferBillNo);
|
||||
String result = this.payService.getV3(url);
|
||||
return GSON.fromJson(result, TransferBillsGetResult.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransferBillsNotifyResult parseTransferBillsNotifyResult(String notifyData, SignatureHeader header) throws WxPayException {
|
||||
return this.payService.baseParseOrderNotifyV3Result(notifyData, header, TransferBillsNotifyResult.class, TransferBillsNotifyResult.DecryptNotifyResult.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.github.binarywang.wxpay.service.impl;
|
||||
|
||||
import com.github.binarywang.wxpay.bean.WxPayApiData;
|
||||
import com.github.binarywang.wxpay.config.WxPayConfig;
|
||||
import com.github.binarywang.wxpay.exception.WxPayException;
|
||||
import com.github.binarywang.wxpay.v3.WxPayV3DownloadHttpGet;
|
||||
import com.google.gson.JsonElement;
|
||||
@@ -99,6 +100,8 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
|
||||
HttpPost httpPost = this.createHttpPost(url, requestStr);
|
||||
httpPost.addHeader(ACCEPT, APPLICATION_JSON);
|
||||
httpPost.addHeader(CONTENT_TYPE, APPLICATION_JSON);
|
||||
String serialNumber = getWechatpaySerial(getConfig());
|
||||
httpPost.addHeader("Wechatpay-Serial", serialNumber);
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||
//v3已经改为通过状态码判断200 204 成功
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
@@ -171,7 +174,7 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
|
||||
HttpPost httpPost = this.createHttpPost(url, requestStr);
|
||||
httpPost.addHeader(ACCEPT, APPLICATION_JSON);
|
||||
httpPost.addHeader(CONTENT_TYPE, APPLICATION_JSON);
|
||||
String serialNumber = getConfig().getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase();
|
||||
String serialNumber = getWechatpaySerial(getConfig());
|
||||
httpPost.addHeader("Wechatpay-Serial", serialNumber);
|
||||
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
|
||||
//v3已经改为通过状态码判断200 204 成功
|
||||
@@ -251,7 +254,7 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
|
||||
HttpGet httpGet = new HttpGet(url);
|
||||
httpGet.addHeader(ACCEPT, APPLICATION_JSON);
|
||||
httpGet.addHeader(CONTENT_TYPE, APPLICATION_JSON);
|
||||
String serialNumber = getConfig().getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase();
|
||||
String serialNumber = getWechatpaySerial(getConfig());
|
||||
httpGet.addHeader("Wechatpay-Serial", serialNumber);
|
||||
return this.requestV3(url, httpGet);
|
||||
}
|
||||
@@ -380,4 +383,15 @@ public class WxPayServiceApacheHttpImpl extends BaseWxPayServiceImpl {
|
||||
return wxPayException;
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容微信支付公钥模式
|
||||
* @param wxPayConfig
|
||||
* @return
|
||||
*/
|
||||
private String getWechatpaySerial(WxPayConfig wxPayConfig) {
|
||||
if (StringUtils.isNotBlank(wxPayConfig.getPublicKeyId())) {
|
||||
return wxPayConfig.getPublicKeyId();
|
||||
}
|
||||
return wxPayConfig.getVerifier().getValidCertificate().getSerialNumber().toString(16).toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ public class PublicCertificateVerifier implements Verifier{
|
||||
|
||||
private final PublicKey publicKey;
|
||||
|
||||
private Verifier certificateVerifier;
|
||||
|
||||
private final X509PublicCertificate publicCertificate;
|
||||
|
||||
public PublicCertificateVerifier(PublicKey publicKey, String publicId) {
|
||||
@@ -16,8 +18,15 @@ public class PublicCertificateVerifier implements Verifier{
|
||||
this.publicCertificate = new X509PublicCertificate(publicKey, publicId);
|
||||
}
|
||||
|
||||
public void setOtherVerifier(Verifier verifier) {
|
||||
this.certificateVerifier = verifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verify(String serialNumber, byte[] message, String signature) {
|
||||
if (!serialNumber.contains("PUB_KEY_ID") && this.certificateVerifier != null) {
|
||||
return this.certificateVerifier.verify(serialNumber, message, signature);
|
||||
}
|
||||
try {
|
||||
Signature sign = Signature.getInstance("SHA256withRSA");
|
||||
sign.initVerify(publicKey);
|
||||
|
||||
@@ -7,4 +7,6 @@ public interface Verifier {
|
||||
|
||||
|
||||
X509Certificate getValidCertificate();
|
||||
|
||||
default void setOtherVerifier(Verifier verifier) {};
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user