提交 4a4415d4 编写于 作者: 楼国栋

Merge branch 'feature/new-dd-qywx-attendance' into 'develop'

Feature/钉钉考勤打卡功能

See merge request o2oa/o2oa!256
package com.x.attendance.assemble.control;
import com.x.attendance.assemble.control.factory.AttendanceAdminFactory;
import com.x.attendance.assemble.control.factory.AttendanceAppealInfoFactory;
import com.x.attendance.assemble.control.factory.AttendanceDetailFactory;
import com.x.attendance.assemble.control.factory.AttendanceDetailMobileFactory;
import com.x.attendance.assemble.control.factory.AttendanceDetailStatisticFactory;
import com.x.attendance.assemble.control.factory.AttendanceEmployeeConfigFactory;
import com.x.attendance.assemble.control.factory.AttendanceImportFileInfoFactory;
import com.x.attendance.assemble.control.factory.AttendanceScheduleSettingFactory;
import com.x.attendance.assemble.control.factory.AttendanceSelfHolidayFactory;
import com.x.attendance.assemble.control.factory.AttendanceSettingFactory;
import com.x.attendance.assemble.control.factory.AttendanceStatisticRequireLogFactory;
import com.x.attendance.assemble.control.factory.AttendanceStatisticalCycleFactory;
import com.x.attendance.assemble.control.factory.AttendanceWorkDayConfigFactory;
import com.x.attendance.assemble.control.factory.AttendanceWorkPlaceFactory;
import com.x.attendance.assemble.control.factory.StatisticPersonForMonthFactory;
import com.x.attendance.assemble.control.factory.StatisticTopUnitForDayFactory;
import com.x.attendance.assemble.control.factory.StatisticTopUnitForMonthFactory;
import com.x.attendance.assemble.control.factory.StatisticUnitForDayFactory;
import com.x.attendance.assemble.control.factory.StatisticUnitForMonthFactory;
import com.x.attendance.assemble.control.factory.*;
import com.x.base.core.container.EntityManagerContainer;
import com.x.organization.core.express.Organization;
......@@ -34,6 +16,8 @@ public class Business {
return this.emc;
}
//钉钉同步数据处理
private DingdingAttendanceFactory dingdingAttendanceFactory;
// 人员组织业务处理类
private Organization organization;
// 系统配置业务处理类
......@@ -74,6 +58,13 @@ public class Business {
private AttendanceDetailStatisticFactory attendanceDetailStatisticFactory;
public DingdingAttendanceFactory dingdingAttendanceFactory() throws Exception {
if (null == this.dingdingAttendanceFactory) {
this.dingdingAttendanceFactory = new DingdingAttendanceFactory(this);
}
return this.dingdingAttendanceFactory;
}
public AttendanceWorkPlaceFactory attendanceWorkPlaceFactory() throws Exception {
if (null == this.attendanceWorkPlaceFactory) {
this.attendanceWorkPlaceFactory = new AttendanceWorkPlaceFactory(this);
......
package com.x.attendance.assemble.control;
import com.x.attendance.assemble.control.exception.DingDingRequestException;
import com.x.attendance.entity.AttendanceDingtalkDetail;
import com.x.attendance.entity.AttendanceDingtalkDetail_;
import com.x.attendance.entity.DingdingQywxSyncRecord;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.Application;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.config.Config;
import com.x.base.core.project.connection.HttpConnection;
import com.x.base.core.project.gson.GsonPropertyObject;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.organization.Person;
import com.x.base.core.project.organization.Unit;
import com.x.base.core.project.queue.AbstractQueue;
import com.x.base.core.project.tools.DateTools;
import com.x.base.core.project.tools.ListTools;
import com.x.base.core.project.x_organization_assemble_control;
import org.apache.commons.lang3.StringUtils;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class DingdingAttendanceQueue extends AbstractQueue<DingdingQywxSyncRecord> {
......@@ -21,37 +40,204 @@ public class DingdingAttendanceQueue extends AbstractQueue<DingdingQywxSyncRecor
@Override
protected void execute(DingdingQywxSyncRecord record) throws Exception {
logger.info("开始执行钉钉打卡数据同步," + record.getWay());
logger.info("开始执行钉钉打卡数据同步,from:" + record.getDateFrom() + ", to:"+record.getDateTo());
if (DingdingQywxSyncRecord.syncType_dingding.equals(record.getType())) {
try {
dingdingSync(record);
}catch (Exception e) {
logger.error(e);
updateSyncRecord(record, e.getMessage());
}
} else {
logger.info("不是钉钉同步任务。。。。。。。。。。。。。");
}
}
private boolean isSameDay(Date startDate, Date endDate) {
Calendar start = Calendar.getInstance();
start.setTime( startDate );
Calendar end = Calendar.getInstance();
end.setTime(endDate);
return (start.get(Calendar.YEAR) == end.get(Calendar.YEAR) && start.get(Calendar.DAY_OF_YEAR) == end.get(Calendar.DAY_OF_YEAR));
}
private void dingdingSync(DingdingQywxSyncRecord record) throws Exception {
Application app = ThisApplication.context().applications().randomWithWeight(x_organization_assemble_control.class.getName());
//开始分页查询人员
boolean hasNextPerson = true;
int personPageSize = 50;
//开始时间和结束时间
Date fromDate = new Date();
fromDate.setTime(record.getDateFrom());
Date toDate =new Date();
toDate.setTime(record.getDateTo());
//先删除
deleteDingdingAttendance(fromDate, toDate);
//人员查询地址
String uri = "person/list/(0)/next/50";
//钉钉考勤同步接口地址
String dingdingUrl = "https://oapi.dingtalk.com/attendance/list?access_token=" + Config.dingding().corpAccessToken();
int saveNumber = 0;
while (hasNextPerson) {
List<Person> list = ThisApplication.context().applications().getQuery(false, app, uri).getDataAsList(Person.class);
if (list != null && list.size() > 0) {
//钉钉用户id
List<String> ddUsers = list.stream().filter(person -> StringUtils.isNotEmpty(person.getDingdingId()))
.map(Person::getDingdingId).collect(Collectors.toList());
if (ListTools.isNotEmpty(ddUsers)) {
//分页查询
int page = 0;
boolean hasMoreResult = true;
while (hasMoreResult) {
DingdingAttendancePost post = new DingdingAttendancePost();
//post传入 时间(时间间隔不能超过7天) 人员(人员数量不能超过50个)
post.setLimit(50L);
post.setOffset(page * 50L);//从0开始翻页
//这里的开始时间和结束时间 查询的是钉钉返回结果中的workDate
//查询考勤打卡记录的起始工作日
post.setWorkDateFrom(DateTools.format(fromDate));
//查询考勤打卡记录的结束工作日
post.setWorkDateTo(DateTools.format(toDate));
post.setUserIdList(ddUsers);
DingdingAttendanceResult result = HttpConnection.postAsObject(dingdingUrl, null, post.toString(), DingdingAttendanceResult.class);
if (result.errcode != null && result.errcode == 0) {
List<DingdingAttendanceResultItem> resultList = result.getRecordresult();
saveDingdingAttendance(resultList, list);
saveNumber += resultList.size();
if (result.hasMore) {
page++;
} else {
logger.info("同步钉钉考勤结束。。。。。。。。。。。。。。。。");
hasMoreResult = false;
}
} else {
//请求结果异常 结束
throw new DingDingRequestException(result.errmsg);
}
}
}
//是否还有更多用户
if (list.size() < personPageSize) {
logger.info("同步钉钉考勤 没有更多用户了,结束。。。。。。。。。。。。。。。");
hasNextPerson = false;
updateSyncRecord(record, null);
} else {
//还有更多用户继续查询
uri = "person/list/" + list.get(list.size() - 1).getDistinguishedName() + "/next/50";
}
} else {
//没有用户查询到结束
logger.info("同步钉钉考勤 查询不到用户了,结束。。。。。。。。。。。。。。。");
hasNextPerson = false;
updateSyncRecord(record, null);
}
}
logger.info("结束 插入:"+saveNumber+" 条");
//插入数据成功 开始统计程序
private void dingdingSync() throws Exception {
boolean hasNextDate = true;
Date statisticDate = fromDate;
while (hasNextDate) {
logger.info("发起钉钉考勤数据统计, date:"+ DateTools.format(statisticDate));
ThisApplication.personStatisticQueue.send(statisticDate);
ThisApplication.unitStatisticQueue.send(statisticDate);
if (!isSameDay(statisticDate, toDate)) {
statisticDate = DateTools.addDay(statisticDate, 1);
}else {
hasNextDate = false;
}
}
logger.info("发起数据统计程序 完成。。。。。。。。。。");
}
private void deleteDingdingAttendance(Date fromDate, Date toDate) throws Exception{
try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
Application app = ThisApplication.context().applications().randomWithWeight(x_organization_assemble_control.class.getName());
//开始分页查询人员
boolean hasNextPerson = true;
String uri = "person/list/(0)/next/50";
String dingdingUrl = "https://oapi.dingtalk.com/attendance/list?access_token="+ Config.dingding().corpAccessToken();
while (hasNextPerson) {
List<Person> list = ThisApplication.context().applications().getQuery(false, app, uri).getDataAsList(Person.class);
if (list != null && list.size() > 0) {
DingdingAttendancePost post = new DingdingAttendancePost();
}else {
//没有用户查询到结束
logger.info("查询不到用户了,结束。。。。。。。。。。。。。。。");
hasNextPerson = false;
//先删除 再同步
EntityManager em = emc.get(AttendanceDingtalkDetail.class);
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<AttendanceDingtalkDetail> query = cb.createQuery(AttendanceDingtalkDetail.class);
Root<AttendanceDingtalkDetail> root = query.from(AttendanceDingtalkDetail.class);
long start = fromDate.getTime();
long end = toDate.getTime();
Predicate p = cb.between(root.get(AttendanceDingtalkDetail_.workDate), start, end);
query.select(root).where(p);
List<AttendanceDingtalkDetail> detailList = em.createQuery(query).getResultList();
//先删除
logger.info("删除");
if (detailList != null) {
logger.info("删除 list:"+detailList.size());
emc.beginTransaction(AttendanceDingtalkDetail.class);
for (int i = 0; i < detailList.size(); i++) {
emc.remove(detailList.get(i));
}
emc.commit();
}
logger.info("删除结束");
}
}
private void saveDingdingAttendance(List<DingdingAttendanceResultItem> list, List<Person> personList) throws Exception {
if (list != null && !list.isEmpty()) {
try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
emc.beginTransaction(AttendanceDingtalkDetail.class);
for (int i = 0; i < list.size(); i++) {
DingdingAttendanceResultItem item = list.get(i);
AttendanceDingtalkDetail detail = DingdingAttendanceResultItem.copier.copy(item);
detail.setDdId(item.getId());
if (detail.getUserCheckTime() > 0) {
Date date = new Date(detail.getUserCheckTime());
detail.setUserCheckTimeDate(date);
}
//添加o2组织和用户
Optional<Person> first = personList.stream().filter(p -> item.userId.equals(p.getDingdingId())).findFirst();
if (first.isPresent()) {
Person person = first.get();
String unit = getUnitWithPerson(person.getDistinguishedName(), business);
detail.setO2Unit(unit);
detail.setO2User(person.getDistinguishedName());
}
emc.persist(detail);
}
emc.commit();
}
}
}
private String getUnitWithPerson(String person, Business business) throws Exception {
String result = null;
Integer level = 0;
Unit unit = null;
List<String> unitNames = business.organization().unit().listWithPerson( person );
if( ListTools.isNotEmpty( unitNames ) ) {
for( String unitName : unitNames ) {
if( StringUtils.isNotEmpty( unitName ) && !"null".equals( unitName ) ) {
unit = business.organization().unit().getObject( unitName );
if( level < unit.getLevel() ) {
level = unit.getLevel();
result = unitName;
}
}
}
}
return result;
}
private void updateSyncRecord(DingdingQywxSyncRecord record, String errMsg) throws Exception {
try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
emc.beginTransaction(DingdingQywxSyncRecord.class);
DingdingQywxSyncRecord entity = emc.find(record.getId(), DingdingQywxSyncRecord.class);
entity.setEndTime(new Date());
if (errMsg == null || errMsg.isEmpty()) {
entity.setStatus(DingdingQywxSyncRecord.status_end);
} else {
entity.setStatus(DingdingQywxSyncRecord.status_error);
entity.setExceptionMessage(errMsg);
}
emc.commit();
}
}
public static class DingdingAttendancePost extends GsonPropertyObject {
// {
// {
// "workDateFrom": "yyyy-MM-dd HH:mm:ss",
// "workDateTo": "yyyy-MM-dd HH:mm:ss",
// "userIdList":["员工UserId列表"], // 必填,与offset和limit配合使用
......@@ -61,8 +247,8 @@ public class DingdingAttendanceQueue extends AbstractQueue<DingdingQywxSyncRecor
private String workDateFrom;
private String workDateTo;
private List<String> userIdList;
private Integer offset;
private Integer limit;
private Long offset;
private Long limit;
public String getWorkDateFrom() {
return workDateFrom;
......@@ -88,20 +274,185 @@ public class DingdingAttendanceQueue extends AbstractQueue<DingdingQywxSyncRecor
this.userIdList = userIdList;
}
public Integer getOffset() {
public Long getOffset() {
return offset;
}
public void setOffset(Integer offset) {
public void setOffset(Long offset) {
this.offset = offset;
}
public Integer getLimit() {
public Long getLimit() {
return limit;
}
public void setLimit(Integer limit) {
public void setLimit(Long limit) {
this.limit = limit;
}
}
public static class DingdingAttendanceResult extends GsonPropertyObject {
private Integer errcode;
private String errmsg;
private Boolean hasMore;
private List<DingdingAttendanceResultItem> recordresult;
public Integer getErrcode() {
return errcode;
}
public void setErrcode(Integer errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public Boolean getHasMore() {
return hasMore;
}
public void setHasMore(Boolean hasMore) {
this.hasMore = hasMore;
}
public List<DingdingAttendanceResultItem> getRecordresult() {
return recordresult;
}
public void setRecordresult(List<DingdingAttendanceResultItem> recordresult) {
this.recordresult = recordresult;
}
}
public static class DingdingAttendanceResultItem extends GsonPropertyObject {
private static final long serialVersionUID = 1618421987561110713L;
static WrapCopier<DingdingAttendanceResultItem, AttendanceDingtalkDetail> copier = WrapCopierFactory.wi(DingdingAttendanceResultItem.class,
AttendanceDingtalkDetail.class, null, JpaObject.FieldsUnmodify);
private long id;
private long ddId;
private String userId;
private long baseCheckTime;
private long userCheckTime;
private long workDate;
private String timeResult;
private String checkType;
private String locationResult;
private String sourceType;
private long groupId;
private long planId;
private long recordId;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public long getDdId() {
return ddId;
}
public void setDdId(long ddId) {
this.ddId = ddId;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public long getBaseCheckTime() {
return baseCheckTime;
}
public void setBaseCheckTime(long baseCheckTime) {
this.baseCheckTime = baseCheckTime;
}
public long getUserCheckTime() {
return userCheckTime;
}
public void setUserCheckTime(long userCheckTime) {
this.userCheckTime = userCheckTime;
}
public long getWorkDate() {
return workDate;
}
public void setWorkDate(long workDate) {
this.workDate = workDate;
}
public String getTimeResult() {
return timeResult;
}
public void setTimeResult(String timeResult) {
this.timeResult = timeResult;
}
public String getCheckType() {
return checkType;
}
public void setCheckType(String checkType) {
this.checkType = checkType;
}
public String getLocationResult() {
return locationResult;
}
public void setLocationResult(String locationResult) {
this.locationResult = locationResult;
}
public String getSourceType() {
return sourceType;
}
public void setSourceType(String sourceType) {
this.sourceType = sourceType;
}
public long getGroupId() {
return groupId;
}
public void setGroupId(long groupId) {
this.groupId = groupId;
}
public long getPlanId() {
return planId;
}
public void setPlanId(long planId) {
this.planId = planId;
}
public long getRecordId() {
return recordId;
}
public void setRecordId(long recordId) {
this.recordId = recordId;
}
}
}
package com.x.attendance.assemble.control;
import com.x.attendance.entity.AttendanceDingtalkDetail;
import com.x.attendance.entity.StatisticDingdingPersonForMonth;
import com.x.attendance.entity.StatisticDingdingUnitForDay;
import com.x.attendance.entity.StatisticDingdingUnitForMonth;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.project.Application;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.organization.Person;
import com.x.base.core.project.organization.Unit;
import com.x.base.core.project.queue.AbstractQueue;
import com.x.base.core.project.tools.DateTools;
import com.x.base.core.project.tools.ListTools;
import com.x.base.core.project.x_organization_assemble_control;
import org.apache.commons.lang3.StringUtils;
import java.util.Date;
import java.util.List;
/**
* Created by fancyLou on 2020-04-05.
* Copyright © 2020 O2. All rights reserved.
*/
public class DingdingPersonStatisticQueue extends AbstractQueue<Date> {
private static final Logger logger = LoggerFactory.getLogger(DingdingPersonStatisticQueue.class);
@Override
protected void execute(Date date) throws Exception {
logger.info("开始执行人员钉钉考勤统计。。。time:"+DateTools.format(date));
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
saveStatisticPersonForMonth(business, emc, date);
}
}
private void saveStatisticPersonForMonth(Business business, EntityManagerContainer emc, Date date) throws Exception {
String dateString = DateTools.format(date, DateTools.format_yyyyMMdd);
String year = dateString.substring(0, 4);
String month = dateString.substring(5, 7);
Application app = ThisApplication.context().applications().randomWithWeight(x_organization_assemble_control.class.getName());
//开始分页查询人员
boolean hasNextPerson = true;
int personPageSize = 50;
//人员查询地址
String uri = "person/list/(0)/next/50";
while (hasNextPerson) {
List<Person> list = ThisApplication.context().applications()
.getQuery(false, app, uri).getDataAsList(Person.class);
if (list != null && list.size() > 0) {
for (Person person : list) {
List<String> ids = business.dingdingAttendanceFactory()
.getStatPersonForMonthIds(year, month, person.getDistinguishedName());
emc.beginTransaction(StatisticDingdingPersonForMonth.class);
if (ids != null && ids.size() > 0) {
for (String item : ids) {
StatisticDingdingPersonForMonth personForMonth_temp = emc.find(item, StatisticDingdingPersonForMonth.class);
emc.remove(personForMonth_temp);
}
}
StatisticDingdingPersonForMonth personForMonth = new StatisticDingdingPersonForMonth();
personForMonth.setStatisticYear(year);
personForMonth.setStatisticMonth(month);
personForMonth.setO2Unit(getUnitWithPerson(person.getDistinguishedName(), business));
personForMonth.setO2User(person.getDistinguishedName());
Long onduty = business.dingdingAttendanceFactory().dingdingPersonForMonthDutyTimesCount(year, month,
person.getDistinguishedName(), AttendanceDingtalkDetail.OnDuty);
personForMonth.setWorkDayCount(onduty);
personForMonth.setOnDutyTimes(onduty);
personForMonth.setOffDutyTimes(business.dingdingAttendanceFactory().dingdingPersonForMonthDutyTimesCount(year, month,
person.getDistinguishedName(), AttendanceDingtalkDetail.OffDuty));
personForMonth.setResultNormal(business.dingdingAttendanceFactory().dingdingPersonForMonthTimeResultCount(year, month,
person.getDistinguishedName(), AttendanceDingtalkDetail.TIMERESULT_NORMAL));
personForMonth.setLateTimes(business.dingdingAttendanceFactory().dingdingPersonForMonthTimeResultCount(year, month,
person.getDistinguishedName(), AttendanceDingtalkDetail.TIMERESULT_Late));
personForMonth.setLeaveEarlyTimes(business.dingdingAttendanceFactory().dingdingPersonForMonthTimeResultCount(year, month,
person.getDistinguishedName(), AttendanceDingtalkDetail.TIMERESULT_Early));
personForMonth.setAbsenteeismTimes(business.dingdingAttendanceFactory().dingdingPersonForMonthTimeResultCount(year, month,
person.getDistinguishedName(), AttendanceDingtalkDetail.TIMERESULT_Absenteeism));
personForMonth.setNotSignedCount(business.dingdingAttendanceFactory().dingdingPersonForMonthTimeResultCount(year, month,
person.getDistinguishedName(), AttendanceDingtalkDetail.TIMERESULT_NotSigned));
personForMonth.setSeriousLateTimes(business.dingdingAttendanceFactory().dingdingPersonForMonthTimeResultCount(year, month,
person.getDistinguishedName(), AttendanceDingtalkDetail.TIMERESULT_SeriousLate));
emc.persist(personForMonth);
emc.commit();
}
//是否还有更多用户
if (list.size() < personPageSize) {
logger.info("统计钉钉考勤个人数据 结束。。。。。。。。。。。。。。。");
hasNextPerson = false;
} else {
//还有更多用户继续查询
uri = "person/list/" + list.get(list.size() - 1).getDistinguishedName() + "/next/50";
}
}else {
//没有用户查询到结束
logger.info("统计钉钉考勤个人数据 结束。。。。。。。。。。。。。。。");
hasNextPerson = false;
}
}
}
private String getUnitWithPerson(String person, Business business) throws Exception {
String result = null;
Integer level = 0;
Unit unit = null;
List<String> unitNames = business.organization().unit().listWithPerson( person );
if( ListTools.isNotEmpty( unitNames ) ) {
for( String unitName : unitNames ) {
if( StringUtils.isNotEmpty( unitName ) && !"null".equals( unitName ) ) {
unit = business.organization().unit().getObject( unitName );
if( level < unit.getLevel() ) {
level = unit.getLevel();
result = unitName;
}
}
}
}
return result;
}
}
package com.x.attendance.assemble.control;
import com.x.attendance.entity.AttendanceDingtalkDetail;
import com.x.attendance.entity.StatisticDingdingUnitForDay;
import com.x.attendance.entity.StatisticDingdingUnitForMonth;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.queue.AbstractQueue;
import com.x.base.core.project.tools.DateTools;
import org.apache.commons.lang3.StringUtils;
import java.util.Date;
import java.util.List;
/**
* Created by fancyLou on 2020-04-05.
* Copyright © 2020 O2. All rights reserved.
*/
public class DingdingUnitStatisticQueue extends AbstractQueue<Date> {
private static final Logger logger = LoggerFactory.getLogger(DingdingUnitStatisticQueue.class);
@Override
protected void execute(Date date) throws Exception {
logger.info("开始执行组织钉钉考勤统计。。。time:"+DateTools.format(date));
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
saveStatisticUnitForDay(business, emc, date);
}
}
/**
* 单位 日统计
* @param business
* @param emc
* @param date
* @throws Exception
*/
private void saveStatisticUnitForDay(Business business, EntityManagerContainer emc, Date date) throws Exception{
String dateString = DateTools.format(date, DateTools.format_yyyyMMdd);
String year = dateString.substring(0, 4);
String month = dateString.substring(5, 7);
String day = dateString.substring(8, 10);
List<String> units = business.dingdingAttendanceFactory().dingdingUnitDistinct(dateString);
if (units != null && !units.isEmpty()) {
for (String unit : units) {
if (StringUtils.isEmpty(unit)){
continue;
}
List<String> ids = business.dingdingAttendanceFactory().getStatUnitForDayIds(year, month, day, unit);
emc.beginTransaction(StatisticDingdingUnitForDay.class);
if (ids != null && ids.size() > 0) {
for (String item : ids) {
StatisticDingdingUnitForDay statisticTopUnitForDay_tmp = emc.find(item, StatisticDingdingUnitForDay.class);
emc.remove(statisticTopUnitForDay_tmp);
}
}
//for day
StatisticDingdingUnitForDay unitForDay = new StatisticDingdingUnitForDay();
unitForDay.setO2Unit(unit);
unitForDay.setStatisticYear(year);
unitForDay.setStatisticMonth(month);
unitForDay.setStatisticDate(day);
Long on = business.dingdingAttendanceFactory().dingdingUnitForDayDutyTimesCount(dateString, unit, AttendanceDingtalkDetail.OnDuty);
unitForDay.setWorkDayCount(on);
unitForDay.setOnDutyTimes(on);
unitForDay.setOffDutyTimes(business.dingdingAttendanceFactory().
dingdingUnitForDayDutyTimesCount(dateString, unit, AttendanceDingtalkDetail.OffDuty));
unitForDay.setResultNormal(business.dingdingAttendanceFactory().dingdingUnitForDayTimeResultCount(dateString, unit,
AttendanceDingtalkDetail.TIMERESULT_NORMAL));
unitForDay.setLateTimes(business.dingdingAttendanceFactory().dingdingUnitForDayTimeResultCount(dateString, unit,
AttendanceDingtalkDetail.TIMERESULT_Late));
unitForDay.setLeaveEarlyTimes(business.dingdingAttendanceFactory().dingdingUnitForDayTimeResultCount(dateString, unit,
AttendanceDingtalkDetail.TIMERESULT_Early));
unitForDay.setNotSignedCount(business.dingdingAttendanceFactory().dingdingUnitForDayTimeResultCount(dateString, unit,
AttendanceDingtalkDetail.TIMERESULT_NotSigned));
unitForDay.setAbsenteeismTimes(business.dingdingAttendanceFactory().dingdingUnitForDayTimeResultCount(dateString, unit,
AttendanceDingtalkDetail.TIMERESULT_Absenteeism));
unitForDay.setSeriousLateTimes(business.dingdingAttendanceFactory().dingdingUnitForDayTimeResultCount(dateString, unit,
AttendanceDingtalkDetail.TIMERESULT_SeriousLate));
emc.persist(unitForDay);
emc.commit();
}
saveStatisticUnitForMonth(business, emc, units, year, month);
}
}
/**
* 单位月统计
* @param business
* @param emc
* @param units
* @param year
* @param month
* @throws Exception
*/
private void saveStatisticUnitForMonth(Business business, EntityManagerContainer emc, List<String> units,
String year, String month) throws Exception {
for (String unit : units) {
if (StringUtils.isEmpty(unit)){
continue;
}
Long workDay = business.dingdingAttendanceFactory().sumWorkDayUnitForDayWithMonth(year, month, unit);
Long onduty = business.dingdingAttendanceFactory().sumOnDutyUnitForDayWithMonth(year, month, unit);
Long offDuty = business.dingdingAttendanceFactory().sumOffDutyUnitForDayWithMonth(year, month, unit);
Long normal = business.dingdingAttendanceFactory().sumNormalUnitForDayWithMonth(year, month, unit);
Long late = business.dingdingAttendanceFactory().sumLateTimesUnitForDayWithMonth(year, month, unit);
Long leaveearly = business.dingdingAttendanceFactory().sumLeaveEarlyUnitForDayWithMonth(year, month, unit);
Long notSign = business.dingdingAttendanceFactory().sumNotSignedUnitForDayWithMonth(year, month, unit);
Long absenteeism = business.dingdingAttendanceFactory().sumAbsenteeismUnitForDayWithMonth(year, month, unit);
Long serious = business.dingdingAttendanceFactory().sumSeriousLateUnitForDayWithMonth(year, month, unit);
List<String> list = business.dingdingAttendanceFactory().getStatUnitForMonthIds(year, month, unit);
emc.beginTransaction(StatisticDingdingUnitForMonth.class);
if (list != null && list.size() > 0) {
for (String item : list) {
StatisticDingdingUnitForMonth statisticTopUnitForMonth_tmp = emc.find(item, StatisticDingdingUnitForMonth.class);
emc.remove(statisticTopUnitForMonth_tmp);
}
}
StatisticDingdingUnitForMonth unitForMonth = new StatisticDingdingUnitForMonth();
unitForMonth.setO2Unit(unit);
unitForMonth.setStatisticYear(year);
unitForMonth.setStatisticMonth(month);
unitForMonth.setWorkDayCount(workDay);
unitForMonth.setOnDutyTimes(onduty);
unitForMonth.setOffDutyTimes(offDuty);
unitForMonth.setResultNormal(normal);
unitForMonth.setLateTimes(late);
unitForMonth.setLeaveEarlyTimes(leaveearly);
unitForMonth.setNotSignedCount(notSign);
unitForMonth.setAbsenteeismTimes(absenteeism);
unitForMonth.setSeriousLateTimes(serious);
emc.persist(unitForMonth);
emc.commit();
}
}
}
package com.x.attendance.assemble.control;
import com.x.attendance.assemble.control.exception.DingDingRequestException;
import com.x.attendance.entity.*;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.Application;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.config.Config;
import com.x.base.core.project.connection.HttpConnection;
import com.x.base.core.project.gson.GsonPropertyObject;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.organization.Person;
import com.x.base.core.project.queue.AbstractQueue;
import com.x.base.core.project.tools.ListTools;
import com.x.base.core.project.tools.StringTools;
import com.x.base.core.project.x_organization_assemble_control;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
public class QywxAttendanceSyncQueue extends AbstractQueue<DingdingQywxSyncRecord> {
private static final Logger logger = LoggerFactory.getLogger(QywxAttendanceSyncQueue.class);
@Override
protected void execute(DingdingQywxSyncRecord record) throws Exception {
logger.info("开始执行企业微信打卡数据同步,from:" + record.getDateFrom() + ", to:"+record.getDateTo());
if (DingdingQywxSyncRecord.syncType_qywx.equals(record.getType())) {
try {
qywxSync(record);
}catch (Exception e) {
logger.error(e);
updateSyncRecord(record, e.getMessage());
}
} else {
logger.info("不是企业微信同步任务。。。。。。。。。。。。。");
}
}
private void qywxSync(DingdingQywxSyncRecord record) throws Exception{
Application app = ThisApplication.context().applications().randomWithWeight(x_organization_assemble_control.class.getName());
//开始分页查询人员
boolean hasNextPerson = true;
int personPageSize = 50;
//开始时间和结束时间
Date fromDate = new Date();
fromDate.setTime(record.getDateFrom());
Date toDate =new Date();
toDate.setTime(record.getDateTo());
//先删除
deleteQywxAttendance(fromDate, toDate);
//人员查询地址
String uri = "person/list/(0)/next/50";
String qywxuri = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata?access_token="+ Config.qiyeweixin().attendanceAccessToken();
int saveNumber = 0;
while (hasNextPerson) {
List<Person> list = ThisApplication.context().applications().getQuery(false, app, uri).getDataAsList(Person.class);
if (list != null && list.size() > 0) {
//钉钉用户id
List<String> qywxUsers = list.stream().filter(person -> StringUtils.isNotEmpty(person.getQiyeweixinId()))
.map(Person::getQiyeweixinId).collect(Collectors.toList());
if(ListTools.isNotEmpty(qywxUsers)){
QywxPost post = new QywxPost();
post.setStarttime(fromDate.getTime());
post.setEndtime(toDate.getTime());
post.setUseridlist(qywxUsers);
post.setOpencheckindatatype(3);//全部打卡信息
logger.info("企业微信 post :" + post.toString());
QywxResult result = HttpConnection.postAsObject(qywxuri, null, post.toString(), QywxResult.class);
logger.info("返回结果:"+result.toString());
if (result.errcode == 0) {
List<QywxResultItem> resultList = result.getCheckindata();
saveQywxAttendance(resultList);
saveNumber += resultList.size();
} else {
//请求结果异常 结束
throw new DingDingRequestException(result.errmsg);
}
}
//是否还有更多用户
if (list.size() < personPageSize) {
logger.info("同步钉钉考勤 没有更多用户了,结束。。。。。。。。。。。。。。。");
hasNextPerson = false;
updateSyncRecord(record, null);
} else {
//还有更多用户继续查询
uri = "person/list/" + list.get(list.size() - 1).getDistinguishedName() + "/next/50";
}
} else {
//没有用户查询到结束
logger.info("同步钉钉考勤 查询不到用户了,结束。。。。。。。。。。。。。。。");
hasNextPerson = false;
updateSyncRecord(record, null);
}
}
logger.info("结束 插入:"+saveNumber+" 条");
}
private void saveQywxAttendance(List<QywxResultItem> resultList) throws Exception {
if (resultList != null && !resultList.isEmpty()) {
try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
emc.beginTransaction(AttendanceQywxDetail.class);
for (int i = 0; i < resultList.size(); i++) {
QywxResultItem item = resultList.get(i);
AttendanceQywxDetail detail = QywxResultItem.copier.copy(item);
emc.persist(detail);
}
emc.commit();
}
}
}
private void deleteQywxAttendance(Date fromDate, Date toDate) throws Exception {
try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
//先删除 再同步
EntityManager em = emc.get(AttendanceQywxDetail.class);
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<AttendanceQywxDetail> query = cb.createQuery(AttendanceQywxDetail.class);
Root<AttendanceQywxDetail> root = query.from(AttendanceQywxDetail.class);
long start = fromDate.getTime();
long end = toDate.getTime();
Predicate p = cb.between(root.get(AttendanceQywxDetail_.checkin_time), start, end);
query.select(root).where(p);
List<AttendanceQywxDetail> detailList = em.createQuery(query).getResultList();
//先删除
logger.info("删除");
if (detailList != null) {
logger.info("删除 list:"+detailList.size());
emc.beginTransaction(AttendanceQywxDetail.class);
for (int i = 0; i < detailList.size(); i++) {
emc.remove(detailList.get(i));
}
emc.commit();
}
logger.info("删除结束");
}
}
private void updateSyncRecord(DingdingQywxSyncRecord record, String message) throws Exception {
try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
emc.beginTransaction(DingdingQywxSyncRecord.class);
DingdingQywxSyncRecord entity = emc.find(record.getId(), DingdingQywxSyncRecord.class);
entity.setEndTime(new Date());
if (message == null || message.isEmpty()) {
entity.setStatus(DingdingQywxSyncRecord.status_end);
} else {
entity.setStatus(DingdingQywxSyncRecord.status_error);
entity.setExceptionMessage(message);
}
emc.commit();
}
}
public static class QywxPost extends GsonPropertyObject {
//{
// "opencheckindatatype": 3,
// "starttime": 1492617600,
// "endtime": 1492790400,
// "useridlist": ["james","paul"]
//}
//打卡类型。1:上下班打卡;2:外出打卡;3:全部打卡
private int opencheckindatatype;
private long starttime;
private long endtime;
private List<String> useridlist;
public int getOpencheckindatatype() {
return opencheckindatatype;
}
public void setOpencheckindatatype(int opencheckindatatype) {
this.opencheckindatatype = opencheckindatatype;
}
public long getStarttime() {
return starttime;
}
public void setStarttime(long starttime) {
this.starttime = starttime;
}
public long getEndtime() {
return endtime;
}
public void setEndtime(long endtime) {
this.endtime = endtime;
}
public List<String> getUseridlist() {
return useridlist;
}
public void setUseridlist(List<String> useridlist) {
this.useridlist = useridlist;
}
}
public static class QywxResult extends GsonPropertyObject {
private int errcode;
private String errmsg;
private List<QywxResultItem> checkindata;
public int getErrcode() {
return errcode;
}
public void setErrcode(int errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public List<QywxResultItem> getCheckindata() {
return checkindata;
}
public void setCheckindata(List<QywxResultItem> checkindata) {
this.checkindata = checkindata;
}
}
public static class QywxResultItem extends GsonPropertyObject {
static WrapCopier<QywxResultItem, AttendanceQywxDetail> copier = WrapCopierFactory.wi(QywxResultItem.class,
AttendanceQywxDetail.class, null, JpaObject.FieldsUnmodify);
private String userid;
private String groupname;
private String checkin_type;
private long checkin_time;
private String exception_type;
private String location_title;
private String location_detail;
private String wifiname;
private String notes;
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getGroupname() {
return groupname;
}
public void setGroupname(String groupname) {
this.groupname = groupname;
}
public String getCheckin_type() {
return checkin_type;
}
public void setCheckin_type(String checkin_type) {
this.checkin_type = checkin_type;
}
public long getCheckin_time() {
return checkin_time;
}
public void setCheckin_time(long checkin_time) {
this.checkin_time = checkin_time;
}
public String getException_type() {
return exception_type;
}
public void setException_type(String exception_type) {
this.exception_type = exception_type;
}
public String getLocation_title() {
return location_title;
}
public void setLocation_title(String location_title) {
this.location_title = location_title;
}
public String getLocation_detail() {
return location_detail;
}
public void setLocation_detail(String location_detail) {
this.location_detail = location_detail;
}
public String getWifiname() {
return wifiname;
}
public void setWifiname(String wifiname) {
this.wifiname = wifiname;
}
public String getNotes() {
return notes;
}
public void setNotes(String notes) {
this.notes = notes;
}
}
}
......@@ -2,8 +2,7 @@ package com.x.attendance.assemble.control;
import com.x.attendance.assemble.control.processor.monitor.MonitorFileDataOpt;
import com.x.attendance.assemble.control.processor.thread.DataProcessThreadFactory;
import com.x.attendance.assemble.control.schedule.AttendanceStatisticTask;
import com.x.attendance.assemble.control.schedule.MobileRecordAnalyseTask;
import com.x.attendance.assemble.control.schedule.*;
import com.x.attendance.assemble.control.service.AttendanceSettingService;
import com.x.base.core.project.Context;
import com.x.base.core.project.config.Config;
......@@ -18,6 +17,9 @@ public class ThisApplication {
}
public static DingdingAttendanceQueue dingdingQueue = new DingdingAttendanceQueue();
public static QywxAttendanceSyncQueue qywxQueue = new QywxAttendanceSyncQueue();
public static DingdingPersonStatisticQueue personStatisticQueue = new DingdingPersonStatisticQueue();
public static DingdingUnitStatisticQueue unitStatisticQueue = new DingdingUnitStatisticQueue();
public static void init() throws Exception {
try {
......@@ -26,6 +28,16 @@ public class ThisApplication {
context.schedule(MobileRecordAnalyseTask.class, "0 0/10 * * * ?");
if (BooleanUtils.isTrue(Config.dingding().getAttendanceSyncEnable())) {
dingdingQueue.start();
personStatisticQueue.start();
unitStatisticQueue.start();
context.schedule(DingdingAttendanceSyncScheduleTask.class, "0 0 1 * * ?");
//已经将任务 放到了同步结束后执行 暂时不需要开定时任务了
// context.schedule(DingdingAttendanceStatisticScheduleTask.class, "0 0 3 * * ?");
// context.schedule(DingdingAttendanceStatisticPersonScheduleTask.class, "0 0 3 * * ?");
}
if (BooleanUtils.isTrue(Config.qiyeweixin().getAttendanceSyncEnable())) {
qywxQueue.start();
context.schedule(QywxAttendanceSyncScheduleTask.class, "0 0 1 * * ?");
}
} catch (Exception e) {
e.printStackTrace();
......@@ -48,5 +60,20 @@ public class ThisApplication {
} catch (Exception e) {
e.printStackTrace();
}
try {
personStatisticQueue.stop();
} catch (Exception e) {
e.printStackTrace();
}
try {
unitStatisticQueue.stop();
} catch (Exception e) {
e.printStackTrace();
}
try {
qywxQueue.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
}
\ No newline at end of file
package com.x.attendance.assemble.control.exception;
import com.x.base.core.project.exception.PromptException;
public class DingDingRequestException extends PromptException {
private static final long serialVersionUID = -2160589718239895222L;
public DingDingRequestException(String errorMsg) {
super(errorMsg);
}
}
package com.x.attendance.assemble.control.exception;
import com.x.base.core.project.exception.PromptException;
public class DingdingFindNoArgumentError extends PromptException {
public DingdingFindNoArgumentError() {
super("没有传入正确的参数");
}
}
package com.x.attendance.assemble.control.exception;
import com.x.base.core.project.exception.PromptException;
public class QywxFindNoArgumentError extends PromptException {
public QywxFindNoArgumentError() {
super("没有传入正确的参数");
}
}
......@@ -18,7 +18,10 @@ import com.x.attendance.assemble.control.jaxrs.attendancestatistic.AttendanceSta
import com.x.attendance.assemble.control.jaxrs.attendancestatisticalcycle.AttendanceStatisticalCycleAction;
import com.x.attendance.assemble.control.jaxrs.attendancestatisticrequirelog.AttendanceStatisticRequireLogAction;
import com.x.attendance.assemble.control.jaxrs.attendanceworkdayconfig.AttendanceWorkDayConfigAction;
import com.x.attendance.assemble.control.jaxrs.dingding.DingdingAttendanceAction;
import com.x.attendance.assemble.control.jaxrs.dingdingstatistic.DingdingAttendanceStatisticAction;
import com.x.attendance.assemble.control.jaxrs.fileimport.AttendanceDetailFileImportAction;
import com.x.attendance.assemble.control.jaxrs.qywx.QywxAttendanceAction;
import com.x.attendance.assemble.control.jaxrs.selfholiday.AttendanceSelfHolidayAction;
import com.x.attendance.assemble.control.jaxrs.selfholiday.AttendanceSelfHolidaySimpleAction;
import com.x.attendance.assemble.control.jaxrs.uuid.UUIDAction;
......@@ -48,6 +51,9 @@ public class ActionApplication extends AbstractActionApplication {
this.classes.add(AttendanceStatisticalCycleAction.class);
this.classes.add(AttendanceEmployeeConfigAction.class);
this.classes.add(AttendanceStatisticRequireLogAction.class);
this.classes.add(DingdingAttendanceAction.class);
this.classes.add(QywxAttendanceAction.class);
this.classes.add(DingdingAttendanceStatisticAction.class);
return this.classes;
}
......
package com.x.attendance.assemble.control.jaxrs;
import com.x.base.core.project.jaxrs.CipherManagerJaxrsFilter;
import com.x.base.core.project.jaxrs.ManagerUserJaxrsFilter;
import javax.servlet.annotation.WebFilter;
@WebFilter(urlPatterns = "/jaxrs/dingding/*", asyncSupported = true)
public class DingdingJaxrsFilter extends CipherManagerJaxrsFilter {
public class DingdingJaxrsFilter extends ManagerUserJaxrsFilter {
}
package com.x.attendance.assemble.control.jaxrs;
import com.x.base.core.project.jaxrs.ManagerUserJaxrsFilter;
import javax.servlet.annotation.WebFilter;
@WebFilter(urlPatterns = "/jaxrs/dingdingstatistic/*", asyncSupported = true)
public class DingdingStatisticJaxrsFilter extends ManagerUserJaxrsFilter {
}
package com.x.attendance.assemble.control.jaxrs;
import com.x.base.core.project.jaxrs.CipherManagerJaxrsFilter;
import javax.servlet.annotation.WebFilter;
@WebFilter(urlPatterns = "/jaxrs/qywx/*", asyncSupported = true)
public class QywxJaxrsFilter extends CipherManagerJaxrsFilter {
}
package com.x.attendance.assemble.control.jaxrs.attendancesetting;
import com.x.base.core.project.config.Config;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.http.EffectivePerson;
import com.x.base.core.project.jaxrs.WrapString;
class ActionEnableType extends BaseAction {
public static final String TYPE_QIYEWEIXIN = "qywx";
public static final String TYPE_DINGDING = "dingding";
ActionResult<Wo> execute(EffectivePerson effectivePerson) throws Exception {
ActionResult<Wo> result = new ActionResult<>();
Wo wo = new Wo();
if (Config.qiyeweixin().getEnable() && Config.qiyeweixin().getAttendanceSyncEnable()) {
wo.setValue(TYPE_QIYEWEIXIN);
} else if (Config.dingding().getEnable() && Config.dingding().getAttendanceSyncEnable()) {
wo.setValue(TYPE_DINGDING);
} else {
wo.setValue("");
}
result.setData(wo);
return result;
}
public static class Wo extends WrapString {
}
}
......@@ -152,4 +152,22 @@ public class AttendanceSettingAction extends StandardJaxrsAction {
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "是否启用钉钉考勤或企业微信考勤", action = ActionEnableType.class)
@GET
@Path("enable/type")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void enableType(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request) {
ActionResult<ActionEnableType.Wo> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionEnableType().execute(effectivePerson);
} catch (Exception e) {
result = new ActionResult<>();
result.error(e);
logger.error(e, effectivePerson, request, null);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
}
\ No newline at end of file
......@@ -22,14 +22,14 @@ public class ActionDeleteAllData extends BaseAction {
ActionResult<WrapBoolean> result = new ActionResult<>();
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
List<AttendanceDingtalkDetail> details = emc.fetchAll(AttendanceDingtalkDetail.class);
List<AttendanceDingtalkDetail> details = emc.listAll(AttendanceDingtalkDetail.class);
if ( null == details ) {
result.error( new FindEmptyException() );
}else{
//进行数据库持久化操作
emc.beginTransaction( AttendanceDingtalkDetail.class );
for (AttendanceDingtalkDetail d : details) {
emc.remove(d, CheckRemoveType.all);
emc.remove(d);
}
emc.commit();
result.setData(new WrapBoolean(true));
......
package com.x.attendance.assemble.control.jaxrs.dingding;
import com.google.gson.JsonElement;
import com.x.attendance.assemble.control.Business;
import com.x.attendance.assemble.control.jaxrs.dingding.exception.SearchArgEmptyException;
import com.x.attendance.assemble.control.jaxrs.dingding.exception.TimeEmptyException;
import com.x.attendance.entity.AttendanceDingtalkDetail;
import com.x.attendance.entity.AttendanceDingtalkDetail_;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.annotation.FieldDescribe;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.gson.GsonPropertyObject;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.jaxrs.BetweenTerms;
import com.x.base.core.project.jaxrs.EqualsTerms;
import com.x.base.core.project.jaxrs.InTerms;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.organization.Person;
import com.x.base.core.project.tools.DateTools;
import com.x.base.core.project.tools.ListTools;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
public class ActionListDDAttendanceDetail extends BaseAction {
private static final Logger logger = LoggerFactory.getLogger(ActionListDDAttendanceDetail.class);
public ActionResult<List<Wo>> execute(String flag, Integer count, JsonElement jsonElement) throws Exception {
ActionResult<List<Wo>> result = new ActionResult<>();
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
Wi wi = this.convertToWrapIn(jsonElement , Wi.class);
logger.info("传入参数:"+wi.toString());
if (StringUtils.isEmpty(wi.getYear())) {
throw new TimeEmptyException();
}
if (StringUtils.isEmpty(wi.getPerson()) && StringUtils.isEmpty(wi.getUnit()) && StringUtils.isEmpty(wi.getTopUnit())) {
throw new SearchArgEmptyException();
}
Date startDay ;
Date endDay;
if (StringUtils.isEmpty(wi.getMonth())) {
startDay = getDay(wi.getYear(), "1", "1");
endDay = getDay(wi.getYear(), "12", "31");
}else {
if (StringUtils.isEmpty(wi.getDay())) {
startDay = getDay(wi.getYear(), wi.getMonth(), "1");
endDay = getMonthLastDay(wi.getYear(), wi.getMonth());
}else {
startDay = getDay(wi.getYear(), wi.getMonth(), wi.getDay());
endDay = getEndDay(wi.getYear(), wi.getMonth(), wi.getDay());
}
}
logger.info("startDay:"+DateTools.format(startDay));
logger.info("endDay:"+DateTools.format(endDay));
BetweenTerms betweenTerms = new BetweenTerms();
betweenTerms.put("userCheckTime", ListTools.toList(startDay.getTime(), endDay.getTime()));
logger.info("between :"+betweenTerms.toString());
String id = EMPTY_SYMBOL;
/** 如果不是空位标志位 */
if (!StringUtils.equals(EMPTY_SYMBOL, flag)) {
id = flag;
}
if (StringUtils.isNotEmpty(wi.getPerson())) {
EqualsTerms equals = new EqualsTerms();
equals.put("o2User", wi.getPerson());
if (isCheckTypeEnable(wi.getCheckType())){
equals.put("checkType", wi.getCheckType());
}
if (isTimeResultEnable(wi.getTimeResult())) {
equals.put("timeResult", wi.getTimeResult());
}
logger.info("equals :"+equals.toString());
result = this.standardListNext(Wo.copier, id, count, JpaObject.sequence_FIELDNAME, equals, null,
null, null, null, null, null, betweenTerms, true, DESC);
}
if (StringUtils.isNotEmpty(wi.getUnit())) {
EqualsTerms equals = new EqualsTerms();
equals.put("o2Unit", wi.getUnit());
if (isCheckTypeEnable(wi.getCheckType())){
equals.put("checkType", wi.getCheckType());
}
if (isTimeResultEnable(wi.getTimeResult())) {
equals.put("timeResult", wi.getTimeResult());
}
logger.info("equals :"+equals.toString());
result = this.standardListNext(Wo.copier, id, count, JpaObject.sequence_FIELDNAME, equals, null,
null, null, null, null, null, betweenTerms, true, DESC);
}
if (StringUtils.isNotEmpty(wi.getTopUnit())) {
EqualsTerms equals = new EqualsTerms();
if (isCheckTypeEnable(wi.getCheckType())){
equals.put("checkType", wi.getCheckType());
}
if (isTimeResultEnable(wi.getTimeResult())) {
equals.put("timeResult", wi.getTimeResult());
}
InTerms ins = new InTerms();
List<String> subUnits = business.organization().unit().listWithUnitSubNested( wi.getTopUnit() );
if (subUnits == null || subUnits.isEmpty()) {
subUnits = new ArrayList<>();
}
subUnits.add(wi.getTopUnit());
ins.put("o2Unit", subUnits);
logger.info("ins :"+ins.toString());
result = this.standardListNext(Wo.copier, id, count, JpaObject.sequence_FIELDNAME, equals, null,
null, ins, null, null, null, betweenTerms, true, DESC);
}
}
return result;
}
private boolean isCheckTypeEnable(String type) {
if (StringUtils.isEmpty(type) || (!AttendanceDingtalkDetail.OffDuty.equals(type) && !AttendanceDingtalkDetail.OnDuty.equals(type))) {
return false;
}
return true;
}
private boolean isTimeResultEnable(String result) {
if (StringUtils.isEmpty(result) ||
(!AttendanceDingtalkDetail.TIMERESULT_Absenteeism.equals(result)
&& !AttendanceDingtalkDetail.TIMERESULT_Early.equals(result)
&& !AttendanceDingtalkDetail.TIMERESULT_Late.equals(result)
&& !AttendanceDingtalkDetail.TIMERESULT_NORMAL.equals(result)
&& !AttendanceDingtalkDetail.TIMERESULT_NotSigned.equals(result)
&& !AttendanceDingtalkDetail.TIMERESULT_SeriousLate.equals(result))) {
return false;
}
return true;
}
public static Date getMonthLastDay(String year, String month) throws Exception {
Calendar cal = Calendar.getInstance();
int yearInt = Integer.parseInt(year);
cal.set(Calendar.YEAR, yearInt);
int monthInt = Integer.parseInt(month);
cal.set(Calendar.MONTH, monthInt);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 0);
cal.add(Calendar.DAY_OF_MONTH, -1);
return cal.getTime();
}
public static Date getDay(String year, String month, String day) throws Exception {
Calendar cal = Calendar.getInstance();
int yearInt = Integer.parseInt(year);
cal.set(Calendar.YEAR, yearInt);
int monthInt = Integer.parseInt(month);
cal.set(Calendar.MONTH, monthInt-1);
int dayInt = Integer.parseInt(day);
cal.set(Calendar.DATE, dayInt);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime();
}
public static Date getEndDay(String year, String month, String day) throws Exception {
Calendar cal = Calendar.getInstance();
int yearInt = Integer.parseInt(year);
cal.set(Calendar.YEAR, yearInt);
int monthInt = Integer.parseInt(month);
cal.set(Calendar.MONTH, monthInt-1);
int dayInt = Integer.parseInt(day);
cal.set(Calendar.DATE, dayInt);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime();
}
public static class Wi extends GsonPropertyObject {
@FieldDescribe("年份")
private String year;
@FieldDescribe("月份")
private String month;
@FieldDescribe("日期")
private String day;
@FieldDescribe("人员")
private String person;
@FieldDescribe("部门")
private String unit;
@FieldDescribe("顶级部门,会及联查询下级部门")
private String topUnit;
@FieldDescribe("打卡类型:OffDuty|OnDuty")
private String checkType;
@FieldDescribe("打卡结果:Normal|Early|Late|SeriousLate|Absenteeism|NotSigned")
private String timeResult;
public String getCheckType() {
return checkType;
}
public void setCheckType(String checkType) {
this.checkType = checkType;
}
public String getTimeResult() {
return timeResult;
}
public void setTimeResult(String timeResult) {
this.timeResult = timeResult;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public String getMonth() {
return month;
}
public void setMonth(String month) {
this.month = month;
}
public String getDay() {
return day;
}
public void setDay(String day) {
this.day = day;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
public String getPerson() {
return person;
}
public void setPerson(String person) {
this.person = person;
}
public String getTopUnit() {
return topUnit;
}
public void setTopUnit(String topUnit) {
this.topUnit = topUnit;
}
}
public static class Wo extends AttendanceDingtalkDetail {
static final WrapCopier<AttendanceDingtalkDetail, Wo> copier =
WrapCopierFactory.wo(AttendanceDingtalkDetail.class, Wo.class, null, JpaObject.FieldsInvisible);
@FieldDescribe("实际打卡时间")
private Date userCheckTimeFormat;
@FieldDescribe("工作日")
private Date workDateFormat;
@FieldDescribe("基准时间,用于计算迟到和早退")
private Date baseCheckTimeFormat;
@FieldDescribe("排序号")
private Long rank;
public void formatDateTime() {
if (userCheckTimeFormat == null) {
Date date = new Date();
date.setTime(getUserCheckTime());
setUserCheckTimeFormat(date);
}
if (workDateFormat == null) {
Date date = new Date();
date.setTime(getWorkDate());
setWorkDateFormat(date);
}
if (baseCheckTimeFormat == null) {
Date date = new Date();
date.setTime(getBaseCheckTime());
setBaseCheckTimeFormat(date);
}
}
public Long getRank() {
return rank;
}
public void setRank(Long rank) {
this.rank = rank;
}
public Date getUserCheckTimeFormat() {
return userCheckTimeFormat;
}
public void setUserCheckTimeFormat(Date userCheckTimeFormat) {
this.userCheckTimeFormat = userCheckTimeFormat;
}
public Date getWorkDateFormat() {
return workDateFormat;
}
public void setWorkDateFormat(Date workDateFormat) {
this.workDateFormat = workDateFormat;
}
public Date getBaseCheckTimeFormat() {
return baseCheckTimeFormat;
}
public void setBaseCheckTimeFormat(Date baseCheckTimeFormat) {
this.baseCheckTimeFormat = baseCheckTimeFormat;
}
}
}
package com.x.attendance.assemble.control.jaxrs.dingding;
import com.x.attendance.assemble.control.Business;
import com.x.attendance.entity.DingdingQywxSyncRecord;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.annotation.FieldDescribe;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
public class ActionListDingdingSyncRecord extends BaseAction {
private static final Logger logger = LoggerFactory.getLogger(ActionListDingdingSyncRecord.class);
public ActionResult<List<Wo>> execute() throws Exception {
ActionResult<List<Wo>> result = new ActionResult<>();
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
List<DingdingQywxSyncRecord> list = business.dingdingAttendanceFactory().findAllSyncRecordWithType(DingdingQywxSyncRecord.syncType_dingding);
if (list != null && !list.isEmpty()) {
List<Wo> wos = list.stream().map(record -> {
Wo wo = new Wo();
try {
wo = Wo.copier.copy(record, wo);
wo.formatDate();
}catch (Exception e) {
logger.error(e);
}
return wo;
}).collect(Collectors.toList());
result.setData(wos);
}
}
return result;
}
public static class Wo extends DingdingQywxSyncRecord {
static final WrapCopier<DingdingQywxSyncRecord, Wo> copier =
WrapCopierFactory.wo(DingdingQywxSyncRecord.class, Wo.class, null, JpaObject.FieldsInvisible);
@FieldDescribe("同步打卡记录的开始时间")
private Date dateFromFormat;
@FieldDescribe("同步打卡记录的结束时间")
private Date dateToFormat;
public void formatDate() {
Date date = new Date();
date.setTime(getDateFrom());
setDateFromFormat(date);
Date dateto = new Date();
dateto.setTime(getDateTo());
setDateToFormat(dateto);
}
public Date getDateFromFormat() {
return dateFromFormat;
}
public void setDateFromFormat(Date dateFromFormat) {
this.dateFromFormat = dateFromFormat;
}
public Date getDateToFormat() {
return dateToFormat;
}
public void setDateToFormat(Date dateToFormat) {
this.dateToFormat = dateToFormat;
}
}
}
package com.x.attendance.assemble.control.jaxrs.dingding;
import com.x.attendance.assemble.control.ThisApplication;
import com.x.attendance.assemble.control.jaxrs.dingding.exception.SearchArgEmptyException;
import com.x.attendance.assemble.control.jaxrs.dingdingstatistic.BaseAction;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.jaxrs.WrapBoolean;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.tools.DateTools;
import org.apache.commons.lang3.StringUtils;
import java.util.Date;
/**
* Created by fancyLou on 2020-04-05.
* Copyright © 2020 O2. All rights reserved.
*/
public class ActionStatisticPersonMonthData extends BaseAction {
private static final Logger logger = LoggerFactory.getLogger(ActionStatisticPersonMonthData.class);
ActionResult<WrapBoolean> execute(String year, String month) throws Exception{
ActionResult<WrapBoolean> result = new ActionResult<WrapBoolean>();
if (StringUtils.isEmpty(year) || StringUtils.isEmpty(month)) {
throw new SearchArgEmptyException();
}
logger.info("开始执行全部人员考勤信息统计 year:"+year+", month:"+month);
Date date = DateTools.parse(year+"-"+month+"-01");
ThisApplication.personStatisticQueue.send(date);
result.setData(new WrapBoolean(true));
return result;
}
}
package com.x.attendance.assemble.control.jaxrs.dingding;
import com.x.attendance.assemble.control.ThisApplication;
import com.x.attendance.assemble.control.jaxrs.dingding.exception.SearchArgEmptyException;
import com.x.attendance.assemble.control.jaxrs.dingdingstatistic.BaseAction;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.jaxrs.WrapBoolean;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.tools.DateTools;
import org.apache.commons.lang3.StringUtils;
import java.util.Date;
/**
* Created by fancyLou on 2020-04-05.
* Copyright © 2020 O2. All rights reserved.
*/
public class ActionStatisticUnitDayData extends BaseAction {
private static final Logger logger = LoggerFactory.getLogger(ActionStatisticUnitDayData.class);
ActionResult<WrapBoolean> execute(String year, String month, String day) throws Exception{
ActionResult<WrapBoolean> result = new ActionResult<WrapBoolean>();
if (StringUtils.isEmpty(year) || StringUtils.isEmpty(month) || StringUtils.isEmpty(day)) {
throw new SearchArgEmptyException();
}
logger.info("开始执行全部部门考勤信息统计 year:"+year+", month:"+month);
Date date = DateTools.parse(year+"-"+month+"-"+day);
ThisApplication.unitStatisticQueue.send(date);
result.setData(new WrapBoolean(true));
return result;
}
}
package com.x.attendance.assemble.control.jaxrs.dingding;
import com.google.gson.JsonElement;
import com.x.attendance.assemble.control.Business;
import com.x.attendance.assemble.control.ThisApplication;
import com.x.attendance.entity.DingdingQywxSyncRecord;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.http.EffectivePerson;
import com.x.base.core.project.jaxrs.WrapBoolean;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.tools.DateTools;
import java.util.Date;
import java.util.List;
public class ActionSyncData extends BaseAction {
private static final Logger logger = LoggerFactory.getLogger(ActionSyncData.class);
public ActionResult<WrapBoolean> execute(EffectivePerson effectivePerson, JsonElement jsonElement) throws Exception {
public ActionResult<WrapBoolean> execute(EffectivePerson effectivePerson, String dateFrom, String dateTo) throws Exception {
ActionResult<WrapBoolean> result = new ActionResult<>();
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Wi wi = this.convertToWrapIn(jsonElement, Wi.class);
if (null == wi.getWay() ||
(!DingdingQywxSyncRecord.syncWay_week.equals(wi.getWay()) && !DingdingQywxSyncRecord.syncWay_year.equals(wi.getWay()))) {
if (null == dateFrom || null == dateTo) {
throw new SyncWayException();
}
Date from = DateTools.parse(dateFrom);
Date to = DateTools.parse(dateTo);
long gap = to.getTime() - from.getTime();
if (gap < 0) {
throw new SyncWayException();
}
if ((gap / (1000 * 60 * 60 * 24)) > 6 ) {
throw new MoreThanSevenDayException();
}
// Business business = new Business(emc);
// List<DingdingQywxSyncRecord> conflictList = business.dingdingAttendanceFactory().findConflictSyncRecord(from.getTime(), to.getTime());
// if (conflictList != null && !conflictList.isEmpty()) {
// throw new ConflictSyncRecordException();
// }
DingdingQywxSyncRecord record = new DingdingQywxSyncRecord();
record.setWay(wi.getWay());
record.setDateFrom(from.getTime());
record.setDateTo(to.getTime());
record.setStartTime(new Date());
record.setType(DingdingQywxSyncRecord.syncType_dingding);
record.setStatus(DingdingQywxSyncRecord.status_loading);
emc.beginTransaction(DingdingQywxSyncRecord.class);
emc.persist(record);
emc.commit();
ThisApplication.dingdingQueue.executing(record);
ThisApplication.dingdingQueue.send(record);
result.setData(new WrapBoolean(true));
}
return result;
}
public static class Wi extends DingdingQywxSyncRecord {
public static WrapCopier<Wi, DingdingQywxSyncRecord> copier = WrapCopierFactory.wi(Wi.class,
DingdingQywxSyncRecord.class, null, JpaObject.FieldsUnmodify);
}
}
package com.x.attendance.assemble.control.jaxrs.dingding;
import com.x.base.core.project.exception.PromptException;
public class ConflictSyncRecordException extends PromptException {
private static final long serialVersionUID = 7077761236199564642L;
public ConflictSyncRecordException() {
super("同步时间和历史有冲突!");
}
}
......@@ -3,6 +3,7 @@ package com.x.attendance.assemble.control.jaxrs.dingding;
import com.google.gson.JsonElement;
import com.x.base.core.project.annotation.JaxrsDescribe;
import com.x.base.core.project.annotation.JaxrsMethodDescribe;
import com.x.base.core.project.annotation.JaxrsParameterDescribe;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.http.EffectivePerson;
import com.x.base.core.project.http.HttpMediaType;
......@@ -18,6 +19,7 @@ import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.util.List;
@Path("dingding")
......@@ -47,20 +49,77 @@ public class DingdingAttendanceAction extends StandardJaxrsAction {
}
//获取一年的数据 ???不知道是否能成 接口限制
//获取7天数据 可以做定时每天晚上更新
//
@JaxrsMethodDescribe(value = "同步钉钉考勤结果", action = ActionSyncData.class)
@POST
@Path("sync")
@GET
@Path("sync/from/{dateFrom}/to/{dateTo}/start")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void syncData(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
JsonElement jsonElement) {
@JaxrsParameterDescribe("开始时间: yyyy-MM-dd") @PathParam("dateFrom") String dateFrom,
@JaxrsParameterDescribe("结束时间: yyyy-MM-dd") @PathParam("dateTo") String dateTo) {
ActionResult<WrapBoolean> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionSyncData().execute(effectivePerson, dateFrom, dateTo);
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "查询钉钉同步记录信息", action = ActionListDingdingSyncRecord.class)
@GET
@Path("sync/list")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void listDingdingSyncRecord(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request) {
ActionResult<List<ActionListDingdingSyncRecord.Wo>> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionListDingdingSyncRecord().execute();
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "查询钉钉打卡结果", action = ActionListDDAttendanceDetail.class)
@PUT
@Path("attendance/list/{id}/next/{count}")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void listNextDingdingAttendance(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
@JaxrsParameterDescribe("最后一条数据ID") @PathParam("id") String id,
@JaxrsParameterDescribe("每页显示的条目数量") @PathParam("count") Integer count,
JsonElement jsonElement) {
ActionResult<List<ActionListDDAttendanceDetail.Wo>> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionListDDAttendanceDetail().execute(id, count, jsonElement);
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "钉钉考勤全部个人数据统计", action = ActionStatisticPersonMonthData.class)
@GET
@Path("statistic/person/year/{year}/month/{month}")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void statisticPerson(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
@JaxrsParameterDescribe("年份: yyyy") @PathParam("year") String year,
@JaxrsParameterDescribe("月份: MM") @PathParam("month") String month) {
ActionResult<WrapBoolean> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionSyncData().execute(effectivePerson, jsonElement);
result = new ActionStatisticPersonMonthData().execute(year, month);
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
......@@ -69,5 +128,24 @@ public class DingdingAttendanceAction extends StandardJaxrsAction {
}
@JaxrsMethodDescribe(value = "钉钉考勤全部组织数据统计", action = ActionStatisticUnitDayData.class)
@GET
@Path("statistic/unit/year/{year}/month/{month}/day/{day}")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void statisticUnit(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
@JaxrsParameterDescribe("年份: yyyy") @PathParam("year") String year,
@JaxrsParameterDescribe("月份: MM") @PathParam("month") String month,
@JaxrsParameterDescribe("日期: dd") @PathParam("day") String day) {
ActionResult<WrapBoolean> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionStatisticUnitDayData().execute(year, month, day);
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
}
package com.x.attendance.assemble.control.jaxrs.dingding;
import com.x.base.core.project.exception.PromptException;
public class MoreThanSevenDayException extends PromptException {
private static final long serialVersionUID = 7077761236199564642L;
public MoreThanSevenDayException() {
super("同步时间间隔大于7天!");
}
}
......@@ -6,6 +6,6 @@ public class SyncWayException extends PromptException {
private static final long serialVersionUID = -6072567404702590349L;
public SyncWayException() {
super("同步方式不正确!");
super("传入的同步时间不正确!");
}
}
package com.x.attendance.assemble.control.jaxrs.dingding.exception;
import com.x.base.core.project.exception.PromptException;
/**
* Created by fancyLou on 2020-04-01.
* Copyright © 2020 O2. All rights reserved.
*/
public class SearchArgEmptyException extends PromptException {
public SearchArgEmptyException() {
super("传入参数不正确!");
}
}
package com.x.attendance.assemble.control.jaxrs.dingding.exception;
import com.x.base.core.project.exception.PromptException;
/**
* Created by fancyLou on 2020-04-01.
* Copyright © 2020 O2. All rights reserved.
*/
public class TimeEmptyException extends PromptException {
public TimeEmptyException() {
super("传入的时间参数不正确!");
}
}
package com.x.attendance.assemble.control.jaxrs.dingdingstatistic;
import com.x.attendance.assemble.control.Business;
import com.x.attendance.entity.StatisticDingdingPersonForMonth;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.http.ActionResult;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
/**
* Created by fancyLou on 2020-04-07.
* Copyright © 2020 O2. All rights reserved.
*/
public class ActionPersonStatistic extends BaseAction {
ActionResult<List<Wo>> execute(String person, String year, String month) throws Exception {
ActionResult<List<Wo>> result = new ActionResult<>();
if (StringUtils.isEmpty(person) || StringUtils.isEmpty(year) || StringUtils.isEmpty(month)) {
throw new EmptyArgsException();
}
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
List<StatisticDingdingPersonForMonth> list = business.dingdingAttendanceFactory().findPersonStatistic(person, year, month);
result.setData(Wo.copier.copy(list));
}
return result;
}
public static class Wo extends StatisticDingdingPersonForMonth {
static final WrapCopier<StatisticDingdingPersonForMonth, Wo> copier = WrapCopierFactory.wo(StatisticDingdingPersonForMonth.class, Wo.class,
null, JpaObject.FieldsInvisible);
}
}
package com.x.attendance.assemble.control.jaxrs.dingdingstatistic;
import com.x.attendance.assemble.control.Business;
import com.x.attendance.entity.StatisticDingdingPersonForMonth;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.http.ActionResult;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
/**
* Created by fancyLou on 2020-04-07.
* Copyright © 2020 O2. All rights reserved.
*/
public class ActionPersonStatisticWithUnit extends BaseAction {
ActionResult<List<Wo>> execute(String unit, String year, String month) throws Exception {
ActionResult<List<Wo>> result = new ActionResult<>();
if (StringUtils.isEmpty(unit) || StringUtils.isEmpty(year) || StringUtils.isEmpty(month)) {
throw new EmptyArgsException();
}
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
List<StatisticDingdingPersonForMonth> list = business.dingdingAttendanceFactory().findPersonStatisticWithUnit(unit, year, month);
result.setData(Wo.copier.copy(list));
}
return result;
}
public static class Wo extends StatisticDingdingPersonForMonth {
static final WrapCopier<StatisticDingdingPersonForMonth, Wo> copier = WrapCopierFactory.wo(StatisticDingdingPersonForMonth.class, Wo.class,
null, JpaObject.FieldsInvisible);
}
}
package com.x.attendance.assemble.control.jaxrs.dingdingstatistic;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.jaxrs.WrapBoolean;
/**
* Created by fancyLou on 2020-04-05.
* Copyright © 2020 O2. All rights reserved.
*/
public class ActionTest extends BaseAction {
ActionResult<WrapBoolean> execute() throws Exception {
return new ActionResult<>();
}
}
package com.x.attendance.assemble.control.jaxrs.dingdingstatistic;
import com.x.attendance.assemble.control.Business;
import com.x.attendance.entity.StatisticDingdingUnitForMonth;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.http.ActionResult;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
/**
* Created by fancyLou on 2020-04-07.
* Copyright © 2020 O2. All rights reserved.
*/
public class ActionUnitStatistic extends BaseAction {
ActionResult<Wo> execute(String unit, String year, String month) throws Exception {
ActionResult<Wo> result = new ActionResult<>();
if (StringUtils.isEmpty(unit) || StringUtils.isEmpty(year) || StringUtils.isEmpty(month)) {
throw new EmptyArgsException();
}
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
List<StatisticDingdingUnitForMonth> list = business.dingdingAttendanceFactory().findUnitStatistic(unit, year, month);
if (list!=null && !list.isEmpty()) {
result.setData(Wo.copier.copy(list.get(0)));
}else {
result.setData(new Wo());
}
}
return result;
}
public static class Wo extends StatisticDingdingUnitForMonth {
static final WrapCopier<StatisticDingdingUnitForMonth, Wo> copier = WrapCopierFactory.wo(StatisticDingdingUnitForMonth.class, Wo.class,
null, JpaObject.FieldsInvisible);
}
}
package com.x.attendance.assemble.control.jaxrs.dingdingstatistic;
import com.x.base.core.project.jaxrs.StandardJaxrsAction;
public class BaseAction extends StandardJaxrsAction {
}
package com.x.attendance.assemble.control.jaxrs.dingdingstatistic;
import com.x.base.core.project.annotation.JaxrsDescribe;
import com.x.base.core.project.annotation.JaxrsMethodDescribe;
import com.x.base.core.project.annotation.JaxrsParameterDescribe;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.http.EffectivePerson;
import com.x.base.core.project.http.HttpMediaType;
import com.x.base.core.project.jaxrs.ResponseFactory;
import com.x.base.core.project.jaxrs.StandardJaxrsAction;
import com.x.base.core.project.jaxrs.WrapBoolean;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.util.List;
/**
* Created by fancyLou on 2020-04-05.
* Copyright © 2020 O2. All rights reserved.
*/
@Path("dingdingstatistic")
@JaxrsDescribe("钉钉打卡数据统计管理")
public class DingdingAttendanceStatisticAction extends StandardJaxrsAction {
private static final Logger logger = LoggerFactory.getLogger(DingdingAttendanceStatisticAction.class);
@JaxrsMethodDescribe(value = "测试", action = ActionTest.class)
@GET
@Path("demo")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void syncData(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request) {
ActionResult<WrapBoolean> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionTest().execute();
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "人员月份统计查询", action = ActionPersonStatistic.class)
@GET
@Path("person/{person}/{year}/{month}")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void personMonth(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
@JaxrsParameterDescribe("人员") @PathParam("person") String person,
@JaxrsParameterDescribe("年份: yyyy") @PathParam("year") String year,
@JaxrsParameterDescribe("月份: MM") @PathParam("month") String month) {
ActionResult<List<ActionPersonStatistic.Wo>> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionPersonStatistic().execute(person, year, month);
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "根据部门查询人员月份统计", action = ActionPersonStatisticWithUnit.class)
@GET
@Path("person/unit/{unit}/{year}/{month}")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void personMonthWithUnit(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
@JaxrsParameterDescribe("部门") @PathParam("unit") String unit,
@JaxrsParameterDescribe("年份: yyyy") @PathParam("year") String year,
@JaxrsParameterDescribe("月份: MM") @PathParam("month") String month) {
ActionResult<List<ActionPersonStatisticWithUnit.Wo>> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionPersonStatisticWithUnit().execute(unit, year, month);
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "部门月份统计查询", action = ActionUnitStatistic.class)
@GET
@Path("unit/{unit}/{year}/{month}")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void unitMonth(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
@JaxrsParameterDescribe("部门") @PathParam("unit") String unit,
@JaxrsParameterDescribe("年份: yyyy") @PathParam("year") String year,
@JaxrsParameterDescribe("月份: MM") @PathParam("month") String month) {
ActionResult<ActionUnitStatistic.Wo> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionUnitStatistic().execute(unit, year, month);
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
}
package com.x.attendance.assemble.control.jaxrs.dingdingstatistic;
import com.x.base.core.project.exception.PromptException;
/**
* Created by fancyLou on 2020-04-07.
* Copyright © 2020 O2. All rights reserved.
*/
public class EmptyArgsException extends PromptException {
public EmptyArgsException() {
super("传入参数不能为空!");
}
}
package com.x.attendance.assemble.control.jaxrs.qywx;
import com.x.attendance.entity.AttendanceQywxDetail;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.http.EffectivePerson;
import com.x.base.core.project.jaxrs.WrapBoolean;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import java.util.List;
public class ActionDeleteAllQywxAttendanceData extends BaseAction {
private static final Logger logger = LoggerFactory.getLogger(ActionDeleteAllQywxAttendanceData.class);
public ActionResult<WrapBoolean> execute(EffectivePerson effectivePerson) {
ActionResult<WrapBoolean> result = new ActionResult<>();
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
List<AttendanceQywxDetail> details = emc.listAll(AttendanceQywxDetail.class);
if ( null != details && !details.isEmpty() ) {
//进行数据库持久化操作
emc.beginTransaction( AttendanceQywxDetail.class );
for (AttendanceQywxDetail d : details) {
emc.remove(d);
}
emc.commit();
logger.info( "成功删除所有的企业微信打卡数据信息" );
}
result.setData(new WrapBoolean(true));
} catch ( Exception e ) {
result.error(e);
logger.error(e);
}
return result;
}
}
package com.x.attendance.assemble.control.jaxrs.qywx;
import com.google.gson.JsonElement;
import com.x.attendance.assemble.control.Business;
import com.x.attendance.assemble.control.jaxrs.dingding.BaseAction;
import com.x.attendance.entity.AttendanceQywxDetail;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.annotation.FieldDescribe;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.gson.GsonPropertyObject;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.organization.Person;
import com.x.base.core.project.tools.DateTools;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
public class ActionListQywxAttendanceDetail extends BaseAction {
private static final Logger logger = LoggerFactory.getLogger(ActionListQywxAttendanceDetail.class);
public ActionResult<List<Wo>> execute(JsonElement jsonElement) throws Exception {
ActionResult<List<Wo>> result = new ActionResult<>();
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
Wi wi = this.convertToWrapIn(jsonElement , Wi.class);
Date start = DateTools.parseDateTime(wi.getStartTime());
Date end = DateTools.parseDateTime(wi.getEndTime());
String qywxUser = null;
//转化成企业微信的id
if (wi.getPerson() != null && !wi.getPerson().isEmpty()) {
Person person = business.organization().person().getObject(wi.getPerson());
qywxUser = person.getQiyeweixinId();
}
List<AttendanceQywxDetail> list = business.dingdingAttendanceFactory().findQywxAttendanceDetail(start, end, qywxUser);
if (list != null && !list.isEmpty()) {
List<Wo> wos = list.stream().map(detail -> {
Wo wo = new Wo();
try {
wo = Wo.copier.copy(detail, wo);
wo.formatDateTime();
}catch (Exception e) {
logger.error(e);
}
return wo;
}).collect(Collectors.toList());
result.setData(wos);
}
}
return result;
}
public static class Wi extends GsonPropertyObject {
@FieldDescribe("开始时间:yyyy-MM-dd HH:mm:ss")
private String startTime;
@FieldDescribe("结束时间:yyyy-MM-dd HH:mm:ss")
private String endTime;
@FieldDescribe("人员")
private String person;
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
public String getPerson() {
return person;
}
public void setPerson(String person) {
this.person = person;
}
}
public static class Wo extends AttendanceQywxDetail {
static final WrapCopier<AttendanceQywxDetail, Wo> copier =
WrapCopierFactory.wo(AttendanceQywxDetail.class, Wo.class, null, JpaObject.FieldsInvisible);
@FieldDescribe("实际打卡时间")
private Date checkTimeFormat;
public void formatDateTime() {
if (checkTimeFormat == null) {
Date date = new Date();
date.setTime(getCheckin_time());
setCheckTimeFormat(date);
}
}
public Date getCheckTimeFormat() {
return checkTimeFormat;
}
public void setCheckTimeFormat(Date checkTimeFormat) {
this.checkTimeFormat = checkTimeFormat;
}
}
}
package com.x.attendance.assemble.control.jaxrs.qywx;
import com.x.attendance.assemble.control.Business;
import com.x.attendance.assemble.control.jaxrs.dingding.BaseAction;
import com.x.attendance.entity.DingdingQywxSyncRecord;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.annotation.FieldDescribe;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
public class ActionListQywxSyncRecord extends BaseAction {
private static final Logger logger = LoggerFactory.getLogger(ActionListQywxSyncRecord.class);
public ActionResult<List<Wo>> execute() throws Exception {
ActionResult<List<Wo>> result = new ActionResult<>();
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
List<DingdingQywxSyncRecord> list = business.dingdingAttendanceFactory().findAllSyncRecordWithType(DingdingQywxSyncRecord.syncType_qywx);
if (list != null && !list.isEmpty()) {
List<Wo> wos = list.stream().map(record -> {
Wo wo = new Wo();
try {
wo = Wo.copier.copy(record, wo);
wo.formatDate();
}catch (Exception e) {
logger.error(e);
}
return wo;
}).collect(Collectors.toList());
result.setData(wos);
}
}
return result;
}
public static class Wo extends DingdingQywxSyncRecord {
static final WrapCopier<DingdingQywxSyncRecord, Wo> copier =
WrapCopierFactory.wo(DingdingQywxSyncRecord.class, Wo.class, null, JpaObject.FieldsInvisible);
@FieldDescribe("同步打卡记录的开始时间")
private Date dateFromFormat;
@FieldDescribe("同步打卡记录的结束时间")
private Date dateToFormat;
public void formatDate() {
if (dateFromFormat == null) {
Date date = new Date();
date.setTime(getDateFrom());
setDateFromFormat(date);
}
if (dateToFormat == null) {
Date dateto = new Date();
dateto.setTime(getDateTo());
setDateToFormat(dateto);
}
}
public Date getDateFromFormat() {
return dateFromFormat;
}
public void setDateFromFormat(Date dateFromFormat) {
this.dateFromFormat = dateFromFormat;
}
public Date getDateToFormat() {
return dateToFormat;
}
public void setDateToFormat(Date dateToFormat) {
this.dateToFormat = dateToFormat;
}
}
}
package com.x.attendance.assemble.control.jaxrs.qywx;
import com.x.attendance.assemble.control.ThisApplication;
import com.x.attendance.assemble.control.jaxrs.dingding.MoreThanSevenDayException;
import com.x.attendance.entity.DingdingQywxSyncRecord;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.http.EffectivePerson;
import com.x.base.core.project.jaxrs.WrapBoolean;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.tools.DateTools;
import java.util.Date;
public class ActionSyncQywxData extends BaseAction {
private static final Logger logger = LoggerFactory.getLogger(ActionSyncQywxData.class);
public ActionResult<WrapBoolean> execute(EffectivePerson effectivePerson, String dateFrom, String dateTo) throws Exception {
ActionResult<WrapBoolean> result = new ActionResult<>();
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
if (null == dateFrom || null == dateTo) {
throw new SyncDateException();
}
Date from = DateTools.parse(dateFrom);
Date to = DateTools.parse(dateTo);
long gap = to.getTime() - from.getTime();
if (gap < 0) {
throw new SyncDateException();
}
if ((gap / (1000 * 60 * 60 * 24)) > 6 ) {
throw new MoreThanSevenDayException();
}
Date wxTo = DateTools.parse(dateTo+" 23:59:59");//企业微信和钉钉查询时间不一样
DingdingQywxSyncRecord record = new DingdingQywxSyncRecord();
record.setDateFrom(from.getTime());
record.setDateTo(wxTo.getTime());
record.setStartTime(new Date());
record.setType(DingdingQywxSyncRecord.syncType_qywx);
record.setStatus(DingdingQywxSyncRecord.status_loading);
emc.beginTransaction(DingdingQywxSyncRecord.class);
emc.persist(record);
emc.commit();
//企业微信的处理队列
ThisApplication.qywxQueue.send(record);
result.setData(new WrapBoolean(true));
}
return result;
}
}
package com.x.attendance.assemble.control.jaxrs.qywx;
import com.x.base.core.project.jaxrs.StandardJaxrsAction;
public class BaseAction extends StandardJaxrsAction {
}
package com.x.attendance.assemble.control.jaxrs.qywx;
import com.google.gson.JsonElement;
import com.x.base.core.project.annotation.JaxrsDescribe;
import com.x.base.core.project.annotation.JaxrsMethodDescribe;
import com.x.base.core.project.annotation.JaxrsParameterDescribe;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.http.EffectivePerson;
import com.x.base.core.project.http.HttpMediaType;
import com.x.base.core.project.jaxrs.ResponseFactory;
import com.x.base.core.project.jaxrs.StandardJaxrsAction;
import com.x.base.core.project.jaxrs.WrapBoolean;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.Suspended;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.util.List;
@Path("qywx")
@JaxrsDescribe("企业微信打卡数据管理")
public class QywxAttendanceAction extends StandardJaxrsAction {
private static final Logger logger = LoggerFactory.getLogger(QywxAttendanceAction.class);
//删除所有打卡数据
@JaxrsMethodDescribe(value = "删除所有打卡数据", action = ActionDeleteAllQywxAttendanceData.class)
@DELETE
@Path("all")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void deleteAllData(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request) {
ActionResult<WrapBoolean> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionDeleteAllQywxAttendanceData().execute(effectivePerson);
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
//
@JaxrsMethodDescribe(value = "同步企业微信考勤结果", action = ActionSyncQywxData.class)
@GET
@Path("sync/from/{dateFrom}/to/{dateTo}/start")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void syncData(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
@JaxrsParameterDescribe("开始时间: yyyy-MM-dd") @PathParam("dateFrom") String dateFrom,
@JaxrsParameterDescribe("结束时间: yyyy-MM-dd") @PathParam("dateTo") String dateTo) {
ActionResult<WrapBoolean> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionSyncQywxData().execute(effectivePerson, dateFrom, dateTo);
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "查询企业微信同步记录信息", action = ActionListQywxSyncRecord.class)
@GET
@Path("sync/list")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void listDingdingSyncRecord(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request) {
ActionResult<List<ActionListQywxSyncRecord.Wo>> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionListQywxSyncRecord().execute();
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "查询企业微信打卡结果", action = ActionListQywxAttendanceDetail.class)
@PUT
@Path("attendance/list")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void listDingdingAttendance(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request, JsonElement jsonElement) {
ActionResult<List<ActionListQywxAttendanceDetail.Wo>> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionListQywxAttendanceDetail().execute(jsonElement);
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
}
package com.x.attendance.assemble.control.jaxrs.qywx;
import com.x.base.core.project.exception.PromptException;
public class SyncDateException extends PromptException {
private static final long serialVersionUID = -6409463169780597687L;
public SyncDateException() {
super("传入的同步时间不正确!");
}
}
package com.x.attendance.assemble.control.schedule;
import com.x.attendance.assemble.control.ThisApplication;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.schedule.AbstractJob;
import com.x.base.core.project.tools.DateTools;
import org.quartz.JobExecutionContext;
import java.util.Date;
/**
* 钉钉考勤结果统计定时器
* 每天晚上3点定时处理钉钉考勤的个人统计数据
* Created by fancyLou on 2020-04-05.
* Copyright © 2020 O2. All rights reserved.
*/
public class DingdingAttendanceStatisticPersonScheduleTask extends AbstractJob {
private static final Logger logger = LoggerFactory.getLogger(DingdingAttendanceStatisticPersonScheduleTask.class);
@Override
public void schedule(JobExecutionContext jobExecutionContext) throws Exception {
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
logger.info("开始执行钉钉考勤统计的程序。。。。。。。。。。。。。。。。。。。。。");
//前一天 0点到23点
Date from = new Date();
from = DateTools.addDay(from, -1);//前面一天
ThisApplication.personStatisticQueue.send(from);
}
}
}
package com.x.attendance.assemble.control.schedule;
import com.x.attendance.assemble.control.ThisApplication;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.schedule.AbstractJob;
import com.x.base.core.project.tools.DateTools;
import org.quartz.JobExecutionContext;
import java.util.Date;
/**
* 钉钉考勤结果统计定时器
* 每天晚上3点定时处理钉钉考勤的统计数据
* Created by fancyLou on 2020-04-03.
* Copyright © 2020 O2. All rights reserved.
*/
public class DingdingAttendanceStatisticScheduleTask extends AbstractJob {
private static final Logger logger = LoggerFactory.getLogger(DingdingAttendanceStatisticScheduleTask.class);
@Override
public void schedule(JobExecutionContext jobExecutionContext) throws Exception {
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
logger.info("开始执行钉钉考勤统计的程序。。。。。。。。。。。。。。。。。。。。。");
//前一天 0点到23点
Date from = new Date();
from = DateTools.addDay(from, -1);//前面一天
ThisApplication.unitStatisticQueue.send(from);
}
}
}
package com.x.attendance.assemble.control.schedule;
import com.x.attendance.assemble.control.ThisApplication;
import com.x.attendance.entity.DingdingQywxSyncRecord;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.schedule.AbstractJob;
import com.x.base.core.project.tools.DateTools;
import org.quartz.JobExecutionContext;
import java.util.Date;
/**
* 钉钉考勤结果同步的定时器
* 每天晚上1点同步前一天的结果
* Created by fancyLou on 2020-03-26.
* Copyright © 2020 O2. All rights reserved.
*/
public class DingdingAttendanceSyncScheduleTask extends AbstractJob {
private static final Logger logger = LoggerFactory.getLogger(DingdingAttendanceSyncScheduleTask.class);
@Override
public void schedule(JobExecutionContext jobExecutionContext) throws Exception {
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
logger.info("开始同步钉钉考勤打卡结果。。。。。。。。。。。。。。。。。。。。。");
//前一天 0点到23点
Date from = new Date();
from = DateTools.addDay(from, -1);
from = DateTools.floorDate(from, null);
String toDay = DateTools.format(from, DateTools.format_yyyyMMdd);
Date to = DateTools.parse(toDay+" 23:59:59");
DingdingQywxSyncRecord record = new DingdingQywxSyncRecord();
record.setDateFrom(from.getTime());
record.setDateTo(to.getTime());
record.setStartTime(new Date());
record.setType(DingdingQywxSyncRecord.syncType_dingding);
record.setStatus(DingdingQywxSyncRecord.status_loading);
emc.beginTransaction(DingdingQywxSyncRecord.class);
emc.persist(record);
emc.commit();
ThisApplication.dingdingQueue.send(record);
}
}
}
package com.x.attendance.assemble.control.schedule;
import com.x.attendance.assemble.control.ThisApplication;
import com.x.attendance.entity.DingdingQywxSyncRecord;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
import com.x.base.core.project.schedule.AbstractJob;
import com.x.base.core.project.tools.DateTools;
import org.quartz.JobExecutionContext;
import java.util.Date;
/**
* 企业微信考勤同步定时器
* 每天晚上1点同步前一天的考勤数据
* Created by fancyLou on 2020-03-26.
* Copyright © 2020 O2. All rights reserved.
*/
public class QywxAttendanceSyncScheduleTask extends AbstractJob {
private static final Logger logger = LoggerFactory.getLogger(QywxAttendanceSyncScheduleTask.class);
@Override
public void schedule(JobExecutionContext jobExecutionContext) throws Exception {
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
logger.info("开始同步企业微信考勤打卡结果。。。。。。。。。。。。。。。。。。。。。");
//前一天 0点到23点
Date from = new Date();
from = DateTools.addDay(from, -1);
from = DateTools.floorDate(from, null);
String toDay = DateTools.format(from, DateTools.format_yyyyMMdd);
Date to = DateTools.parse(toDay+" 23:59:59");
DingdingQywxSyncRecord record = new DingdingQywxSyncRecord();
record.setDateFrom(from.getTime());
record.setDateTo(to.getTime());
record.setStartTime(new Date());
record.setType(DingdingQywxSyncRecord.syncType_qywx);
record.setStatus(DingdingQywxSyncRecord.status_loading);
emc.beginTransaction(DingdingQywxSyncRecord.class);
emc.persist(record);
emc.commit();
ThisApplication.qywxQueue.send(record);
}
}
}
......@@ -27,10 +27,10 @@ public class UserManagerService {
}
}
/**
* 根据员工姓名获取组织名称
* 根据员工获取所在组织
* 如果用户有多个身份,则取组织级别最大的组织名称
* @param employeeName
* @return
* @param personName dn
* @return unit 也是 dn
* @throws Exception
*/
public String getUnitNameWithPersonName( String personName ) throws Exception{
......
......@@ -13,6 +13,13 @@ import com.x.base.core.project.organization.Person;
import com.x.base.core.project.queue.AbstractQueue;
import com.x.base.core.project.x_organization_assemble_control;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class DingdingAttendanceQueue extends AbstractQueue<DingdingQywxSyncRecord> {
......@@ -22,36 +29,133 @@ public class DingdingAttendanceQueue extends AbstractQueue<DingdingQywxSyncRecor
@Override
protected void execute(DingdingQywxSyncRecord record) throws Exception {
logger.info("开始执行钉钉打卡数据同步," + record.getWay());
if (DingdingQywxSyncRecord.syncType_dingding.equals(record.getType())) {
dingdingSync(record);
} else {
logger.info("其它类型:");
}
}
private void dingdingSync() throws Exception {
try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Business business = new Business(emc);
Application app = ThisApplication.context().applications().randomWithWeight(x_organization_assemble_control.class.getName());
//开始分页查询人员
boolean hasNextPerson = true;
String uri = "person/list/(0)/next/50";
String dingdingUrl = "https://oapi.dingtalk.com/attendance/list?access_token="+ Config.dingding().corpAccessToken();
while (hasNextPerson) {
List<Person> list = ThisApplication.context().applications().getQuery(false, app, uri).getDataAsList(Person.class);
if (list != null && list.size() > 0) {
private boolean isSameDay(Date startDate, Date endDate) {
Calendar start = Calendar.getInstance();
start.setTime( startDate );
Calendar end = Calendar.getInstance();
end.setTime(endDate);
return (start.get(Calendar.YEAR) == end.get(Calendar.YEAR) && start.get(Calendar.DAY_OF_YEAR) == end.get(Calendar.DAY_OF_YEAR));
}
private void dingdingSync(DingdingQywxSyncRecord record) throws Exception {
logger.debug(record.toString());
Application app = ThisApplication.context().applications().randomWithWeight(x_organization_assemble_control.class.getName());
//开始分页查询人员
boolean hasNextPerson = true;
int personPageSize = 50;
String uri = "person/list/(0)/next/50";
String dingdingUrl = "https://oapi.dingtalk.com/attendance/list?access_token=" + Config.dingding().corpAccessToken();
logger.debug("dingding url :"+dingdingUrl);
while (hasNextPerson) {
logger.info("查询人员 uri:" + uri);
List<Person> list = ThisApplication.context().applications().getQuery(false, app, uri).getDataAsList(Person.class);
if (list != null && list.size() > 0) {
//钉钉用户id
List<String> ddUsers = list.stream().map(Person::getDingdingId).collect(Collectors.toList());
//week
Date today = new Date();
today = DateTools.floorDate(today, null);
Date sevenDayBefore = DateTools.addDay(today, -7);
//分页查询
int page = 0;
boolean hasMoreResult = true;
while (hasMoreResult) {
DingdingAttendancePost post = new DingdingAttendancePost();
}else {
//没有用户查询到结束
logger.info("查询不到用户了,结束。。。。。。。。。。。。。。。");
//post传入 时间(时间间隔不能超过7天) 人员(人员数量不能超过50个)
post.setLimit(50L);
post.setOffset(page * 50L);//从0开始翻页
post.setWorkDateFrom(DateTools.format(sevenDayBefore, DateTools.format_yyyyMMddHHmmss));
post.setWorkDateTo(DateTools.format(today, DateTools.format_yyyyMMddHHmmss));
post.setUserIdList(ddUsers);
String body = post.toString();
logger.info("查询钉钉打卡结果:" + body);
DingdingAttendanceResult result = HttpConnection.postAsObject(dingdingUrl, null, post.toString(), DingdingAttendanceResult.class);
if (result.errcode != null && result.errcode == 0) {
saveDingdingRecord(result.getRecordresult());
if (result.hasMore) {
page++;
} else {
logger.info("同步钉钉考勤结束。。。。。。。。。。。。。。。。");
hasMoreResult = false;
}
} else {
//请求结果异常 结束
logger.error(new DingDingRequestException(result.errmsg));
hasMoreResult = false;
}
}
//是否还有更多用户
if (list.size() < personPageSize) {
logger.info("同步钉钉考勤 没有更多用户了,结束。。。。。。。。。。。。。。。");
hasNextPerson = false;
updateSyncRecord(record, null);
} else {
//还有更多用户继续查询
uri = "person/list/" + list.get(list.size() - 1).getDistinguishedName() + "/next/50";
}
} else {
//没有用户查询到结束
logger.info("同步钉钉考勤 查询不到用户了,结束。。。。。。。。。。。。。。。");
hasNextPerson = false;
updateSyncRecord(record, null);
}
}
logger.info("结束 插入:"+saveNumber+" 条");
//插入数据成功 开始统计程序
boolean hasNextDate = true;
Date statisticDate = fromDate;
while (hasNextDate) {
logger.info("发起钉钉考勤数据统计, date:"+ DateTools.format(statisticDate));
ThisApplication.personStatisticQueue.send(statisticDate);
ThisApplication.unitStatisticQueue.send(statisticDate);
if (!isSameDay(statisticDate, toDate)) {
statisticDate = DateTools.addDay(statisticDate, 1);
}else {
hasNextDate = false;
}
}
logger.info("发起数据统计程序 完成。。。。。。。。。。");
}
private void saveDingdingRecord(List<DingdingAttendanceResultItem> list) throws Exception {
if (list != null && !list.isEmpty()) {
try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
emc.beginTransaction(AttendanceDingtalkDetail.class);
for (int i = 0; i < list.size(); i++) {
DingdingAttendanceResultItem item = list.get(i);
AttendanceDingtalkDetail detail = DingdingAttendanceResultItem.copier.copy(item);
detail.setDdId(item.getId());
emc.persist(detail);
}
emc.commit();
}
}
}
private void updateSyncRecord(DingdingQywxSyncRecord record, String errMsg) throws Exception {
try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
emc.beginTransaction(DingdingQywxSyncRecord.class);
record.setEndTime(new Date());
if (errMsg == null || errMsg.isEmpty()) {
record.setExceptionMessage(errMsg);
record.setStatus(DingdingQywxSyncRecord.status_error);
} else {
record.setStatus(DingdingQywxSyncRecord.status_end);
}
emc.commit();
}
}
public static class DingdingAttendancePost extends GsonPropertyObject {
// {
// {
// "workDateFrom": "yyyy-MM-dd HH:mm:ss",
// "workDateTo": "yyyy-MM-dd HH:mm:ss",
// "userIdList":["员工UserId列表"], // 必填,与offset和limit配合使用
......
......@@ -18,6 +18,7 @@ import com.x.attendance.assemble.control.jaxrs.attendancestatistic.AttendanceSta
import com.x.attendance.assemble.control.jaxrs.attendancestatisticalcycle.AttendanceStatisticalCycleAction;
import com.x.attendance.assemble.control.jaxrs.attendancestatisticrequirelog.AttendanceStatisticRequireLogAction;
import com.x.attendance.assemble.control.jaxrs.attendanceworkdayconfig.AttendanceWorkDayConfigAction;
import com.x.attendance.assemble.control.jaxrs.dingding.DingdingAttendanceAction;
import com.x.attendance.assemble.control.jaxrs.fileimport.AttendanceDetailFileImportAction;
import com.x.attendance.assemble.control.jaxrs.selfholiday.AttendanceSelfHolidayAction;
import com.x.attendance.assemble.control.jaxrs.selfholiday.AttendanceSelfHolidaySimpleAction;
......@@ -48,6 +49,7 @@ public class ActionApplication extends AbstractActionApplication {
this.classes.add(AttendanceStatisticalCycleAction.class);
this.classes.add(AttendanceEmployeeConfigAction.class);
this.classes.add(AttendanceStatisticRequireLogAction.class);
this.classes.add(DingdingAttendanceAction.class);
return this.classes;
}
......
package com.x.attendance.assemble.control.jaxrs;
import com.x.base.core.project.jaxrs.CipherManagerJaxrsFilter;
import com.x.base.core.project.jaxrs.ManagerUserJaxrsFilter;
import javax.servlet.annotation.WebFilter;
@WebFilter(urlPatterns = "/jaxrs/dingding/*", asyncSupported = true)
public class DingdingJaxrsFilter extends CipherManagerJaxrsFilter {
public class DingdingJaxrsFilter extends ManagerUserJaxrsFilter {
}
......@@ -152,4 +152,22 @@ public class AttendanceSettingAction extends StandardJaxrsAction {
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
@JaxrsMethodDescribe(value = "是否启用钉钉考勤或企业微信考勤", action = ActionEnableType.class)
@GET
@Path("enable/type")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void enableType(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request) {
ActionResult<ActionEnableType.Wo> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionEnableType().execute(effectivePerson);
} catch (Exception e) {
result = new ActionResult<>();
result.error(e);
logger.error(e, effectivePerson, request, null);
}
asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
}
}
\ No newline at end of file
package com.x.attendance.assemble.control.jaxrs.dingding;
import com.google.gson.JsonElement;
import com.x.attendance.assemble.control.ThisApplication;
import com.x.attendance.entity.DingdingQywxSyncRecord;
import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.container.factory.EntityManagerContainerFactory;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.bean.WrapCopier;
import com.x.base.core.project.bean.WrapCopierFactory;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.http.EffectivePerson;
import com.x.base.core.project.jaxrs.WrapBoolean;
......@@ -21,30 +17,25 @@ public class ActionSyncData extends BaseAction {
private static final Logger logger = LoggerFactory.getLogger(ActionSyncData.class);
public ActionResult<WrapBoolean> execute(EffectivePerson effectivePerson, JsonElement jsonElement) throws Exception {
public ActionResult<WrapBoolean> execute(EffectivePerson effectivePerson, String way) throws Exception {
ActionResult<WrapBoolean> result = new ActionResult<>();
try ( EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
Wi wi = this.convertToWrapIn(jsonElement, Wi.class);
if (null == wi.getWay() ||
(!DingdingQywxSyncRecord.syncWay_week.equals(wi.getWay()) && !DingdingQywxSyncRecord.syncWay_year.equals(wi.getWay()))) {
if (null == way ||
(!DingdingQywxSyncRecord.syncWay_week.equals(way) && !DingdingQywxSyncRecord.syncWay_year.equals(way))) {
throw new SyncWayException();
}
DingdingQywxSyncRecord record = new DingdingQywxSyncRecord();
record.setWay(wi.getWay());
record.setWay(way);
record.setStartTime(new Date());
record.setType(DingdingQywxSyncRecord.syncType_dingding);
record.setStatus(DingdingQywxSyncRecord.status_loading);
emc.beginTransaction(DingdingQywxSyncRecord.class);
emc.persist(record);
emc.commit();
ThisApplication.dingdingQueue.executing(record);
ThisApplication.dingdingQueue.send(record);
result.setData(new WrapBoolean(true));
}
return result;
}
public static class Wi extends DingdingQywxSyncRecord {
public static WrapCopier<Wi, DingdingQywxSyncRecord> copier = WrapCopierFactory.wi(Wi.class,
DingdingQywxSyncRecord.class, null, JpaObject.FieldsUnmodify);
}
}
......@@ -3,6 +3,7 @@ package com.x.attendance.assemble.control.jaxrs.dingding;
import com.google.gson.JsonElement;
import com.x.base.core.project.annotation.JaxrsDescribe;
import com.x.base.core.project.annotation.JaxrsMethodDescribe;
import com.x.base.core.project.annotation.JaxrsParameterDescribe;
import com.x.base.core.project.http.ActionResult;
import com.x.base.core.project.http.EffectivePerson;
import com.x.base.core.project.http.HttpMediaType;
......@@ -51,16 +52,16 @@ public class DingdingAttendanceAction extends StandardJaxrsAction {
//获取7天数据 可以做定时每天晚上更新
@JaxrsMethodDescribe(value = "同步钉钉考勤结果", action = ActionSyncData.class)
@POST
@Path("sync")
@GET
@Path("sync/{way}/start")
@Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
@Consumes(MediaType.APPLICATION_JSON)
public void syncData(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
JsonElement jsonElement) {
@JaxrsParameterDescribe("同步方式") @PathParam("way") String way) {
ActionResult<WrapBoolean> result = new ActionResult<>();
EffectivePerson effectivePerson = this.effectivePerson(request);
try {
result = new ActionSyncData().execute(effectivePerson, jsonElement);
result = new ActionSyncData().execute(effectivePerson, way);
}catch (Exception e) {
logger.error(e, effectivePerson, request, null);
result.error(e);
......
......@@ -7,6 +7,7 @@ import com.x.base.core.entity.annotation.ContainerEntity;
import com.x.base.core.project.annotation.FieldDescribe;
import javax.persistence.*;
import java.util.Date;
@ContainerEntity
@Entity
......@@ -49,10 +50,18 @@ public class AttendanceDingtalkDetail extends SliceJpaObject {
@Column(name = ColumnNamePrefix + "ddID")
private long ddId;
@FieldDescribe("用户id")
@FieldDescribe("钉钉的用户id")
@Column(name = ColumnNamePrefix + "userId", length = length_96B)
private String userId;
@FieldDescribe("O2用户")
@Column(name = ColumnNamePrefix + "o2User", length = length_128B)
private String o2User;
@FieldDescribe("O2用户所在的组织")
@Column(name = ColumnNamePrefix + "o2Unit", length = length_128B)
private String o2Unit;
@FieldDescribe("基准时间,用于计算迟到和早退")
@Column(name = ColumnNamePrefix + "baseCheckTime")
private long baseCheckTime;
......@@ -61,6 +70,10 @@ public class AttendanceDingtalkDetail extends SliceJpaObject {
@Column(name = ColumnNamePrefix + "userCheckTime")
private long userCheckTime;
@FieldDescribe("实际打卡时间, 用Date格式存储")
@Column(name = ColumnNamePrefix + "userCheckTimeDate")
private Date userCheckTimeDate;
@FieldDescribe("工作日")
@Column(name = ColumnNamePrefix + "workDate")
private long workDate;
......@@ -142,6 +155,22 @@ public class AttendanceDingtalkDetail extends SliceJpaObject {
// private String procInstId;
public String getO2User() {
return o2User;
}
public void setO2User(String o2User) {
this.o2User = o2User;
}
public String getO2Unit() {
return o2Unit;
}
public void setO2Unit(String o2Unit) {
this.o2Unit = o2Unit;
}
public long getDdId() {
return ddId;
}
......@@ -237,4 +266,12 @@ public class AttendanceDingtalkDetail extends SliceJpaObject {
public void setRecordId(long recordId) {
this.recordId = recordId;
}
public Date getUserCheckTimeDate() {
return userCheckTimeDate;
}
public void setUserCheckTimeDate(Date userCheckTimeDate) {
this.userCheckTimeDate = userCheckTimeDate;
}
}
......@@ -61,11 +61,13 @@ public class DingdingQywxSyncRecord extends SliceJpaObject {
@Column(name = ColumnNamePrefix + "type", length = length_32B)
private String type;
public static final String syncWay_year = "year";
public static final String syncWay_week = "week";
@FieldDescribe("同步方式,year(同步一年数据) , week(同步一周数据)")
@Column(name = ColumnNamePrefix + "way", length = length_32B)
private String way;
@FieldDescribe("同步打卡记录的开始时间")
@Column(name = ColumnNamePrefix + "dateFrom")
private long dateFrom;
@FieldDescribe("同步打卡记录的结束时间, 起始与结束工作日最多相隔7天")
@Column(name = ColumnNamePrefix + "dateTo")
private long dateTo;
public static final String status_loading = "loading";
public static final String status_end = "end";
......@@ -104,12 +106,20 @@ public class DingdingQywxSyncRecord extends SliceJpaObject {
this.type = type;
}
public String getWay() {
return way;
public long getDateFrom() {
return dateFrom;
}
public void setDateFrom(long dateFrom) {
this.dateFrom = dateFrom;
}
public long getDateTo() {
return dateTo;
}
public void setWay(String way) {
this.way = way;
public void setDateTo(long dateTo) {
this.dateTo = dateTo;
}
public String getStatus() {
......
......@@ -78,6 +78,15 @@ public final class PersistenceProperties extends AbstractPersistenceProperties {
public static class StatisticPersonForMonth {
public static final String table = "ATDC_STATISTIC_PERSON_FORMONTH";
}
public static class StatisticDingdingPersonForMonth {
public static final String table = "ATDC_STATISTIC_DD_PERSON_FORMONTH";
}
public static class StatisticDingdingUnitForMonth {
public static final String table = "ATDC_STATISTIC_DD_UNIT_FORMONTH";
}
public static class StatisticDingdingUnitForDay {
public static final String table = "ATDC_STATISTIC_DD_UNIT_FORDAY";
}
public static class AttendanceWorkPlace {
public static final String table = "ATDC_WORK_PLACE";
......
package com.x.attendance.entity;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.entity.SliceJpaObject;
import com.x.base.core.entity.annotation.CheckPersist;
import com.x.base.core.entity.annotation.ContainerEntity;
import com.x.base.core.project.annotation.FieldDescribe;
import javax.persistence.*;
@ContainerEntity
@Entity
@Table(name = PersistenceProperties.StatisticDingdingPersonForMonth.table, uniqueConstraints = {
@UniqueConstraint(name = PersistenceProperties.StatisticDingdingPersonForMonth.table + JpaObject.IndexNameMiddle
+ JpaObject.DefaultUniqueConstraintSuffix, columnNames = { JpaObject.IDCOLUMN,
JpaObject.CREATETIMECOLUMN, JpaObject.UPDATETIMECOLUMN, JpaObject.SEQUENCECOLUMN }) })
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class StatisticDingdingPersonForMonth extends SliceJpaObject {
private static final String TABLE = PersistenceProperties.StatisticDingdingPersonForMonth.table;
private static final long serialVersionUID = 2006440116216111693L;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@FieldDescribe("数据库主键,自动生成.")
@Id
@Column(length = length_id, name = ColumnNamePrefix + id_FIELDNAME)
private String id = createId();
public void onPersist() throws Exception {
}
/*
* =============================================================================
* ===== 以上为 JpaObject 默认字段
* =============================================================================
* =====
*/
/*
* =============================================================================
* ===== 以下为具体不同的业务及数据表字段要求
* =============================================================================
* =====
*/
@FieldDescribe("O2用户")
@Column(name = ColumnNamePrefix + "o2User", length = length_128B)
@CheckPersist(allowEmpty = false)
private String o2User;
@FieldDescribe("O2用户所在的组织")
@Column(name = ColumnNamePrefix + "o2Unit", length = length_128B)
@CheckPersist(allowEmpty = false)
private String o2Unit;
@FieldDescribe("统计年份")
@Column(name = "xstatisticYear", length = JpaObject.length_16B)
@CheckPersist(allowEmpty = false)
private String statisticYear;
@FieldDescribe("统计月份")
@Column(name = "xstatisticMonth", length = JpaObject.length_16B)
@CheckPersist(allowEmpty = false)
private String statisticMonth;
@FieldDescribe("出勤天数")
@Column(name = "xworkDayCount")
private Long workDayCount;
@FieldDescribe("上班签到次数")
@Column(name = "xonDutyTimes")
private Long onDutyTimes;
@FieldDescribe("下班签到次数")
@Column(name = "xoffDutyTimes")
private Long offDutyTimes;
@FieldDescribe("正常签到次数")
@Column(name = "xresultNormal")
private Long resultNormal;
@FieldDescribe("迟到次数")
@Column(name = "xlateTimes")
private Long lateTimes;
@FieldDescribe("严重迟到次数")
@Column(name = "xSeriousLateTimes")
private Long seriousLateTimes;
@FieldDescribe("早退次数")
@Column(name = "xleaveEarlyTimes")
private Long leaveEarlyTimes;
@FieldDescribe("旷工次数")
@Column(name = "xAbsenteeismTimes")
private Long absenteeismTimes;
@FieldDescribe("未打卡次数")
@Column(name = "xNotSignedCount")
private Long notSignedCount;
public Long getResultNormal() {
return resultNormal;
}
public void setResultNormal(Long resultNormal) {
this.resultNormal = resultNormal;
}
public String getO2User() {
return o2User;
}
public void setO2User(String o2User) {
this.o2User = o2User;
}
public String getO2Unit() {
return o2Unit;
}
public void setO2Unit(String o2Unit) {
this.o2Unit = o2Unit;
}
public String getStatisticYear() {
return statisticYear;
}
public void setStatisticYear(String statisticYear) {
this.statisticYear = statisticYear;
}
public String getStatisticMonth() {
return statisticMonth;
}
public void setStatisticMonth(String statisticMonth) {
this.statisticMonth = statisticMonth;
}
public Long getWorkDayCount() {
return workDayCount;
}
public void setWorkDayCount(Long workDayCount) {
this.workDayCount = workDayCount;
}
public Long getOnDutyTimes() {
return onDutyTimes;
}
public void setOnDutyTimes(Long onDutyTimes) {
this.onDutyTimes = onDutyTimes;
}
public Long getOffDutyTimes() {
return offDutyTimes;
}
public void setOffDutyTimes(Long offDutyTimes) {
this.offDutyTimes = offDutyTimes;
}
public Long getLateTimes() {
return lateTimes;
}
public void setLateTimes(Long lateTimes) {
this.lateTimes = lateTimes;
}
public Long getSeriousLateTimes() {
return seriousLateTimes;
}
public void setSeriousLateTimes(Long seriousLateTimes) {
this.seriousLateTimes = seriousLateTimes;
}
public Long getLeaveEarlyTimes() {
return leaveEarlyTimes;
}
public void setLeaveEarlyTimes(Long leaveEarlyTimes) {
this.leaveEarlyTimes = leaveEarlyTimes;
}
public Long getAbsenteeismTimes() {
return absenteeismTimes;
}
public void setAbsenteeismTimes(Long absenteeismTimes) {
this.absenteeismTimes = absenteeismTimes;
}
public Long getNotSignedCount() {
return notSignedCount;
}
public void setNotSignedCount(Long notSignedCount) {
this.notSignedCount = notSignedCount;
}
}
\ No newline at end of file
package com.x.attendance.entity;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.entity.SliceJpaObject;
import com.x.base.core.entity.annotation.CheckPersist;
import com.x.base.core.entity.annotation.ContainerEntity;
import com.x.base.core.project.annotation.FieldDescribe;
import javax.persistence.*;
@ContainerEntity
@Entity
@Table(name = PersistenceProperties.StatisticDingdingUnitForDay.table, uniqueConstraints = {
@UniqueConstraint(name = PersistenceProperties.StatisticDingdingUnitForDay.table + JpaObject.IndexNameMiddle
+ JpaObject.DefaultUniqueConstraintSuffix, columnNames = { JpaObject.IDCOLUMN,
JpaObject.CREATETIMECOLUMN, JpaObject.UPDATETIMECOLUMN, JpaObject.SEQUENCECOLUMN }) })
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class StatisticDingdingUnitForDay extends SliceJpaObject {
private static final String TABLE = PersistenceProperties.StatisticDingdingUnitForDay.table;
private static final long serialVersionUID = 2090817422412907325L;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@FieldDescribe("数据库主键,自动生成.")
@Id
@Column(length = length_id, name = ColumnNamePrefix + id_FIELDNAME)
private String id = createId();
public void onPersist() throws Exception {
}
/*
* =============================================================================
* ===== 以上为 JpaObject 默认字段
* =============================================================================
* =====
*/
/*
* =============================================================================
* ===== 以下为具体不同的业务及数据表字段要求
* =============================================================================
* =====
*/
@FieldDescribe("O2用户所在的组织")
@Column(name = ColumnNamePrefix + "o2Unit", length = length_128B)
@CheckPersist(allowEmpty = false)
private String o2Unit;
@FieldDescribe("统计年份")
@Column(name = "xstatisticYear", length = JpaObject.length_16B)
@CheckPersist(allowEmpty = false)
private String statisticYear;
@FieldDescribe("统计月份")
@Column(name = "xstatisticMonth", length = JpaObject.length_16B)
@CheckPersist(allowEmpty = false)
private String statisticMonth;
@FieldDescribe("统计日期")
@Column(name = "xstatisticDate", length = JpaObject.length_16B)
@CheckPersist(allowEmpty = false)
private String statisticDate;
@FieldDescribe("出勤人数")
@Column(name = "xworkDayCount")
private Long workDayCount;
@FieldDescribe("上班签到人数")
@Column(name = "xonDutyTimes")
private Long onDutyTimes;
@FieldDescribe("下班签到人数")
@Column(name = "xoffDutyTimes")
private Long offDutyTimes;
@FieldDescribe("正常签到次数")
@Column(name = "xresultNormal")
private Long resultNormal;
@FieldDescribe("迟到人数")
@Column(name = "xlateTimes")
private Long lateTimes;
@FieldDescribe("严重迟到人数")
@Column(name = "xSeriousLateTimes")
private Long seriousLateTimes;
@FieldDescribe("早退人数")
@Column(name = "xleaveEarlyTimes")
private Long leaveEarlyTimes;
@FieldDescribe("旷工人数")
@Column(name = "xAbsenteeismTimes")
private Long absenteeismTimes;
@FieldDescribe("未打卡人数")
@Column(name = "xNotSignedCount")
private Long notSignedCount;
public Long getResultNormal() {
return resultNormal;
}
public void setResultNormal(Long resultNormal) {
this.resultNormal = resultNormal;
}
public String getStatisticDate() {
return statisticDate;
}
public void setStatisticDate(String statisticDate) {
this.statisticDate = statisticDate;
}
public String getO2Unit() {
return o2Unit;
}
public void setO2Unit(String o2Unit) {
this.o2Unit = o2Unit;
}
public String getStatisticYear() {
return statisticYear;
}
public void setStatisticYear(String statisticYear) {
this.statisticYear = statisticYear;
}
public String getStatisticMonth() {
return statisticMonth;
}
public void setStatisticMonth(String statisticMonth) {
this.statisticMonth = statisticMonth;
}
public Long getWorkDayCount() {
return workDayCount;
}
public void setWorkDayCount(Long workDayCount) {
this.workDayCount = workDayCount;
}
public Long getOnDutyTimes() {
return onDutyTimes;
}
public void setOnDutyTimes(Long onDutyTimes) {
this.onDutyTimes = onDutyTimes;
}
public Long getOffDutyTimes() {
return offDutyTimes;
}
public void setOffDutyTimes(Long offDutyTimes) {
this.offDutyTimes = offDutyTimes;
}
public Long getLateTimes() {
return lateTimes;
}
public void setLateTimes(Long lateTimes) {
this.lateTimes = lateTimes;
}
public Long getSeriousLateTimes() {
return seriousLateTimes;
}
public void setSeriousLateTimes(Long seriousLateTimes) {
this.seriousLateTimes = seriousLateTimes;
}
public Long getLeaveEarlyTimes() {
return leaveEarlyTimes;
}
public void setLeaveEarlyTimes(Long leaveEarlyTimes) {
this.leaveEarlyTimes = leaveEarlyTimes;
}
public Long getAbsenteeismTimes() {
return absenteeismTimes;
}
public void setAbsenteeismTimes(Long absenteeismTimes) {
this.absenteeismTimes = absenteeismTimes;
}
public Long getNotSignedCount() {
return notSignedCount;
}
public void setNotSignedCount(Long notSignedCount) {
this.notSignedCount = notSignedCount;
}
}
\ No newline at end of file
package com.x.attendance.entity;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.entity.SliceJpaObject;
import com.x.base.core.entity.annotation.CheckPersist;
import com.x.base.core.entity.annotation.ContainerEntity;
import com.x.base.core.project.annotation.FieldDescribe;
import javax.persistence.*;
@ContainerEntity
@Entity
@Table(name = PersistenceProperties.StatisticDingdingUnitForMonth.table, uniqueConstraints = {
@UniqueConstraint(name = PersistenceProperties.StatisticDingdingUnitForMonth.table + JpaObject.IndexNameMiddle
+ JpaObject.DefaultUniqueConstraintSuffix, columnNames = { JpaObject.IDCOLUMN,
JpaObject.CREATETIMECOLUMN, JpaObject.UPDATETIMECOLUMN, JpaObject.SEQUENCECOLUMN }) })
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class StatisticDingdingUnitForMonth extends SliceJpaObject {
private static final String TABLE = PersistenceProperties.StatisticDingdingUnitForMonth.table;
private static final long serialVersionUID = 2831416127767736230L;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@FieldDescribe("数据库主键,自动生成.")
@Id
@Column(length = length_id, name = ColumnNamePrefix + id_FIELDNAME)
private String id = createId();
public void onPersist() throws Exception {
}
/*
* =============================================================================
* ===== 以上为 JpaObject 默认字段
* =============================================================================
* =====
*/
/*
* =============================================================================
* ===== 以下为具体不同的业务及数据表字段要求
* =============================================================================
* =====
*/
@FieldDescribe("O2用户所在的组织")
@Column(name = ColumnNamePrefix + "o2Unit", length = length_128B)
@CheckPersist(allowEmpty = false)
private String o2Unit;
@FieldDescribe("统计年份")
@Column(name = "xstatisticYear", length = JpaObject.length_16B)
@CheckPersist(allowEmpty = false)
private String statisticYear;
@FieldDescribe("统计月份")
@Column(name = "xstatisticMonth", length = JpaObject.length_16B)
@CheckPersist(allowEmpty = false)
private String statisticMonth;
@FieldDescribe("出勤天数")
@Column(name = "xworkDayCount")
private Long workDayCount;
@FieldDescribe("上班签到人数")
@Column(name = "xonDutyTimes")
private Long onDutyTimes;
@FieldDescribe("下班签到人数")
@Column(name = "xoffDutyTimes")
private Long offDutyTimes;
@FieldDescribe("正常签到次数")
@Column(name = "xresultNormal")
private Long resultNormal;
@FieldDescribe("迟到人数")
@Column(name = "xlateTimes")
private Long lateTimes;
@FieldDescribe("严重迟到人数")
@Column(name = "xSeriousLateTimes")
private Long seriousLateTimes;
@FieldDescribe("早退人数")
@Column(name = "xleaveEarlyTimes")
private Long leaveEarlyTimes;
@FieldDescribe("旷工人数")
@Column(name = "xAbsenteeismTimes")
private Long absenteeismTimes;
@FieldDescribe("未打卡人数")
@Column(name = "xNotSignedCount")
private Long notSignedCount;
public Long getResultNormal() {
return resultNormal;
}
public void setResultNormal(Long resultNormal) {
this.resultNormal = resultNormal;
}
public String getO2Unit() {
return o2Unit;
}
public void setO2Unit(String o2Unit) {
this.o2Unit = o2Unit;
}
public String getStatisticYear() {
return statisticYear;
}
public void setStatisticYear(String statisticYear) {
this.statisticYear = statisticYear;
}
public String getStatisticMonth() {
return statisticMonth;
}
public void setStatisticMonth(String statisticMonth) {
this.statisticMonth = statisticMonth;
}
public Long getWorkDayCount() {
return workDayCount;
}
public void setWorkDayCount(Long workDayCount) {
this.workDayCount = workDayCount;
}
public Long getOnDutyTimes() {
return onDutyTimes;
}
public void setOnDutyTimes(Long onDutyTimes) {
this.onDutyTimes = onDutyTimes;
}
public Long getOffDutyTimes() {
return offDutyTimes;
}
public void setOffDutyTimes(Long offDutyTimes) {
this.offDutyTimes = offDutyTimes;
}
public Long getLateTimes() {
return lateTimes;
}
public void setLateTimes(Long lateTimes) {
this.lateTimes = lateTimes;
}
public Long getSeriousLateTimes() {
return seriousLateTimes;
}
public void setSeriousLateTimes(Long seriousLateTimes) {
this.seriousLateTimes = seriousLateTimes;
}
public Long getLeaveEarlyTimes() {
return leaveEarlyTimes;
}
public void setLeaveEarlyTimes(Long leaveEarlyTimes) {
this.leaveEarlyTimes = leaveEarlyTimes;
}
public Long getAbsenteeismTimes() {
return absenteeismTimes;
}
public void setAbsenteeismTimes(Long absenteeismTimes) {
this.absenteeismTimes = absenteeismTimes;
}
public Long getNotSignedCount() {
return notSignedCount;
}
public void setNotSignedCount(Long notSignedCount) {
this.notSignedCount = notSignedCount;
}
}
\ No newline at end of file
......@@ -44,6 +44,13 @@ public class Qiyeweixin extends ConfigObject {
private Boolean messageEnable;
@FieldDescribe("企业微信扫码登录")
private Boolean scanLoginEnable;
@FieldDescribe("是否启用考勤信息")
private Boolean attendanceSyncEnable;
@FieldDescribe("企业微信考勤打卡应用id")
private String attendanceSyncAgentId;
@FieldDescribe("企业微信考勤打卡应用secret")
private String attendanceSyncSecret;
public static Qiyeweixin defaultInstance() {
return new Qiyeweixin();
......@@ -61,6 +68,7 @@ public class Qiyeweixin extends ConfigObject {
public static final String default_messageRedirectPortal = "";
public static final Boolean default_messageEanble = false;
public static final Boolean default_scanLoginEnable = false;
public static final Boolean default_attendanceSyncEnable = false;
public Qiyeweixin() {
this.enable = default_enable;
......@@ -75,9 +83,14 @@ public class Qiyeweixin extends ConfigObject {
this.workUrl = default_workUrl;
this.messageRedirectPortal = default_messageRedirectPortal;
this.scanLoginEnable = default_scanLoginEnable;
this.attendanceSyncEnable = default_attendanceSyncEnable;
this.attendanceSyncAgentId = "";
this.attendanceSyncSecret = "";
}
private static String cacheAttendanceAccessToken;
private static Date cacheAttendanceAccessTokenDate;
private static String cachedCorpAccessToken;
private static Date cachedCorpAccessTokenDate;
......@@ -142,6 +155,26 @@ public class Qiyeweixin extends ConfigObject {
}
}
public String attendanceAccessToken() throws Exception {
if ((StringUtils.isNotEmpty(cacheAttendanceAccessToken) && (null != cacheAttendanceAccessTokenDate))
&& (cacheAttendanceAccessTokenDate.after(new Date()))) {
return cacheAttendanceAccessToken;
} else {
String address = default_apiAddress + "/cgi-bin/gettoken?corpid=" + this.getCorpId() + "&corpsecret="
+ this.getAttendanceSyncSecret();
CorpAccessTokenResp resp = HttpConnection.getAsObject(address, null, CorpAccessTokenResp.class);
if (resp.getErrcode() != 0) {
throw new ExceptionQiyeweixinCorpAccessToken(resp.getErrcode(), resp.getErrmsg());
}
cacheAttendanceAccessToken = resp.getAccess_token();
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, 90);
cacheAttendanceAccessTokenDate = cal.getTime();
return cacheAttendanceAccessToken;
}
}
public String syncAccessToken() throws Exception {
if ((StringUtils.isNotEmpty(cachedSyncAccessToken) && (null != cachedSyncAccessTokenDate))
&& (cachedSyncAccessTokenDate.after(new Date()))) {
......@@ -386,6 +419,31 @@ public class Qiyeweixin extends ConfigObject {
this.scanLoginEnable = scanLoginEnable;
}
public Boolean getAttendanceSyncEnable() {
return attendanceSyncEnable;
}
public void setAttendanceSyncEnable(Boolean attendanceSyncEnable) {
this.attendanceSyncEnable = attendanceSyncEnable;
}
public String getAttendanceSyncAgentId() {
return attendanceSyncAgentId;
}
public void setAttendanceSyncAgentId(String attendanceSyncAgentId) {
this.attendanceSyncAgentId = attendanceSyncAgentId;
}
public String getAttendanceSyncSecret() {
return attendanceSyncSecret;
}
public void setAttendanceSyncSecret(String attendanceSyncSecret) {
this.attendanceSyncSecret = attendanceSyncSecret;
}
public void save() throws Exception {
File file = new File(Config.base(), Config.PATH_CONFIG_QIYEWEIXIN);
FileUtils.write(file, XGsonBuilder.toJson(this), DefaultCharset.charset);
......
......@@ -609,5 +609,33 @@ public class DateTools {
return dayForWeek;
}
/**
* 指定的日期,添加指定的天数
*
* @param date
* @param dayCount
* @return
*/
public static Date addDay(Date date, int dayCount) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DAY_OF_YEAR, dayCount);// 指定的时间上加上n天
date = calendar.getTime();
return date;
}
public static void main(String[] args) {
try {
Date today = new Date();
today = DateTools.floorDate(today, null);
Date sevenDayBefore = DateTools.addDay(today, -7);
System.out.println(DateTools.format(today));
System.out.println(DateTools.format(sevenDayBefore));
} catch (Exception e) {
e.printStackTrace();
}
}
}
\ No newline at end of file
......@@ -15,7 +15,8 @@ import com.x.base.core.project.annotation.ModuleType;
"com.x.attendance.entity.StatisticTopUnitForDay", "com.x.attendance.entity.StatisticTopUnitForMonth",
"com.x.attendance.entity.StatisticUnitForDay", "com.x.attendance.entity.StatisticUnitForMonth",
"com.x.attendance.entity.AttendanceDingtalkDetail", "com.x.attendance.entity.AttendanceQywxDetail",
"com.x.attendance.entity.DingdingQywxSyncRecord"}, storeJars = {
"com.x.attendance.entity.DingdingQywxSyncRecord", "com.x.attendance.entity.StatisticDingdingPersonForMonth",
"com.x.attendance.entity.StatisticDingdingUnitForDay", "com.x.attendance.entity.StatisticDingdingUnitForMonth"}, storeJars = {
"x_attendance_core_entity", "x_organization_core_express", "x_organization_core_entity" })
public class x_attendance_assemble_control extends Deployable {
}
......@@ -2,141 +2,158 @@
{
"title": "我的考勤月报",
"id": "10",
"action" : "openMyIndex"
"action": "openMyIndex"
},
{
"title": "我的考勤统计",
"id": "11",
"action" : "openMyDetail"
"action": "openMyDetail"
},
{
"title": "我的申诉申请",
"id": "12",
"action" : "openMyAppealDeal"
"action": "openMyAppealDeal"
},
{
"title": "员工考勤申诉审批",
"id": "13",
"action" : "openAppealDeal"
"action": "openAppealDeal"
},
{
"access" :"admin_dept",
"type" :"sep"
"access": "admin_dept",
"type": "sep"
},
{
"access" :"admin_dept",
"access": "admin_dept",
"title": "部门考勤月报",
"id": "15",
"action" : "openUnitIndex"
"action": "openUnitIndex"
},
{
"access" :"admin_dept",
"access": "admin_dept",
"title": "个人考勤统计",
"id": "16",
"action" : "openPeopleDetail"
"action": "openPeopleDetail"
},
{
"access" :"admin_dept",
"access": "admin_dept",
"title": "部门考勤统计",
"id": "17",
"action" : "openUnitDetail"
"action": "openUnitDetail"
},
{
"access" :"admin",
"access": "admin",
"title": "公司考勤统计",
"id": "18",
"action" : "openTopUnitDetail"
"action": "openTopUnitDetail"
},
{
"access" :"admin",
"type" :"sep"
"access": "dingding",
"title": "钉钉部门考勤月报",
"id": "151",
"action": "openUnitDingdingIndex"
},
{
"access" :"admin",
"access": "dingding",
"title": "钉钉个人考勤统计",
"id": "161",
"action": "openDingdingPeopleDetail"
},
{
"access": "dingding",
"title": "钉钉部门考勤统计",
"id": "171",
"action": "openDingdingUnitDetail"
},
{
"access": "admin",
"type": "sep"
},
{
"access": "admin",
"title": "维护",
"id": "20",
"sub": [
{
"access" :"admin",
"access": "admin",
"title": "数据导入",
"id": "20.3",
"action" : "openImporting"
"action": "openImporting"
},
{
"access" :"admin",
"access": "admin",
"title": "导入错误信息",
"id": "20.4",
"action" : "openImportedInvalidInfor"
"action": "openImportedInvalidInfor"
},
{
"access" :"admin",
"access": "admin",
"title": "非正常出勤数据导出",
"id": "20.42",
"action" : "openAbnormalExport"
"action": "openAbnormalExport"
},
{
"access" :"admin",
"access": "admin",
"title": "员工休假记录",
"id": "20.1",
"action" : "openSelfHoliday"
"action": "openSelfHoliday"
}
]
},
{
"access" :"admin",
"access": "admin",
"title": "权限和人员",
"id": "30",
"sub": [
{
"id" : "30.10",
"access" : "admin",
"title" : "管理员设置",
"action" : "openPermissionSetting"
"id": "30.10",
"access": "admin",
"title": "管理员设置",
"action": "openPermissionSetting"
},
{
"id" : "30.20",
"access" : "admin",
"title" : "考勤人员配置",
"action" : "openPersonSetting"
"id": "30.20",
"access": "admin",
"title": "考勤人员配置",
"action": "openPersonSetting"
}
]
},
{
"access" :"admin",
"access": "admin",
"title": "配置",
"id": "40",
"sub": [
{
"id" : "40.10",
"access" : "admin",
"title" : "排班设置",
"action" : "openScheduleSetting"
"id": "40.10",
"access": "admin",
"title": "排班设置",
"action": "openScheduleSetting"
},
{
"id" : "40.20",
"access" : "admin",
"title" : "统计周期设置",
"action" : "openStaticsCycleExplorer"
"id": "40.20",
"access": "admin",
"title": "统计周期设置",
"action": "openStaticsCycleExplorer"
},
{
"id" : "40.15",
"access" : "admin",
"title" : "法定假期",
"action" : "openHolidaySetting"
"id": "40.15",
"access": "admin",
"title": "法定假期",
"action": "openHolidaySetting"
},
{
"id" : "40.35",
"access" : "admin",
"title" : "工作场所设置",
"action" : "openAddressSetting"
"id": "40.35",
"access": "admin",
"title": "工作场所设置",
"action": "openAddressSetting"
},
{
"id" : "40.25",
"access" : "admin",
"target" : "_blank",
"title" : "申诉设置",
"action" : "openAppSetting"
"id": "40.25",
"access": "admin",
"target": "_blank",
"title": "申诉设置",
"action": "openAppSetting"
}
]
}
......
[
{
"title": "姓名",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "function( d ){ return d.o2User.split('@')[0] }",
"name": "o2User",
"width": "20%"
},
{
"title": "日期",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "function(d){ var date = new Date(d.userCheckTime); return date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate();}",
"name": "userCheckTime",
"width": "20%"
},
{
"title": "打卡类型",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "function( data ){ if(data.checkType == 'OffDuty'){return '下班打卡';}else{return '上班打卡';} }",
"name": "checkType",
"width": "20%"
},
{
"title": "打卡结果",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "function( data ){ if(data.timeResult == 'Normal'){return '正常';}else if(data.timeResult == 'Early'){return '早退';}else if(data.timeResult == 'Late'){return '迟到';}else if(data.timeResult == 'SeriousLate'){return '严重迟到';}else if(data.timeResult == 'Absenteeism'){return '旷工迟到';}else {return '未打卡';} }",
"name": "timeResult",
"width": "20%"
},
{
"title": "打卡时间",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "function(d){ var date = new Date(d.userCheckTime); return date.getHours()+':'+date.getMinutes()+':'+date.getSeconds();}",
"name": "userCheckTime",
"width": "20%"
}
]
\ No newline at end of file
[
{
"title": "人员",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "function( d ){ return d.o2User.split('@')[0] }",
"name": "o2User",
"width": "9%"
},
{
"title": "月份",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "function( data ){ return data.statisticYear + '-' + data.statisticMonth }",
"name": "statisticMonth",
"width": "9%"
},
{
"title": "上班打卡次数",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "onDutyTimes",
"name": "onDutyTimes",
"width": "9%"
},
{
"title": "下班打卡次数",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "offDutyTimes",
"name": "offDutyTimes",
"width": "9%"
},
{
"title": "出勤人天数",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "workDayCount",
"name": "workDayCount",
"width": "9%"
},
{
"title": "迟到次数",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "lateTimes",
"name": "lateTimes",
"width": "9%"
},
{
"title": "早退次数",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "leaveEarlyTimes",
"name": "leaveEarlyTimes",
"width": "9%"
},
{
"title": "未打卡次数",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "notSignedCount",
"name": "notSignedCount",
"width": "9%"
},
{
"title": "严重迟到次数",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "seriousLateTimes",
"name": "seriousLateTimes",
"width": "9%"
},
{
"title": "旷工次数",
"headStyles": "normalThNode",
"contentStyles": "normalTdNode",
"item": "absenteeismTimes",
"name": "absenteeismTimes",
"width": "9%"
}
]
\ No newline at end of file
......@@ -47,6 +47,11 @@ MWF.xApplication.Attendance.LP = {
"leaveEarlyTimes" : "早退次数",
"lackOfTimeCount" : "工时不足人次",
"abNormalDutyCount" : "异常打卡人次",
"resultNormal" : "正常打卡次数",
"seriousLateTimes": "严重迟到次数",
"leaveEarlyTimes": "早退次数",
"absenteeismTimes": "矿工次数",
"notSignedCount": "未打卡次数",
"topUnitAttendanceDetail" : "公司出勤明细",
"topUnitAttendanceStatic" : "公司出勤率统计",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册