mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-03-10 00:13:40 +08:00
Compare commits
7 Commits
b89ff6a5af
...
5bb8b301c9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bb8b301c9 | ||
|
|
c19d46bdb8 | ||
|
|
60f7497b12 | ||
|
|
389f1785b6 | ||
|
|
8ef5a33dd5 | ||
|
|
3233384b17 | ||
|
|
5ff4114b6c |
5
.github/agents/my-agent.agent.md
vendored
5
.github/agents/my-agent.agent.md
vendored
@@ -10,5 +10,6 @@ description: 需要用中文,包括PR标题和分析总结过程
|
|||||||
|
|
||||||
# My Agent
|
# My Agent
|
||||||
|
|
||||||
1、请使用中文输出思考过程和总结,包括PR标题,提交commit信息也要使用中文;
|
- 1、请使用中文输出思考过程和总结,包括PR标题,提交commit信息也要使用中文;
|
||||||
2、生成代码时需要提供必要的单元测试代码。
|
- 2、生成代码时需要提供必要的单元测试代码;
|
||||||
|
- 3、新增加的代码如果标记作者信息,请注意不要把作者名设为binarywang或者其他无关人员,要改为 Github Copilot。
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ public class WxConsts {
|
|||||||
public static final String DEVICE_STATUS = "device_status";
|
public static final String DEVICE_STATUS = "device_status";
|
||||||
public static final String HARDWARE = "hardware";
|
public static final String HARDWARE = "hardware";
|
||||||
public static final String TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service";
|
public static final String TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service";
|
||||||
|
public static final String TRANSFER_BIZ_AI_IVR = "transfer_biz_ai_ivr";
|
||||||
public static final String UPDATE_TASKCARD = "update_taskcard";
|
public static final String UPDATE_TASKCARD = "update_taskcard";
|
||||||
public static final String UPDATE_BUTTON = "update_button";
|
public static final String UPDATE_BUTTON = "update_button";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package me.chanjar.weixin.common.util.xml;
|
||||||
|
|
||||||
|
import com.thoughtworks.xstream.converters.Converter;
|
||||||
|
import com.thoughtworks.xstream.converters.MarshallingContext;
|
||||||
|
import com.thoughtworks.xstream.converters.UnmarshallingContext;
|
||||||
|
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||||
|
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容两种格式的字符串列表转换器:
|
||||||
|
* <ul>
|
||||||
|
* <li>旧格式(4.8.0之前):<MemChangeList><![CDATA[id1,id2]]></MemChangeList></li>
|
||||||
|
* <li>新格式(4.8.0起):<MemChangeList><Item><![CDATA[id1]]></Item></MemChangeList></li>
|
||||||
|
* </ul>
|
||||||
|
* 解析结果统一为逗号分隔的字符串。
|
||||||
|
*/
|
||||||
|
public class XStreamCDataListConverter implements Converter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
|
||||||
|
if (source != null) {
|
||||||
|
writer.setValue("<![CDATA[" + source + "]]>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
|
||||||
|
if (reader.hasMoreChildren()) {
|
||||||
|
// 新格式:含有 <Item> 子元素
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
while (reader.hasMoreChildren()) {
|
||||||
|
reader.moveDown();
|
||||||
|
String value = reader.getValue();
|
||||||
|
if (value != null && !value.isEmpty()) {
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
sb.append(value);
|
||||||
|
}
|
||||||
|
reader.moveUp();
|
||||||
|
}
|
||||||
|
return sb.length() > 0 ? sb.toString() : null;
|
||||||
|
} else {
|
||||||
|
// 旧格式:直接 CDATA 文本
|
||||||
|
String value = reader.getValue();
|
||||||
|
return (value != null && !value.isEmpty()) ? value : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canConvert(Class type) {
|
||||||
|
return type == String.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package me.chanjar.weixin.cp.api;
|
||||||
|
|
||||||
|
import me.chanjar.weixin.common.error.WxErrorException;
|
||||||
|
import me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldData;
|
||||||
|
import me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldDataResp;
|
||||||
|
import me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldInfoResp;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人事助手相关接口.
|
||||||
|
* 官方文档:https://developer.work.weixin.qq.com/document/path/99132
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/leejoker">leejoker</a> created on 2024-01-01
|
||||||
|
*/
|
||||||
|
public interface WxCpHrService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取员工档案字段信息.
|
||||||
|
* <p>
|
||||||
|
* 请求方式:POST(HTTPS)
|
||||||
|
* 请求地址:https://qyapi.weixin.qq.com/cgi-bin/hr/employee/get_field_info?access_token=ACCESS_TOKEN
|
||||||
|
* 权限说明:
|
||||||
|
* 需要配置人事助手的secret,调用接口前需给对应成员赋予人事小助手应用的权限。
|
||||||
|
*
|
||||||
|
* @param fields 指定字段key列表,不填则返回全部字段
|
||||||
|
* @return 字段信息响应 wx cp hr employee field info resp
|
||||||
|
* @throws WxErrorException the wx error exception
|
||||||
|
*/
|
||||||
|
WxCpHrEmployeeFieldInfoResp getFieldInfo(List<String> fields) throws WxErrorException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取员工档案数据.
|
||||||
|
* <p>
|
||||||
|
* 请求方式:POST(HTTPS)
|
||||||
|
* 请求地址:https://qyapi.weixin.qq.com/cgi-bin/hr/employee/get_employee_field_info?access_token=ACCESS_TOKEN
|
||||||
|
* 权限说明:
|
||||||
|
* 需要配置人事助手的secret,调用接口前需给对应成员赋予人事小助手应用的权限。
|
||||||
|
*
|
||||||
|
* @param userids 员工userid列表,不超过20个
|
||||||
|
* @param fields 指定字段key列表,不填则返回全部字段
|
||||||
|
* @return 员工档案数据响应 wx cp hr employee field data resp
|
||||||
|
* @throws WxErrorException the wx error exception
|
||||||
|
*/
|
||||||
|
WxCpHrEmployeeFieldDataResp getEmployeeFieldInfo(List<String> userids, List<String> fields) throws WxErrorException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新员工档案数据.
|
||||||
|
* <p>
|
||||||
|
* 请求方式:POST(HTTPS)
|
||||||
|
* 请求地址:https://qyapi.weixin.qq.com/cgi-bin/hr/employee/update_employee_field_info?access_token=ACCESS_TOKEN
|
||||||
|
* 权限说明:
|
||||||
|
* 需要配置人事助手的secret,调用接口前需给对应成员赋予人事小助手应用的权限。
|
||||||
|
*
|
||||||
|
* @param userid 员工userid
|
||||||
|
* @param fieldList 字段数据列表
|
||||||
|
* @throws WxErrorException the wx error exception
|
||||||
|
*/
|
||||||
|
void updateEmployeeFieldInfo(String userid, List<WxCpHrEmployeeFieldData.FieldItem> fieldList) throws WxErrorException;
|
||||||
|
}
|
||||||
@@ -594,4 +594,11 @@ public interface WxCpService extends WxService {
|
|||||||
* @return 智能机器人服务 intelligent robot service
|
* @return 智能机器人服务 intelligent robot service
|
||||||
*/
|
*/
|
||||||
WxCpIntelligentRobotService getIntelligentRobotService();
|
WxCpIntelligentRobotService getIntelligentRobotService();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取人事助手服务
|
||||||
|
*
|
||||||
|
* @return 人事助手服务 hr service
|
||||||
|
*/
|
||||||
|
WxCpHrService getHrService();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
|
|||||||
private final WxCpMeetingService meetingService = new WxCpMeetingServiceImpl(this);
|
private final WxCpMeetingService meetingService = new WxCpMeetingServiceImpl(this);
|
||||||
private final WxCpCorpGroupService corpGroupService = new WxCpCorpGroupServiceImpl(this);
|
private final WxCpCorpGroupService corpGroupService = new WxCpCorpGroupServiceImpl(this);
|
||||||
private final WxCpIntelligentRobotService intelligentRobotService = new WxCpIntelligentRobotServiceImpl(this);
|
private final WxCpIntelligentRobotService intelligentRobotService = new WxCpIntelligentRobotServiceImpl(this);
|
||||||
|
private final WxCpHrService hrService = new WxCpHrServiceImpl(this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 全局的是否正在刷新access token的锁.
|
* 全局的是否正在刷新access token的锁.
|
||||||
@@ -708,4 +709,9 @@ public abstract class BaseWxCpServiceImpl<H, P> implements WxCpService, RequestH
|
|||||||
public WxCpIntelligentRobotService getIntelligentRobotService() {
|
public WxCpIntelligentRobotService getIntelligentRobotService() {
|
||||||
return this.intelligentRobotService;
|
return this.intelligentRobotService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxCpHrService getHrService() {
|
||||||
|
return this.hrService;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package me.chanjar.weixin.cp.api.impl;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import me.chanjar.weixin.common.error.WxErrorException;
|
||||||
|
import me.chanjar.weixin.cp.api.WxCpHrService;
|
||||||
|
import me.chanjar.weixin.cp.api.WxCpService;
|
||||||
|
import me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldData;
|
||||||
|
import me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldDataResp;
|
||||||
|
import me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldInfoResp;
|
||||||
|
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Hr.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人事助手相关接口实现类.
|
||||||
|
* 官方文档:https://developer.work.weixin.qq.com/document/path/99132
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/leejoker">leejoker</a> created on 2024-01-01
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class WxCpHrServiceImpl implements WxCpHrService {
|
||||||
|
|
||||||
|
private final WxCpService cpService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxCpHrEmployeeFieldInfoResp getFieldInfo(List<String> fields) throws WxErrorException {
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
if (fields != null && !fields.isEmpty()) {
|
||||||
|
jsonObject.add("fields", WxCpGsonBuilder.create().toJsonTree(fields));
|
||||||
|
}
|
||||||
|
String response = this.cpService.post(
|
||||||
|
this.cpService.getWxCpConfigStorage().getApiUrl(GET_FIELD_INFO),
|
||||||
|
jsonObject.toString()
|
||||||
|
);
|
||||||
|
return WxCpHrEmployeeFieldInfoResp.fromJson(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxCpHrEmployeeFieldDataResp getEmployeeFieldInfo(List<String> userids, List<String> fields) throws WxErrorException {
|
||||||
|
if (userids == null || userids.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("userids 不能为空");
|
||||||
|
}
|
||||||
|
if (userids.size() > 20) {
|
||||||
|
throw new IllegalArgumentException("userids 每次最多传入20个");
|
||||||
|
}
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
jsonObject.add("userids", WxCpGsonBuilder.create().toJsonTree(userids));
|
||||||
|
if (fields != null && !fields.isEmpty()) {
|
||||||
|
jsonObject.add("fields", WxCpGsonBuilder.create().toJsonTree(fields));
|
||||||
|
}
|
||||||
|
String response = this.cpService.post(
|
||||||
|
this.cpService.getWxCpConfigStorage().getApiUrl(GET_EMPLOYEE_FIELD_INFO),
|
||||||
|
jsonObject.toString()
|
||||||
|
);
|
||||||
|
return WxCpHrEmployeeFieldDataResp.fromJson(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateEmployeeFieldInfo(String userid, List<WxCpHrEmployeeFieldData.FieldItem> fieldList) throws WxErrorException {
|
||||||
|
if (userid == null || userid.trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("userid 不能为空");
|
||||||
|
}
|
||||||
|
if (fieldList == null || fieldList.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("fieldList 不能为空");
|
||||||
|
}
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
jsonObject.addProperty("userid", userid);
|
||||||
|
jsonObject.add("field_list", WxCpGsonBuilder.create().toJsonTree(fieldList));
|
||||||
|
this.cpService.post(
|
||||||
|
this.cpService.getWxCpConfigStorage().getApiUrl(UPDATE_EMPLOYEE_FIELD_INFO),
|
||||||
|
jsonObject.toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package me.chanjar.weixin.cp.bean.hr;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人事助手-员工档案数据(单个员工).
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/leejoker">leejoker</a> created on 2024-01-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class WxCpHrEmployeeFieldData implements Serializable {
|
||||||
|
private static final long serialVersionUID = 4593693598671765396L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工userid.
|
||||||
|
*/
|
||||||
|
@SerializedName("userid")
|
||||||
|
private String userid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段数据列表.
|
||||||
|
*/
|
||||||
|
@SerializedName("field_list")
|
||||||
|
private List<FieldItem> fieldList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段数据项.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class FieldItem implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段key.
|
||||||
|
*/
|
||||||
|
@SerializedName("field_key")
|
||||||
|
private String fieldKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段值.
|
||||||
|
*/
|
||||||
|
@SerializedName("field_value")
|
||||||
|
private WxCpHrEmployeeFieldValue fieldValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package me.chanjar.weixin.cp.bean.hr;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
|
||||||
|
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人事助手-获取员工档案数据响应.
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/leejoker">leejoker</a> created on 2024-01-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class WxCpHrEmployeeFieldDataResp extends WxCpBaseResp {
|
||||||
|
private static final long serialVersionUID = 6593693598671765396L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 员工档案数据列表.
|
||||||
|
*/
|
||||||
|
@SerializedName("employee_field_list")
|
||||||
|
private List<WxCpHrEmployeeFieldData> employeeFieldList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From json wx cp hr employee field data resp.
|
||||||
|
*
|
||||||
|
* @param json the json
|
||||||
|
* @return the wx cp hr employee field data resp
|
||||||
|
*/
|
||||||
|
public static WxCpHrEmployeeFieldDataResp fromJson(String json) {
|
||||||
|
return WxCpGsonBuilder.create().fromJson(json, WxCpHrEmployeeFieldDataResp.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package me.chanjar.weixin.cp.bean.hr;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人事助手-员工档案字段信息.
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/leejoker">leejoker</a> created on 2024-01-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class WxCpHrEmployeeFieldInfo implements Serializable {
|
||||||
|
private static final long serialVersionUID = 2593693598671765396L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段key.
|
||||||
|
*/
|
||||||
|
@SerializedName("field_key")
|
||||||
|
private String fieldKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段英文名称.
|
||||||
|
*/
|
||||||
|
@SerializedName("field_en_name")
|
||||||
|
private String fieldEnName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段中文名称.
|
||||||
|
*/
|
||||||
|
@SerializedName("field_zh_name")
|
||||||
|
private String fieldZhName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段类型.
|
||||||
|
* 具体取值参见 {@link WxCpHrFieldType}
|
||||||
|
*/
|
||||||
|
@SerializedName("field_type")
|
||||||
|
private Integer fieldType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取字段类型枚举.
|
||||||
|
*
|
||||||
|
* @return 字段类型枚举,未匹配时返回 null
|
||||||
|
*/
|
||||||
|
public WxCpHrFieldType getFieldTypeEnum() {
|
||||||
|
return fieldType == null ? null : WxCpHrFieldType.fromCode(fieldType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否系统字段.
|
||||||
|
* 0: 否
|
||||||
|
* 1: 是
|
||||||
|
*/
|
||||||
|
@SerializedName("is_sys")
|
||||||
|
private Integer isSys;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段详情.
|
||||||
|
*/
|
||||||
|
@SerializedName("field_detail")
|
||||||
|
private FieldDetail fieldDetail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段详情.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class FieldDetail implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选项列表(单选/多选字段专用).
|
||||||
|
*/
|
||||||
|
@SerializedName("option_list")
|
||||||
|
private List<Option> optionList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选项.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class Option implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选项key.
|
||||||
|
*/
|
||||||
|
@SerializedName("key")
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选项值.
|
||||||
|
*/
|
||||||
|
@SerializedName("value")
|
||||||
|
private String value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package me.chanjar.weixin.cp.bean.hr;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import me.chanjar.weixin.cp.bean.WxCpBaseResp;
|
||||||
|
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人事助手-获取员工档案字段信息响应.
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/leejoker">leejoker</a> created on 2024-01-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class WxCpHrEmployeeFieldInfoResp extends WxCpBaseResp {
|
||||||
|
private static final long serialVersionUID = 5593693598671765396L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字段信息列表.
|
||||||
|
*/
|
||||||
|
@SerializedName("field_info_list")
|
||||||
|
private List<WxCpHrEmployeeFieldInfo> fieldInfoList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From json wx cp hr employee field info resp.
|
||||||
|
*
|
||||||
|
* @param json the json
|
||||||
|
* @return the wx cp hr employee field info resp
|
||||||
|
*/
|
||||||
|
public static WxCpHrEmployeeFieldInfoResp fromJson(String json) {
|
||||||
|
return WxCpGsonBuilder.create().fromJson(json, WxCpHrEmployeeFieldInfoResp.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package me.chanjar.weixin.cp.bean.hr;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人事助手-员工档案字段值.
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/leejoker">leejoker</a> created on 2024-01-01
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class WxCpHrEmployeeFieldValue implements Serializable {
|
||||||
|
private static final long serialVersionUID = 3593693598671765396L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本/数字/手机/邮箱类型字段值.
|
||||||
|
*/
|
||||||
|
@SerializedName("text_value")
|
||||||
|
private String textValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单选类型字段值.
|
||||||
|
*/
|
||||||
|
@SerializedName("option_value")
|
||||||
|
private OptionValue optionValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多选类型字段值列表.
|
||||||
|
*/
|
||||||
|
@SerializedName("option_value_list")
|
||||||
|
private List<OptionValue> optionValueList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期类型字段值.
|
||||||
|
*/
|
||||||
|
@SerializedName("date_value")
|
||||||
|
private DateValue dateValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件类型字段值.
|
||||||
|
*/
|
||||||
|
@SerializedName("attachment_value")
|
||||||
|
private AttachmentValue attachmentValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单选/多选选项值.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class OptionValue implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选项key.
|
||||||
|
*/
|
||||||
|
@SerializedName("key")
|
||||||
|
private String key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期值.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class DateValue implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳(字符串格式).
|
||||||
|
*/
|
||||||
|
@SerializedName("timestamp")
|
||||||
|
private String timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件值.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class AttachmentValue implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 附件id列表.
|
||||||
|
*/
|
||||||
|
@SerializedName("id_list")
|
||||||
|
private List<String> idList;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package me.chanjar.weixin.cp.bean.hr;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人事助手-员工档案字段类型枚举.
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/leejoker">leejoker</a> created on 2024-01-01
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum WxCpHrFieldType {
|
||||||
|
/**
|
||||||
|
* 文本.
|
||||||
|
*/
|
||||||
|
TEXT("文本", 1),
|
||||||
|
/**
|
||||||
|
* 日期.
|
||||||
|
*/
|
||||||
|
DATE("日期", 2),
|
||||||
|
/**
|
||||||
|
* 数字.
|
||||||
|
*/
|
||||||
|
NUMBER("数字", 3),
|
||||||
|
/**
|
||||||
|
* 单选.
|
||||||
|
*/
|
||||||
|
SINGLE_SELECT("单选", 4),
|
||||||
|
/**
|
||||||
|
* 多选.
|
||||||
|
*/
|
||||||
|
MULTI_SELECT("多选", 5),
|
||||||
|
/**
|
||||||
|
* 附件.
|
||||||
|
*/
|
||||||
|
ATTACHMENT("附件", 6),
|
||||||
|
/**
|
||||||
|
* 手机.
|
||||||
|
*/
|
||||||
|
PHONE("手机", 7),
|
||||||
|
/**
|
||||||
|
* 邮箱.
|
||||||
|
*/
|
||||||
|
EMAIL("邮箱", 8);
|
||||||
|
|
||||||
|
private final String typeName;
|
||||||
|
private final int code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据数值获取字段类型枚举.
|
||||||
|
*
|
||||||
|
* @param code 字段类型数值
|
||||||
|
* @return 字段类型枚举,未匹配时返回 null
|
||||||
|
*/
|
||||||
|
public static WxCpHrFieldType fromCode(int code) {
|
||||||
|
for (WxCpHrFieldType type : WxCpHrFieldType.values()) {
|
||||||
|
if (type.code == code) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -67,6 +67,7 @@ public class WxCpKfMsgListResp extends WxCpBaseResp {
|
|||||||
private WxCpKfChannelsShopProductMsg channelsShopProduct;
|
private WxCpKfChannelsShopProductMsg channelsShopProduct;
|
||||||
@SerializedName("channels_shop_order")
|
@SerializedName("channels_shop_order")
|
||||||
private WxCpKfChannelsShopOrderMsg channelsShopOrder;
|
private WxCpKfChannelsShopOrderMsg channelsShopOrder;
|
||||||
|
private WxCpKfChannelsMsg channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package me.chanjar.weixin.cp.bean.kf.msg;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频号消息
|
||||||
|
*
|
||||||
|
* @author liuzhao created on 2024/2/25
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class WxCpKfChannelsMsg {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频号名称
|
||||||
|
*/
|
||||||
|
@SerializedName("nickname")
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频/直播标题
|
||||||
|
*/
|
||||||
|
@SerializedName("title")
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频/直播描述
|
||||||
|
*/
|
||||||
|
@SerializedName("desc")
|
||||||
|
private String desc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 封面图片url
|
||||||
|
*/
|
||||||
|
@SerializedName("cover_url")
|
||||||
|
private String coverUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频/直播链接
|
||||||
|
*/
|
||||||
|
@SerializedName("url")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频号账号名称
|
||||||
|
*/
|
||||||
|
@SerializedName("find_username")
|
||||||
|
private String findUsername;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import me.chanjar.weixin.common.util.XmlUtils;
|
|||||||
import me.chanjar.weixin.common.util.xml.IntegerArrayConverter;
|
import me.chanjar.weixin.common.util.xml.IntegerArrayConverter;
|
||||||
import me.chanjar.weixin.common.util.xml.LongArrayConverter;
|
import me.chanjar.weixin.common.util.xml.LongArrayConverter;
|
||||||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
|
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
|
||||||
|
import me.chanjar.weixin.common.util.xml.XStreamCDataListConverter;
|
||||||
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
import me.chanjar.weixin.cp.config.WxCpConfigStorage;
|
||||||
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
|
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
|
||||||
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
|
||||||
@@ -156,7 +157,7 @@ public class WxCpXmlMessage implements Serializable {
|
|||||||
private String memChangeCnt;
|
private String memChangeCnt;
|
||||||
|
|
||||||
@XStreamAlias("MemChangeList")
|
@XStreamAlias("MemChangeList")
|
||||||
@XStreamConverter(value = XStreamCDataConverter.class)
|
@XStreamConverter(value = XStreamCDataListConverter.class)
|
||||||
private String memChangeList;
|
private String memChangeList;
|
||||||
|
|
||||||
@XStreamAlias("LastMemVer")
|
@XStreamAlias("LastMemVer")
|
||||||
|
|||||||
@@ -1701,4 +1701,25 @@ public interface WxCpApiPathConsts {
|
|||||||
*/
|
*/
|
||||||
String SEND_MESSAGE = "/cgi-bin/intelligent_robot/send_message";
|
String SEND_MESSAGE = "/cgi-bin/intelligent_robot/send_message";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人事助手相关接口.
|
||||||
|
* 官方文档:https://developer.work.weixin.qq.com/document/path/99132
|
||||||
|
*/
|
||||||
|
interface Hr {
|
||||||
|
/**
|
||||||
|
* 获取员工档案字段信息.
|
||||||
|
*/
|
||||||
|
String GET_FIELD_INFO = "/cgi-bin/hr/employee/get_field_info";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取员工档案数据.
|
||||||
|
*/
|
||||||
|
String GET_EMPLOYEE_FIELD_INFO = "/cgi-bin/hr/employee/get_employee_field_info";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新员工档案数据.
|
||||||
|
*/
|
||||||
|
String UPDATE_EMPLOYEE_FIELD_INFO = "/cgi-bin/hr/employee/update_employee_field_info";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package me.chanjar.weixin.cp.api.impl;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import me.chanjar.weixin.common.error.WxErrorException;
|
||||||
|
import me.chanjar.weixin.cp.api.ApiTestModule;
|
||||||
|
import me.chanjar.weixin.cp.api.WxCpHrService;
|
||||||
|
import me.chanjar.weixin.cp.api.WxCpService;
|
||||||
|
import me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldData;
|
||||||
|
import me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldDataResp;
|
||||||
|
import me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldInfoResp;
|
||||||
|
import me.chanjar.weixin.cp.bean.hr.WxCpHrEmployeeFieldValue;
|
||||||
|
import org.testng.annotations.Guice;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 人事助手接口单元测试类.
|
||||||
|
*
|
||||||
|
* @author <a href="https://github.com/leejoker">leejoker</a> created on 2024-01-01
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Guice(modules = ApiTestModule.class)
|
||||||
|
public class WxCpHrServiceImplTest {
|
||||||
|
/**
|
||||||
|
* The Wx service.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
private WxCpService wxCpService;
|
||||||
|
/**
|
||||||
|
* The Config storage.
|
||||||
|
*/
|
||||||
|
@Inject
|
||||||
|
protected ApiTestModule.WxXmlCpInMemoryConfigStorage configStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试获取员工档案字段信息.
|
||||||
|
*
|
||||||
|
* @throws WxErrorException the wx error exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetFieldInfo() throws WxErrorException {
|
||||||
|
WxCpHrService hrService = this.wxCpService.getHrService();
|
||||||
|
// 获取所有字段信息
|
||||||
|
WxCpHrEmployeeFieldInfoResp resp = hrService.getFieldInfo(null);
|
||||||
|
assertThat(resp).isNotNull();
|
||||||
|
assertThat(resp.getFieldInfoList()).isNotNull();
|
||||||
|
log.info("获取所有字段信息: {}", resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试获取指定字段信息.
|
||||||
|
*
|
||||||
|
* @throws WxErrorException the wx error exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetFieldInfoWithFilter() throws WxErrorException {
|
||||||
|
WxCpHrService hrService = this.wxCpService.getHrService();
|
||||||
|
// 获取指定字段信息
|
||||||
|
WxCpHrEmployeeFieldInfoResp resp = hrService.getFieldInfo(Collections.singletonList("sys_field_name"));
|
||||||
|
assertThat(resp).isNotNull();
|
||||||
|
log.info("获取指定字段信息: {}", resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试获取员工档案数据.
|
||||||
|
*
|
||||||
|
* @throws WxErrorException the wx error exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetEmployeeFieldInfo() throws WxErrorException {
|
||||||
|
WxCpHrService hrService = this.wxCpService.getHrService();
|
||||||
|
WxCpHrEmployeeFieldDataResp resp = hrService.getEmployeeFieldInfo(
|
||||||
|
Collections.singletonList(this.configStorage.getUserId()), null);
|
||||||
|
assertThat(resp).isNotNull();
|
||||||
|
assertThat(resp.getEmployeeFieldList()).isNotNull();
|
||||||
|
log.info("获取员工档案数据: {}", resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试更新员工档案数据.
|
||||||
|
*
|
||||||
|
* @throws WxErrorException the wx error exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testUpdateEmployeeFieldInfo() throws WxErrorException {
|
||||||
|
WxCpHrService hrService = this.wxCpService.getHrService();
|
||||||
|
WxCpHrEmployeeFieldData.FieldItem fieldItem = new WxCpHrEmployeeFieldData.FieldItem();
|
||||||
|
fieldItem.setFieldKey("sys_field_name");
|
||||||
|
WxCpHrEmployeeFieldValue fieldValue = new WxCpHrEmployeeFieldValue();
|
||||||
|
fieldValue.setTextValue("测试姓名");
|
||||||
|
fieldItem.setFieldValue(fieldValue);
|
||||||
|
hrService.updateEmployeeFieldInfo(this.configStorage.getUserId(), Arrays.asList(fieldItem));
|
||||||
|
log.info("更新员工档案数据成功");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -570,5 +570,53 @@ public class WxCpXmlMessageTest {
|
|||||||
assertEquals(wxMessage3.getUpdateDetail(), "change_name");
|
assertEquals(wxMessage3.getUpdateDetail(), "change_name");
|
||||||
// 当XML中没有MemChangeList元素时,字段应该为null而不是空字符串
|
// 当XML中没有MemChangeList元素时,字段应该为null而不是空字符串
|
||||||
assertThat(wxMessage3.getMemChangeList()).isNull();
|
assertThat(wxMessage3.getMemChangeList()).isNull();
|
||||||
|
|
||||||
|
// 测试企业微信4.8.0新格式:MemChangeList使用<Item>子元素(加群场景)
|
||||||
|
String xmlNewFormatAddMember = "<xml>"
|
||||||
|
+ "<ToUserName><![CDATA[c2e112dad808119117371bbcd6]]></ToUserName>"
|
||||||
|
+ "<FromUserName><![CDATA[sys]]></FromUserName>"
|
||||||
|
+ "<CreateTime>9811170016713</CreateTime>"
|
||||||
|
+ "<MsgType><![CDATA[event]]></MsgType>"
|
||||||
|
+ "<Event><![CDATA[change_external_chat]]></Event>"
|
||||||
|
+ "<ChatId><![CDATA[wrxUBwDQAAa44T11Ziaed811rhUr8-3Igmug]]></ChatId>"
|
||||||
|
+ "<ChangeType><![CDATA[update]]></ChangeType>"
|
||||||
|
+ "<UpdateDetail><![CDATA[add_member]]></UpdateDetail>"
|
||||||
|
+ "<JoinScene>3</JoinScene>"
|
||||||
|
+ "<MemChangeCnt>1</MemChangeCnt>"
|
||||||
|
+ "<MemChangeList><Item><![CDATA[wmxUBwDQAAO-Hn5_wFJz4wvo5TxLFibw]]></Item></MemChangeList>"
|
||||||
|
+ "<LastMemVer><![CDATA[5807afd2ab75771d5e8ac623f534ac0b]]></LastMemVer>"
|
||||||
|
+ "<CurMemVer><![CDATA[ea36e8b6062b803cda0ee45e9418d637]]></CurMemVer>"
|
||||||
|
+ "</xml>";
|
||||||
|
WxCpXmlMessage wxMessage4 = WxCpXmlMessage.fromXml(xmlNewFormatAddMember);
|
||||||
|
assertEquals(wxMessage4.getEvent(), WxCpConsts.EventType.CHANGE_EXTERNAL_CHAT);
|
||||||
|
assertEquals(wxMessage4.getChangeType(), "update");
|
||||||
|
assertEquals(wxMessage4.getUpdateDetail(), "add_member");
|
||||||
|
assertEquals(wxMessage4.getJoinScene(), "3");
|
||||||
|
assertEquals(wxMessage4.getMemChangeCnt(), "1");
|
||||||
|
// 新格式:<Item>子元素中的成员ID应被正确解析
|
||||||
|
assertEquals(wxMessage4.getMemChangeList(), "wmxUBwDQAAO-Hn5_wFJz4wvo5TxLFibw");
|
||||||
|
|
||||||
|
// 测试企业微信4.8.0新格式:多个<Item>子元素(多成员变更)
|
||||||
|
String xmlNewFormatMultiMember = "<xml>"
|
||||||
|
+ "<ToUserName><![CDATA[toUser]]></ToUserName>"
|
||||||
|
+ "<FromUserName><![CDATA[sys]]></FromUserName>"
|
||||||
|
+ "<CreateTime>1403610513</CreateTime>"
|
||||||
|
+ "<MsgType><![CDATA[event]]></MsgType>"
|
||||||
|
+ "<Event><![CDATA[change_external_chat]]></Event>"
|
||||||
|
+ "<ChangeType><![CDATA[update]]></ChangeType>"
|
||||||
|
+ "<ChatId><![CDATA[wrOgQhDgAAMYQiS5ol9G7gK9JVAAAA]]></ChatId>"
|
||||||
|
+ "<UpdateDetail><![CDATA[del_member]]></UpdateDetail>"
|
||||||
|
+ "<QuitScene>1</QuitScene>"
|
||||||
|
+ "<MemChangeCnt>2</MemChangeCnt>"
|
||||||
|
+ "<MemChangeList>"
|
||||||
|
+ "<Item><![CDATA[wmEJiCwAAA9KG2qlSq6rKwASSgAAAA]]></Item>"
|
||||||
|
+ "<Item><![CDATA[wmEJiCwAAA9KG2qlSq6rKwBBBBBBB]]></Item>"
|
||||||
|
+ "</MemChangeList>"
|
||||||
|
+ "</xml>";
|
||||||
|
WxCpXmlMessage wxMessage5 = WxCpXmlMessage.fromXml(xmlNewFormatMultiMember);
|
||||||
|
assertEquals(wxMessage5.getUpdateDetail(), "del_member");
|
||||||
|
assertEquals(wxMessage5.getMemChangeCnt(), "2");
|
||||||
|
// 多个<Item>元素应被解析为逗号分隔字符串
|
||||||
|
assertEquals(wxMessage5.getMemChangeList(), "wmEJiCwAAA9KG2qlSq6rKwASSgAAAA,wmEJiCwAAA9KG2qlSq6rKwBBBBBBB");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import lombok.Data;
|
|||||||
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
|
import me.chanjar.weixin.common.util.xml.XStreamCDataConverter;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author borisbao
|
* @author borisbao
|
||||||
@@ -26,6 +27,18 @@ public class WxMaMediaAsyncCheckResult implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 综合结果
|
* 综合结果
|
||||||
*/
|
*/
|
||||||
|
@SerializedName("result")
|
||||||
|
private ResultBean result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详细检测结果列表
|
||||||
|
*/
|
||||||
|
@SerializedName("detail")
|
||||||
|
private List<DetailBean> detail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 综合结果内部类定义
|
||||||
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@XStreamAlias("result")
|
@XStreamAlias("result")
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package cn.binarywang.wx.miniapp.bean;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试多媒体内容安全异步检测结果解析
|
||||||
|
*
|
||||||
|
* @author copilot
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public class WxMaMediaAsyncCheckResultTest {
|
||||||
|
|
||||||
|
public void testFromJsonWithResultAndDetail() {
|
||||||
|
String json = "{\n"
|
||||||
|
+ " \"trace_id\": \"test_trace_id_001\",\n"
|
||||||
|
+ " \"result\": {\n"
|
||||||
|
+ " \"suggest\": \"risky\",\n"
|
||||||
|
+ " \"label\": 20001\n"
|
||||||
|
+ " },\n"
|
||||||
|
+ " \"detail\": [\n"
|
||||||
|
+ " {\n"
|
||||||
|
+ " \"strategy\": \"content_model\",\n"
|
||||||
|
+ " \"errcode\": 0,\n"
|
||||||
|
+ " \"suggest\": \"risky\",\n"
|
||||||
|
+ " \"label\": 20006,\n"
|
||||||
|
+ " \"prob\": 90\n"
|
||||||
|
+ " }\n"
|
||||||
|
+ " ]\n"
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
WxMaMediaAsyncCheckResult result = WxMaMediaAsyncCheckResult.fromJson(json);
|
||||||
|
|
||||||
|
assertNotNull(result);
|
||||||
|
assertEquals(result.getTraceId(), "test_trace_id_001");
|
||||||
|
|
||||||
|
assertNotNull(result.getResult());
|
||||||
|
assertEquals(result.getResult().getSuggest(), "risky");
|
||||||
|
assertEquals(result.getResult().getLabel(), "20001");
|
||||||
|
|
||||||
|
assertNotNull(result.getDetail());
|
||||||
|
assertEquals(result.getDetail().size(), 1);
|
||||||
|
WxMaMediaAsyncCheckResult.DetailBean detail = result.getDetail().get(0);
|
||||||
|
assertEquals(detail.getStrategy(), "content_model");
|
||||||
|
assertEquals(detail.getErrcode(), Integer.valueOf(0));
|
||||||
|
assertEquals(detail.getSuggest(), "risky");
|
||||||
|
assertEquals(detail.getLabel(), "20006");
|
||||||
|
assertEquals(detail.getProb(), Integer.valueOf(90));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -131,6 +131,15 @@ public abstract class WxMpXmlOutMessage implements Serializable {
|
|||||||
return new TransferCustomerServiceBuilder();
|
return new TransferCustomerServiceBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得转接AI回复消息builder
|
||||||
|
*
|
||||||
|
* @return 转接AI回复消息构建器
|
||||||
|
*/
|
||||||
|
public static TransferBizAiIvrBuilder TRANSFER_BIZ_AI_IVR() {
|
||||||
|
return new TransferBizAiIvrBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得设备消息builder
|
* 获得设备消息builder
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package me.chanjar.weixin.mp.bean.message;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
||||||
|
import com.thoughtworks.xstream.annotations.XStreamAlias;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import me.chanjar.weixin.common.api.WxConsts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转接AI回复消息.
|
||||||
|
* <pre>
|
||||||
|
* 当用户发送消息给公众号时,公众号开发者服务器回复如下内容,会触发微信公众平台的AI回复。
|
||||||
|
* 注意:需要公众号在微信公众平台上已开启AI回复功能,并且AI已学习完毕历史发表文章。
|
||||||
|
* 官方文档:https://developers.weixin.qq.com/doc/subscription/guide/product/message/Passive_user_reply_message.html
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author copilot
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@XStreamAlias("xml")
|
||||||
|
@JacksonXmlRootElement(localName = "xml")
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class WxMpXmlOutTransferBizAiIvrMessage extends WxMpXmlOutMessage {
|
||||||
|
private static final long serialVersionUID = 8275281170988017563L;
|
||||||
|
|
||||||
|
public WxMpXmlOutTransferBizAiIvrMessage() {
|
||||||
|
this.msgType = WxConsts.XmlMsgType.TRANSFER_BIZ_AI_IVR;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package me.chanjar.weixin.mp.builder.outxml;
|
||||||
|
|
||||||
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTransferBizAiIvrMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转接AI回复消息builder.
|
||||||
|
* <pre>
|
||||||
|
* 用法: WxMpXmlOutTransferBizAiIvrMessage m = WxMpXmlOutMessage.TRANSFER_BIZ_AI_IVR().toUser("").fromUser("").build();
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author copilot
|
||||||
|
*/
|
||||||
|
public final class TransferBizAiIvrBuilder
|
||||||
|
extends BaseBuilder<TransferBizAiIvrBuilder, WxMpXmlOutTransferBizAiIvrMessage> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMpXmlOutTransferBizAiIvrMessage build() {
|
||||||
|
WxMpXmlOutTransferBizAiIvrMessage m = new WxMpXmlOutTransferBizAiIvrMessage();
|
||||||
|
setCommon(m);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMusicMessage;
|
|||||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutNewsMessage;
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutNewsMessage;
|
||||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTextMessage;
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTextMessage;
|
||||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTransferKefuMessage;
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTransferKefuMessage;
|
||||||
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTransferBizAiIvrMessage;
|
||||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutVideoMessage;
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutVideoMessage;
|
||||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutVoiceMessage;
|
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutVoiceMessage;
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ public class XStreamTransformer {
|
|||||||
registerClass(WxMpXmlOutVideoMessage.class);
|
registerClass(WxMpXmlOutVideoMessage.class);
|
||||||
registerClass(WxMpXmlOutVoiceMessage.class);
|
registerClass(WxMpXmlOutVoiceMessage.class);
|
||||||
registerClass(WxMpXmlOutTransferKefuMessage.class);
|
registerClass(WxMpXmlOutTransferKefuMessage.class);
|
||||||
|
registerClass(WxMpXmlOutTransferBizAiIvrMessage.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package me.chanjar.weixin.mp.bean.message;
|
||||||
|
|
||||||
|
import org.testng.Assert;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转接AI回复消息测试.
|
||||||
|
*
|
||||||
|
* @author copilot
|
||||||
|
*/
|
||||||
|
public class WxMpXmlOutTransferBizAiIvrMessageTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
WxMpXmlOutTransferBizAiIvrMessage m = new WxMpXmlOutTransferBizAiIvrMessage();
|
||||||
|
m.setCreateTime(1399197672L);
|
||||||
|
m.setFromUserName("fromuser");
|
||||||
|
m.setToUserName("touser");
|
||||||
|
|
||||||
|
String expected = "<xml>" +
|
||||||
|
"<ToUserName><![CDATA[touser]]></ToUserName>" +
|
||||||
|
"<FromUserName><![CDATA[fromuser]]></FromUserName>" +
|
||||||
|
"<CreateTime>1399197672</CreateTime>" +
|
||||||
|
"<MsgType><![CDATA[transfer_biz_ai_ivr]]></MsgType>" +
|
||||||
|
"</xml>";
|
||||||
|
System.out.println(m.toXml());
|
||||||
|
Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBuild() {
|
||||||
|
WxMpXmlOutTransferBizAiIvrMessage m = WxMpXmlOutMessage.TRANSFER_BIZ_AI_IVR()
|
||||||
|
.fromUser("fromuser").toUser("touser").build();
|
||||||
|
m.setCreateTime(1399197672L);
|
||||||
|
String expected = "<xml>" +
|
||||||
|
"<ToUserName><![CDATA[touser]]></ToUserName>" +
|
||||||
|
"<FromUserName><![CDATA[fromuser]]></FromUserName>" +
|
||||||
|
"<CreateTime>1399197672</CreateTime>" +
|
||||||
|
"<MsgType><![CDATA[transfer_biz_ai_ivr]]></MsgType>" +
|
||||||
|
"</xml>";
|
||||||
|
System.out.println(m.toXml());
|
||||||
|
Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -99,6 +99,260 @@ public class MiPayNotifyV3Result implements Serializable, WxPayBaseNotifyV3Resul
|
|||||||
@SerializedName(value = "mix_trade_no")
|
@SerializedName(value = "mix_trade_no")
|
||||||
private String mixTradeNo;
|
private String mixTradeNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:医保自费混合订单支付状态
|
||||||
|
* 变量名:mix_pay_status
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string
|
||||||
|
* 描述:
|
||||||
|
* 医保自费混合订单支付状态,枚举值:
|
||||||
|
* UNKNOWN_MIX_PAY_STATUS:未知类型,需报错
|
||||||
|
* MIX_PAY_CREATED:等待支付
|
||||||
|
* MIX_PAY_SUCCESS:支付成功
|
||||||
|
* MIX_PAY_REFUND:自费和医保均已退款
|
||||||
|
* MIX_PAY_FAIL:支付失败
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "mix_pay_status")
|
||||||
|
private String mixPayStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:自费部分的支付状态
|
||||||
|
* 变量名:self_pay_status
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string
|
||||||
|
* 描述:
|
||||||
|
* 混合订单中自费部分的支付状态,枚举值:
|
||||||
|
* UNKNOWN_SELF_PAY_STATUS:未知类型,需报错
|
||||||
|
* SELF_PAY_CREATED:等待支付
|
||||||
|
* SELF_PAY_SUCCESS:支付成功
|
||||||
|
* SELF_PAY_REFUND:已退款
|
||||||
|
* SELF_PAY_FAIL:支付失败
|
||||||
|
* NO_SELF_PAY:没有自费
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "self_pay_status")
|
||||||
|
private String selfPayStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:医保部分的支付状态
|
||||||
|
* 变量名:med_ins_pay_status
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string
|
||||||
|
* 描述:
|
||||||
|
* 混合订单中医保部分的支付状态,枚举值:
|
||||||
|
* UNKNOWN_MED_INS_PAY_STATUS:未知类型,需报错
|
||||||
|
* MED_INS_PAY_CREATED:等待支付
|
||||||
|
* MED_INS_PAY_SUCCESS:支付成功
|
||||||
|
* MED_INS_PAY_REFUND:已退款
|
||||||
|
* MED_INS_PAY_FAIL:支付失败
|
||||||
|
* NO_MED_INS_PAY:没有医保
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "med_ins_pay_status")
|
||||||
|
private String medInsPayStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:订单支付时间
|
||||||
|
* 变量名:paid_time
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(64)
|
||||||
|
* 描述:
|
||||||
|
* 订单支付时间,遵循rfc3339标准格式
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "paid_time")
|
||||||
|
private String paidTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:医保局返回内容
|
||||||
|
* 变量名:passthrough_response_content
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(2048)
|
||||||
|
* 描述:
|
||||||
|
* 支付完成后医保局返回内容(透传给医疗机构)
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "passthrough_response_content")
|
||||||
|
private String passthroughResponseContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:混合支付类型
|
||||||
|
* 变量名:mix_pay_type
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string
|
||||||
|
* 描述:
|
||||||
|
* 混合支付类型,枚举值:
|
||||||
|
* UNKNOWN_MIX_PAY_TYPE:未知类型,需报错
|
||||||
|
* CASH_ONLY:纯自费
|
||||||
|
* INSURANCE_ONLY:纯医保
|
||||||
|
* CASH_AND_INSURANCE:医保自费混合
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "mix_pay_type")
|
||||||
|
private String mixPayType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:订单类型
|
||||||
|
* 变量名:order_type
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string
|
||||||
|
* 描述:
|
||||||
|
* 订单类型,枚举值:
|
||||||
|
* UNKNOWN_ORDER_TYPE:未知类型,需报错
|
||||||
|
* REG_PAY:挂号支付
|
||||||
|
* DIAG_PAY:诊间支付
|
||||||
|
* COVID_EXAM_PAY:新冠检测费用(核酸)
|
||||||
|
* IN_HOSP_PAY:住院费支付
|
||||||
|
* PHARMACY_PAY:药店支付
|
||||||
|
* INSURANCE_PAY:保险费支付
|
||||||
|
* INT_REG_PAY:互联网医院挂号支付
|
||||||
|
* INT_RE_DIAG_PAY:互联网医院复诊支付
|
||||||
|
* INT_RX_PAY:互联网医院处方支付
|
||||||
|
* COVID_ANTIGEN_PAY:新冠抗原检测
|
||||||
|
* MED_PAY:药费支付
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "order_type")
|
||||||
|
private String orderType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:用户标识
|
||||||
|
* 变量名:openid
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(128)
|
||||||
|
* 描述:
|
||||||
|
* 用户在appid下的唯一标识
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "openid")
|
||||||
|
private String openid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:用户子标识
|
||||||
|
* 变量名:sub_openid
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(128)
|
||||||
|
* 描述:
|
||||||
|
* 用户在sub_appid下的唯一标识
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "sub_openid")
|
||||||
|
private String subOpenid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:是否代亲属支付
|
||||||
|
* 变量名:pay_for_relatives
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:bool
|
||||||
|
* 描述:
|
||||||
|
* 是否代亲属支付,不传默认替本人支付
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "pay_for_relatives")
|
||||||
|
private Boolean payForRelatives;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:医疗机构订单号
|
||||||
|
* 变量名:serial_no
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(20)
|
||||||
|
* 描述:
|
||||||
|
* 医疗机构订单号
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "serial_no")
|
||||||
|
private String serialNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:医保局支付单ID
|
||||||
|
* 变量名:pay_order_id
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(64)
|
||||||
|
* 描述:
|
||||||
|
* 医保局返回的支付单ID
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "pay_order_id")
|
||||||
|
private String payOrderId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:医保局支付授权码
|
||||||
|
* 变量名:pay_auth_no
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(40)
|
||||||
|
* 描述:
|
||||||
|
* 医保局返回的支付授权码
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "pay_auth_no")
|
||||||
|
private String payAuthNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:用户定位信息
|
||||||
|
* 变量名:geo_location
|
||||||
|
* 是否必填:否
|
||||||
|
* 类型:string(40)
|
||||||
|
* 描述:
|
||||||
|
* 用户定位信息,经纬度。格式:经度,纬度
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "geo_location")
|
||||||
|
private String geoLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:城市ID
|
||||||
|
* 变量名:city_id
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string(8)
|
||||||
|
* 描述:
|
||||||
|
* 城市ID
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "city_id")
|
||||||
|
private String cityId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:医疗机构名称
|
||||||
|
* 变量名:med_inst_name
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string(128)
|
||||||
|
* 描述:
|
||||||
|
* 医疗机构名称
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "med_inst_name")
|
||||||
|
private String medInstName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* 字段名:医疗机构编码
|
||||||
|
* 变量名:med_inst_no
|
||||||
|
* 是否必填:是
|
||||||
|
* 类型:string(32)
|
||||||
|
* 描述:
|
||||||
|
* 医疗机构编码
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@SerializedName(value = "med_inst_no")
|
||||||
|
private String medInstNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
* 字段名:微信支付订单号
|
* 字段名:微信支付订单号
|
||||||
|
|||||||
Reference in New Issue
Block a user