🎨 #3323 【企业微信】获取企业所有打卡规则接口增加官方新添加的late_rule等字段

This commit is contained in:
Copilot
2025-08-08 18:21:59 +08:00
committed by GitHub
parent e61ad44d27
commit 0424d75882
2 changed files with 296 additions and 0 deletions

View File

@ -151,6 +151,30 @@ public class WxCpCheckinGroupBase implements Serializable {
*/
@SerializedName("flex_off_duty_time")
private Integer flexOffDutyTime;
/**
* 是否允许弹性时间
*/
@SerializedName("allow_flex")
private Boolean allowFlex;
/**
* 迟到规则
*/
@SerializedName("late_rule")
private LateRule lateRule;
/**
* 最早可打卡时间限制
*/
@SerializedName("max_allow_arrive_early")
private Integer maxAllowArriveEarly;
/**
* 最晚可打卡时间限制
*/
@SerializedName("max_allow_arrive_late")
private Integer maxAllowArriveLate;
}
/**
@ -160,6 +184,13 @@ public class WxCpCheckinGroupBase implements Serializable {
public static class CheckinTime implements Serializable {
private static final long serialVersionUID = -5507709858609705279L;
/**
* 时段id为班次中某一堆上下班时间组合的id
*/
@SerializedName("time_id")
private Integer timeId;
/**
* 上班时间表示为距离当天0点的秒数。
*/
@ -183,6 +214,60 @@ public class WxCpCheckinGroupBase implements Serializable {
*/
@SerializedName("remind_off_work_sec")
private Integer remindOffWorkSec;
/**
* 休息开始时间仅单时段支持距离0点的秒
*/
@SerializedName("rest_begin_time")
private Integer restBeginTime;
/**
* 休息结束时间仅单时段支持距离0点的秒
*/
@SerializedName("rest_end_time")
private Integer restEndTime;
/**
* 是否允许休息
*/
@SerializedName("allow_rest")
private Boolean allowRest;
/**
* 最早可打卡时间距离0点的秒数
*/
@SerializedName("earliest_work_sec")
private Integer earliestWorkSec;
/**
* 最晚可打卡时间距离0点的秒数
*/
@SerializedName("latest_work_sec")
private Integer latestWorkSec;
/**
* 最早可下班打卡时间距离0点的秒数
*/
@SerializedName("earliest_off_work_sec")
private Integer earliestOffWorkSec;
/**
* 最晚可下班打卡时间距离0点的秒数
*/
@SerializedName("latest_off_work_sec")
private Integer latestOffWorkSec;
/**
* 上班无需打卡
*/
@SerializedName("no_need_checkon")
private Boolean noNeedCheckon;
/**
* 下班无需打卡
*/
@SerializedName("no_need_checkoff")
private Boolean noNeedCheckoff;
}
/**
@ -438,6 +523,17 @@ public class WxCpCheckinGroupBase implements Serializable {
private static final long serialVersionUID = 5604969713950037053L;
/**
* 晚走的时间 距离最晚一个下班的时间单位:秒
*/
@SerializedName("offwork_after_time")
private Integer offWorkAfterTime;
/**
* 第二天第一个班次允许迟到的弹性时间单位:秒
*/
@SerializedName("onwork_flex_time")
private Integer onWorkFlexTime;
/**
* 是否允许超时下班下班晚走次日晚到允许时onwork_flex_timeoffwork_after_time才有意义

View File

@ -209,6 +209,206 @@ public class WxCpOaServiceImplTest {
System.out.println(gson.toJson(option.getOtInfoV2()));
}
/**
* Test late_rule field deserialization in getCropCheckinOption response.
*/
@Test
public void testLateRuleDeserialization() {
// Test JSON with late_rule structure based on the issue #3323
String jsonWithLateRule = "{\n" +
" \"grouptype\": 1,\n" +
" \"groupid\": 1,\n" +
" \"checkindate\": [\n" +
" {\n" +
" \"workdays\": [1, 2, 3, 4, 5],\n" +
" \"checkintime\": [\n" +
" {\n" +
" \"time_id\": 1,\n" +
" \"work_sec\": 32400,\n" +
" \"off_work_sec\": 64800,\n" +
" \"remind_work_sec\": 31800,\n" +
" \"remind_off_work_sec\": 64800,\n" +
" \"rest_begin_time\": 43200,\n" +
" \"rest_end_time\": 48600,\n" +
" \"allow_rest\": true,\n" +
" \"earliest_work_sec\": 21600,\n" +
" \"latest_work_sec\": 64740,\n" +
" \"earliest_off_work_sec\": 32460,\n" +
" \"latest_off_work_sec\": 107940,\n" +
" \"no_need_checkon\": false,\n" +
" \"no_need_checkoff\": false\n" +
" }\n" +
" ],\n" +
" \"noneed_offwork\": false,\n" +
" \"limit_aheadtime\": 0,\n" +
" \"flex_on_duty_time\": 0,\n" +
" \"flex_off_duty_time\": 0,\n" +
" \"allow_flex\": false,\n" +
" \"late_rule\": {\n" +
" \"offwork_after_time\": 3600,\n" +
" \"onwork_flex_time\": 3600,\n" +
" \"allow_offwork_after_time\": true,\n" +
" \"timerules\": [\n" +
" {\n" +
" \"offwork_after_time\": 18000,\n" +
" \"onwork_flex_time\": 3600\n" +
" },\n" +
" {\n" +
" \"offwork_after_time\": 21600,\n" +
" \"onwork_flex_time\": 7200\n" +
" }\n" +
" ]\n" +
" },\n" +
" \"max_allow_arrive_early\": 0,\n" +
" \"max_allow_arrive_late\": 0\n" +
" }\n" +
" ],\n" +
" \"groupname\": \"打卡\",\n" +
" \"need_photo\": false\n" +
"}";
WxCpCropCheckinOption option = WxCpGsonBuilder.create().fromJson(jsonWithLateRule, WxCpCropCheckinOption.class);
assertThat(option).isNotNull();
assertThat(option.getCheckinDate()).isNotNull();
assertThat(option.getCheckinDate().size()).isEqualTo(1);
WxCpCheckinGroupBase.CheckinDate checkinDate = option.getCheckinDate().get(0);
assertThat(checkinDate).isNotNull();
assertThat(checkinDate.getAllowFlex()).isFalse();
assertThat(checkinDate.getMaxAllowArriveEarly()).isEqualTo(0);
assertThat(checkinDate.getMaxAllowArriveLate()).isEqualTo(0);
// Test late_rule field
assertThat(checkinDate.getLateRule()).isNotNull();
assertThat(checkinDate.getLateRule().getOffWorkAfterTime()).isEqualTo(3600);
assertThat(checkinDate.getLateRule().getOnWorkFlexTime()).isEqualTo(3600);
assertThat(checkinDate.getLateRule().getAllowOffWorkAfterTime()).isTrue();
assertThat(checkinDate.getLateRule().getTimerules()).isNotNull();
assertThat(checkinDate.getLateRule().getTimerules().size()).isEqualTo(2);
// Test timerules
WxCpCheckinGroupBase.TimeRule firstRule = checkinDate.getLateRule().getTimerules().get(0);
assertThat(firstRule.getOffWorkAfterTime()).isEqualTo(18000);
assertThat(firstRule.getOnWorkFlexTime()).isEqualTo(3600);
// Test CheckinTime fields
assertThat(checkinDate.getCheckinTime()).isNotNull();
assertThat(checkinDate.getCheckinTime().size()).isEqualTo(1);
WxCpCheckinGroupBase.CheckinTime checkinTime = checkinDate.getCheckinTime().get(0);
assertThat(checkinTime.getTimeId()).isEqualTo(1);
assertThat(checkinTime.getRestBeginTime()).isEqualTo(43200);
assertThat(checkinTime.getRestEndTime()).isEqualTo(48600);
assertThat(checkinTime.getAllowRest()).isTrue();
assertThat(checkinTime.getEarliestWorkSec()).isEqualTo(21600);
assertThat(checkinTime.getLatestWorkSec()).isEqualTo(64740);
assertThat(checkinTime.getEarliestOffWorkSec()).isEqualTo(32460);
assertThat(checkinTime.getLatestOffWorkSec()).isEqualTo(107940);
assertThat(checkinTime.getNoNeedCheckon()).isFalse();
assertThat(checkinTime.getNoNeedCheckoff()).isFalse();
System.out.println("Successfully parsed late_rule and new checkintime fields:");
System.out.println(gson.toJson(option));
}
/**
* Test issue #3323 - full JSON from the issue report.
*/
@Test
public void testIssue3323FullJson() {
// Full JSON from issue #3323
String issueJson = "{\n" +
" \"grouptype\": 1,\n" +
" \"groupid\": 1,\n" +
" \"checkindate\": [\n" +
" {\n" +
" \"workdays\": [\n" +
" 1,\n" +
" 2,\n" +
" 3,\n" +
" 4,\n" +
" 5\n" +
" ],\n" +
" \"checkintime\": [\n" +
" {\n" +
" \"time_id\": 1,\n" +
" \"work_sec\": 32400,\n" +
" \"off_work_sec\": 64800,\n" +
" \"remind_work_sec\": 31800,\n" +
" \"remind_off_work_sec\": 64800,\n" +
" \"rest_begin_time\": 43200,\n" +
" \"rest_end_time\": 48600,\n" +
" \"allow_rest\": true,\n" +
" \"earliest_work_sec\": 21600,\n" +
" \"latest_work_sec\": 64740,\n" +
" \"earliest_off_work_sec\": 32460,\n" +
" \"latest_off_work_sec\": 107940,\n" +
" \"no_need_checkon\": false,\n" +
" \"no_need_checkoff\": false\n" +
" }\n" +
" ],\n" +
" \"noneed_offwork\": false,\n" +
" \"limit_aheadtime\": 0,\n" +
" \"flex_on_duty_time\": 0,\n" +
" \"flex_off_duty_time\": 0,\n" +
" \"allow_flex\": false,\n" +
" \"late_rule\": {\n" +
" \"offwork_after_time\": 3600,\n" +
" \"onwork_flex_time\": 3600,\n" +
" \"allow_offwork_after_time\": true,\n" +
" \"timerules\": [\n" +
" {\n" +
" \"offwork_after_time\": 18000,\n" +
" \"onwork_flex_time\": 3600\n" +
" },\n" +
" {\n" +
" \"offwork_after_time\": 21600,\n" +
" \"onwork_flex_time\": 7200\n" +
" },\n" +
" {\n" +
" \"offwork_after_time\": 28800,\n" +
" \"onwork_flex_time\": 10800\n" +
" }\n" +
" ]\n" +
" },\n" +
" \"max_allow_arrive_early\": 0,\n" +
" \"max_allow_arrive_late\": 0\n" +
" }\n" +
" ],\n" +
" \"spe_workdays\": [],\n" +
" \"spe_offdays\": [],\n" +
" \"sync_holidays\": true,\n" +
" \"groupname\": \"打卡\",\n" +
" \"need_photo\": false,\n" +
" \"wifimac_infos\": [],\n" +
" \"note_can_use_local_pic\": true,\n" +
" \"allow_checkin_offworkday\": false,\n" +
" \"allow_apply_offworkday\": false,\n" +
" \"loc_infos\": []\n" +
" }";
WxCpCropCheckinOption option = WxCpGsonBuilder.create().fromJson(issueJson, WxCpCropCheckinOption.class);
assertThat(option).isNotNull();
assertThat(option.getGroupId()).isEqualTo(1);
assertThat(option.getGroupName()).isEqualTo("打卡");
assertThat(option.getCheckinDate()).isNotNull();
assertThat(option.getCheckinDate().size()).isEqualTo(1);
WxCpCheckinGroupBase.CheckinDate checkinDate = option.getCheckinDate().get(0);
assertThat(checkinDate.getLateRule()).isNotNull();
assertThat(checkinDate.getLateRule().getOffWorkAfterTime()).isEqualTo(3600);
assertThat(checkinDate.getLateRule().getOnWorkFlexTime()).isEqualTo(3600);
assertThat(checkinDate.getLateRule().getAllowOffWorkAfterTime()).isTrue();
assertThat(checkinDate.getLateRule().getTimerules()).isNotNull();
assertThat(checkinDate.getLateRule().getTimerules().size()).isEqualTo(3);
System.out.println("✓ Successfully parsed full JSON from issue #3323");
System.out.println("✓ Late Rule offwork_after_time: " + checkinDate.getLateRule().getOffWorkAfterTime());
System.out.println("✓ Late Rule onwork_flex_time: " + checkinDate.getLateRule().getOnWorkFlexTime());
System.out.println("✓ Late Rule allow_offwork_after_time: " + checkinDate.getLateRule().getAllowOffWorkAfterTime());
System.out.println("✓ Late Rule timerules count: " + checkinDate.getLateRule().getTimerules().size());
}
/**
* Test get approval info.
*