🆕 #1641 企业微信增加OA提交审批申请的接口

This commit is contained in:
Binary Wang 2020-07-18 22:51:26 +08:00
parent 3b8c66a7e1
commit f6f4b89fc0
13 changed files with 352 additions and 50 deletions

View File

@ -1069,10 +1069,26 @@ public enum WxCpErrorMsgEnum {
* 获取打卡记录时间间隔超限保证开始时间大于0 且结束时间大于 0 且结束时间大于开始时间且间隔少于93天.
*/
CODE_301024(301024, "获取打卡记录时间间隔超限保证开始时间大于0 且结束时间大于 0 且结束时间大于开始时间且间隔少于93天"),
/**
* 提交审批单请求参数错误
*/
CODE_301025(301025,"提交审批单请求参数错误"),
/**
* 不允许更新该用户的userid.
*/
CODE_301036(301036, "不允许更新该用户的userid"),
/**
* 无审批应用权限,或者提单者不在审批应用/自建应用的可见范围
*/
CODE_301055(301055,"无审批应用权限,或者提单者不在审批应用/自建应用的可见范围"),
/**
* 审批应用已停用
*/
CODE_301056(301056,"审批应用已停用"),
/**
* 通用错误码提交审批单内部接口失败
*/
CODE_301057(301057,"通用错误码,提交审批单内部接口失败"),
/**
* 批量导入任务的文件中userid有重复.
*/

View File

@ -15,6 +15,22 @@ import java.util.List;
*/
public interface WxCpOaService {
/**
* <pre>提交审批申请
* 调试工具
* 企业可通过审批应用或自建应用Secret调用本接口代应用可见范围内员工在企业微信审批应用内提交指定类型的审批申请
*
* 请求方式POSTHTTPS
* 请求地址 https://qyapi.weixin.qq.com/cgi-bin/oa/applyevent?access_token=ACCESS_TOKEN
* 文档地址https://work.weixin.qq.com/api/doc/90000/90135/91853
* </pre>
*
* @param request 请求
* @return 表单提交成功后返回的表单编号
* @throws WxErrorException .
*/
String apply(WxCpOaApplyEventRequest request) throws WxErrorException;
/**
* <pre>
* 获取打卡数据
@ -40,7 +56,7 @@ public interface WxCpOaService {
* @param datetime 需要获取规则的当天日期
* @param userIdList 需要获取打卡规则的用户列表
* @return 打卡规则列表
* @throws WxErrorException
* @throws WxErrorException .
*/
List<WxCpCheckinOption> getCheckinOption(Date datetime, List<String> userIdList) throws WxErrorException;
@ -63,7 +79,7 @@ public interface WxCpOaService {
* @param size 一次请求拉取审批单数量默认值为100上限值为100
* @param filters 筛选条件可对批量拉取的审批申请设置约束条件支持设置多个条件,nullable
* @return WxCpApprovalInfo
* @throws WxErrorException
* @throws WxErrorException .
*/
WxCpApprovalInfo getApprovalInfo(@NonNull Date startTime, @NonNull Date endTime, Integer cursor, Integer size,
List<WxCpApprovalInfoQueryFilter> filters) throws WxErrorException;
@ -74,7 +90,7 @@ public interface WxCpOaService {
* @param startTime 开始时间
* @param endTime 结束时间
* @return WxCpApprovalInfo
* @throws WxErrorException
* @throws WxErrorException .
* @see me.chanjar.weixin.cp.api.WxCpOaService#getApprovalInfo
*/
WxCpApprovalInfo getApprovalInfo(@NonNull Date startTime, @NonNull Date endTime) throws WxErrorException;
@ -90,7 +106,7 @@ public interface WxCpOaService {
*
* @param spNo 审批单编号
* @return WxCpApprovaldetail
* @throws WxErrorException
* @throws WxErrorException .
*/
WxCpApprovalDetailResult getApprovalDetail(@NonNull String spNo) throws WxErrorException;
@ -104,7 +120,7 @@ public interface WxCpOaService {
* @param startTime 获取审批记录的开始时间
* @param endTime 获取审批记录的结束时间
* @param nextSpnum 第一个拉取的审批单号不填从该时间段的第一个审批单拉取
* @throws WxErrorException
* @throws WxErrorException .
* @see me.chanjar.weixin.cp.api.WxCpOaService#getApprovalInfo
* @see me.chanjar.weixin.cp.api.WxCpOaService#getApprovalDetail
*/
@ -118,18 +134,19 @@ public interface WxCpOaService {
* @param endTime 查询的结束时间戳
* @param offset 分页查询的偏移量
* @param limit 分页查询的每页大小,默认为100条如该参数大于100则按100处理
* @return
* @throws WxErrorException
* @return .
* @throws WxErrorException .
*/
List<WxCpDialRecord> getDialRecord(Date startTime, Date endTime, Integer offset,
Integer limit) throws WxErrorException;
/**
* 获取审批模板详情
*
* @param templateId 模板ID
* @return
* @throws WxErrorException
* @return .
* @throws WxErrorException .
*/
WxCpTemplateResult getTemplateDetail(@NonNull String templateId)throws WxErrorException;
WxCpTemplateResult getTemplateDetail(@NonNull String templateId) throws WxErrorException;
}

View File

@ -31,6 +31,13 @@ public class WxCpOaServiceImpl implements WxCpOaService {
private static final int MONTH_SECONDS = 30 * 24 * 60 * 60;
private static final int USER_IDS_LIMIT = 100;
@Override
public String apply(WxCpOaApplyEventRequest request) throws WxErrorException {
String responseContent = this.mainService.post(this.mainService.getWxCpConfigStorage().getApiUrl(APPLY_EVENT),
request.toJson());
return GsonParser.parse(responseContent).get("sp_no").getAsString();
}
@Override
public List<WxCpCheckinData> getCheckinData(Integer openCheckinDataType, Date startTime, Date endTime,
List<String> userIdList) throws WxErrorException {
@ -42,10 +49,10 @@ public class WxCpOaServiceImpl implements WxCpOaService {
throw new RuntimeException("用户列表不能为空,不超过 " + USER_IDS_LIMIT + " 个,若用户超过 " + USER_IDS_LIMIT + " 个,请分批获取");
}
long endtimestamp = endTime.getTime() / 1000L;
long starttimestamp = startTime.getTime() / 1000L;
long endTimestamp = endTime.getTime() / 1000L;
long startTimestamp = startTime.getTime() / 1000L;
if (endtimestamp - starttimestamp < 0 || endtimestamp - starttimestamp >= MONTH_SECONDS) {
if (endTimestamp - startTimestamp < 0 || endTimestamp - startTimestamp >= MONTH_SECONDS) {
throw new RuntimeException("获取记录时间跨度不超过一个月");
}
@ -53,8 +60,8 @@ public class WxCpOaServiceImpl implements WxCpOaService {
JsonArray jsonArray = new JsonArray();
jsonObject.addProperty("opencheckindatatype", openCheckinDataType);
jsonObject.addProperty("starttime", starttimestamp);
jsonObject.addProperty("endtime", endtimestamp);
jsonObject.addProperty("starttime", startTimestamp);
jsonObject.addProperty("endtime", endTimestamp);
for (String userid : userIdList) {
jsonArray.add(userid);
@ -213,9 +220,9 @@ public class WxCpOaServiceImpl implements WxCpOaService {
@Override
public WxCpTemplateResult getTemplateDetail(@NonNull String templateId) throws WxErrorException {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("template_id",templateId);
jsonObject.addProperty("template_id", templateId);
final String url = this.mainService.getWxCpConfigStorage().getApiUrl(GET_TEMPLATE_DETAIL);
String responseContent = this.mainService.post(url, jsonObject.toString());
return WxCpGsonBuilder.create().fromJson(responseContent,WxCpTemplateResult.class);
return WxCpGsonBuilder.create().fromJson(responseContent, WxCpTemplateResult.class);
}
}

View File

@ -0,0 +1,41 @@
package me.chanjar.weixin.cp.bean.oa;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.experimental.Accessors;
import me.chanjar.weixin.cp.bean.oa.WxCpOaApplyEventRequest;
import java.io.Serializable;
import java.util.List;
/**
* 摘要行信息用于定义某一行摘要显示的内容.
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
* @date 2020-07-19
*/
@Data
@Accessors(chain = true)
public class SummaryInfo implements Serializable {
private static final long serialVersionUID = 8262265774851382414L;
/**
* 摘要行信息用于定义某一行摘要显示的内容
*/
@SerializedName("summary_info")
private List<SummaryInfoData> summaryInfoData;
@Data
@Accessors(chain = true)
public static class SummaryInfoData implements Serializable {
private static final long serialVersionUID = 5314161929610113856L;
/**
* 摘要行显示文字用于记录列表和消息通知的显示不要超过20个字符
*/
private String text;
/**
* 摘要行显示语言
*/
private String lang;
}
}

View File

@ -10,7 +10,7 @@ import java.io.Serializable;
* @author element
*/
@Data
public class WxCpApprovalApplyer extends WxCpOperator implements Serializable {
public class WxCpApprovalApplier extends WxCpOperator implements Serializable {
private static final long serialVersionUID = -8974662568286821271L;

View File

@ -1,7 +1,7 @@
package me.chanjar.weixin.cp.bean.oa;
import lombok.Data;
import me.chanjar.weixin.cp.bean.oa.applydata.Content;
import me.chanjar.weixin.cp.bean.oa.applydata.ApplyDataContent;
import java.io.Serializable;
import java.util.List;
@ -16,6 +16,6 @@ public class WxCpApprovalApplyData implements Serializable {
private static final long serialVersionUID = 4061352949894274704L;
private List<Content> contents;
private List<ApplyDataContent> contents;
}

View File

@ -49,7 +49,7 @@ public class WxCpApprovalDetail implements Serializable {
* 申请人信息
*/
@SerializedName("applyer")
private WxCpApprovalApplyer applier;
private WxCpApprovalApplier applier;
/**
* 审批流程信息可能有多个审批节点

View File

@ -0,0 +1,105 @@
package me.chanjar.weixin.cp.bean.oa;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.experimental.Accessors;
import me.chanjar.weixin.cp.bean.oa.applydata.ApplyDataContent;
import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder;
import java.io.Serializable;
import java.util.List;
/**
* 提交审批申请 请求对象类.
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
* @date 2020-07-18
*/
@Data
@Accessors(chain = true)
public class WxCpOaApplyEventRequest implements Serializable {
private static final long serialVersionUID = 3362660678938569341L;
/**
* 申请人userid此审批申请将以此员工身份提交申请人需在应用可见范围内
*/
@SerializedName("creator_userid")
private String creatorUserId;
/**
* 模板id可在获取审批申请详情审批状态变化回调通知中获得也可在审批模板的模板编辑页面链接中获得暂不支持通过接口提交[打卡补卡][调班]模板审批单
*/
@SerializedName("template_id")
private String templateId;
/**
* 审批人模式0-通过接口指定审批人抄送人此时approvernotifyer等参数可用; 1-使用此模板在管理后台设置的审批流程支持条件审批默认为0
*/
@SerializedName("use_template_approver")
private Integer useTemplateApprover;
/**
* 审批流程信息用于指定审批申请的审批流程支持单人审批多人会签多人或签可能有多个审批节点仅use_template_approver为0时生效
*/
@SerializedName("approver")
private List<Approver> approvers;
/**
* 抄送人节点userid列表仅use_template_approver为0时生效
*/
@SerializedName("notifyer")
private String[] notifiers;
/**
* 抄送方式1-提单时抄送默认值 2-单据通过后抄送3-提单和单据通过后抄送仅use_template_approver为0时生效
*/
@SerializedName("notify_type")
private Integer notifyType;
/**
* 审批申请数据可定义审批申请中各个控件的值其中必填项必须有值选填项可为空数据结构同获取审批申请详情接口返回值中同名参数apply_data
*/
@SerializedName("apply_data")
private ApplyData applyData;
/**
* 摘要信息用于显示在审批通知卡片审批列表的摘要信息最多3行
*/
@SerializedName("summary_list")
private List<SummaryInfo> summaryList;
public String toJson() {
return WxCpGsonBuilder.create().toJson(this);
}
@Data
@Accessors(chain = true)
public static class Approver implements Serializable {
private static final long serialVersionUID = 7625206971546930988L;
/**
* 节点审批方式1-或签2-会签仅在节点为多人审批时有效
*/
private Integer attr;
/**
* 审批节点审批人userid列表若为多人会签多人或签需填写每个人的userid
*/
@SerializedName("userid")
private String[] userIds;
}
@Data
@Accessors(chain = true)
public static class ApplyData implements Serializable {
private static final long serialVersionUID = -2462732405265306981L;
/**
* 审批申请数据可定义审批申请中各个控件的值其中必填项必须有值选填项可为空
* 数据结构同获取审批申请详情接口返回值中同名参数apply_data
*/
@SerializedName("contents")
private List<ApplyDataContent> contents;
}
}

View File

@ -0,0 +1,35 @@
package me.chanjar.weixin.cp.bean.oa.applydata;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* @author element
*/
@Data
@Accessors(chain = true)
public class ApplyDataContent implements Serializable {
private static final long serialVersionUID = 8456821731930526935L;
/**
* 控件类型Text-文本Textarea-多行文本Number-数字Money-金额Date-日期/日期+时间
* Selector-单选/多选Contact-成员/部门Tips-说明文字File-附件Table-明细
*/
private String control;
/**
* 控件id控件的唯一id可通过获取审批模板详情接口获取
*/
private String id;
@SerializedName("title")
private List<ContentTitle> titles;
/**
* 控件值 需在此为申请人在各个控件中填写内容不同控件有不同的赋值参数具体说明详见附录模板配置的控件属性为必填时对应value值需要有值
*/
private ContentValue value;
}

View File

@ -1,24 +0,0 @@
package me.chanjar.weixin.cp.bean.oa.applydata;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @author element
*/
@Data
public class Content implements Serializable {
private static final long serialVersionUID = 8456821731930526935L;
private String control;
private String id;
@SerializedName("title")
private List<ContentTitle> titles;
private ContentValue value;
}

View File

@ -2,6 +2,7 @@ package me.chanjar.weixin.cp.bean.oa.applydata;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
@ -10,6 +11,7 @@ import java.util.List;
* @author element
*/
@Data
@Accessors(chain = true)
public class ContentValue implements Serializable {
private static final long serialVersionUID = -5607678965965065261L;
@ -90,7 +92,7 @@ public class ContentValue implements Serializable {
@Data
public static class Child implements Serializable {
private static final long serialVersionUID = -3500102073821161558L;
private List<Content> list;
private List<ApplyDataContent> list;
}
@ -115,5 +117,4 @@ public class ContentValue implements Serializable {
}
}

View File

@ -81,12 +81,24 @@ public class WxCpOaServiceImplTest {
}
@Test
public void testGetTemplateDetail() throws WxErrorException{
String templateId="3TkZjxugodbqpEMk9j7X6h6zKqYkc7MxQrrFmT7H";
WxCpTemplateResult result=wxService.getOAService().getTemplateDetail(templateId);
public void testGetTemplateDetail() throws WxErrorException {
String templateId = "3TkZjxugodbqpEMk9j7X6h6zKqYkc7MxQrrFmT7H";
WxCpTemplateResult result = wxService.getOAService().getTemplateDetail(templateId);
assertThat(result).isNotNull();
System.out.println("result ");
System.out.println(gson.toJson(result));
}
@Test
public void testApply() throws WxErrorException {
this.wxService.getOAService().apply(new WxCpOaApplyEventRequest().setCreatorUserId("123"));
}
@Test
public void testGetApprovalData() {
}
@Test
public void testGetDialRecord() {
}
}

View File

@ -0,0 +1,92 @@
package me.chanjar.weixin.cp.bean.oa;
import me.chanjar.weixin.common.util.json.GsonParser;
import me.chanjar.weixin.cp.bean.oa.applydata.ApplyDataContent;
import me.chanjar.weixin.cp.bean.oa.applydata.ContentValue;
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/binarywang">Binary Wang</a>
* @date 2020-07-18
*/
public class WxCpOaApplyEventRequestTest {
@Test
public void testToJson() {
String json = "{\n" +
" \"creator_userid\": \"WangXiaoMing\",\n" +
" \"template_id\": \"3Tka1eD6v6JfzhDMqPd3aMkFdxqtJMc2ZRioeFXkaaa\",\n" +
" \"use_template_approver\":0,\n" +
" \"approver\": [\n" +
" {\n" +
" \"attr\": 2,\n" +
" \"userid\": [\"WuJunJie\",\"WangXiaoMing\"]\n" +
" },\n" +
" {\n" +
" \"attr\": 1,\n" +
" \"userid\": [\"LiuXiaoGang\"]\n" +
" }\n" +
" ],\n" +
" \"notifyer\":[ \"WuJunJie\",\"WangXiaoMing\" ],\n" +
" \"notify_type\" : 1,\n" +
" \"apply_data\": {\n" +
" \"contents\": [\n" +
" {\n" +
" \"control\": \"Text\",\n" +
" \"id\": \"Text-15111111111\",\n" +
" \"value\": {\n" +
" \"text\": \"文本填写的内容\"\n" +
" }\n" +
" }\n" +
" ]\n" +
" },\n" +
" \"summary_list\": [\n" +
" {\n" +
" \"summary_info\": [{\n" +
" \"text\": \"摘要第1行\",\n" +
" \"lang\": \"zh_CN\"\n" +
" }]\n" +
" },\n" +
" {\n" +
" \"summary_info\": [{\n" +
" \"text\": \"摘要第2行\",\n" +
" \"lang\": \"zh_CN\"\n" +
" }]\n" +
" },\n" +
" {\n" +
" \"summary_info\": [{\n" +
" \"text\": \"摘要第3行\",\n" +
" \"lang\": \"zh_CN\"\n" +
" }]\n" +
" }\n" +
" ]\n" +
"}";
WxCpOaApplyEventRequest request = new WxCpOaApplyEventRequest();
request.setCreatorUserId("WangXiaoMing")
.setTemplateId("3Tka1eD6v6JfzhDMqPd3aMkFdxqtJMc2ZRioeFXkaaa")
.setUseTemplateApprover(0)
.setApprovers(Arrays.asList(new WxCpOaApplyEventRequest.Approver().setAttr(2).setUserIds(new String[]{"WuJunJie", "WangXiaoMing"}),
new WxCpOaApplyEventRequest.Approver().setAttr(1).setUserIds(new String[]{"LiuXiaoGang"})))
.setNotifiers(new String[]{"WuJunJie", "WangXiaoMing"})
.setNotifyType(1)
.setApplyData(new WxCpOaApplyEventRequest.ApplyData()
.setContents(Collections.singletonList(new ApplyDataContent()
.setControl("Text").setId("Text-15111111111").setValue(new ContentValue().setText("文本填写的内容")))))
.setSummaryList(Arrays.asList(new SummaryInfo()
.setSummaryInfoData(Collections.singletonList(new SummaryInfo.SummaryInfoData().setLang("zh_CN").setText("摘要第1行"))),
new SummaryInfo()
.setSummaryInfoData(Collections.singletonList(new SummaryInfo.SummaryInfoData().setLang("zh_CN").setText("摘要第2行"))),
new SummaryInfo()
.setSummaryInfoData(Collections.singletonList(new SummaryInfo.SummaryInfoData().setLang("zh_CN").setText("摘要第3行")))))
;
assertThat(request.toJson()).isEqualTo(GsonParser.parse(json).toString());
}
}