commit
This commit is contained in:
+1
-3
@@ -15,7 +15,6 @@ import com.budwk.app.flow.entity.ProcessInstance;
|
||||
import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.culture.models.ActivityTissue;
|
||||
@@ -151,8 +150,7 @@ public class ActivityCultureApplyActivityController {
|
||||
return Result.success();
|
||||
}
|
||||
if (tissue.getIsEnrollSystem()) {
|
||||
Sys_home_activity sysHomeActivity = tissue.covertToSysHomeActivity();
|
||||
activityCultureService.insertOrUpdate(sysHomeActivity);
|
||||
activityCultureService.syncHomeActivity(tissue);
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
+1
-3
@@ -9,7 +9,6 @@ import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.culture.models.ActivityTissue;
|
||||
import com.budwk.app.zhgh.activity.culture.service.ActivityCultureService;
|
||||
@@ -144,8 +143,7 @@ public class ActivityCultureAuditActivityController {
|
||||
tissue.setIsUnseal(true);
|
||||
activityCultureService.update(tissue);
|
||||
if (args.getInt("submitType") == 1) {
|
||||
Sys_home_activity sysHomeActivity = tissue.covertToSysHomeActivity();
|
||||
activityCultureService.insertOrUpdate(sysHomeActivity);
|
||||
activityCultureService.syncHomeActivity(tissue);
|
||||
}
|
||||
flowCommonService.executeTask(args);
|
||||
return Result.success();
|
||||
|
||||
+9
-3
@@ -74,9 +74,15 @@ public class ActivityCultureInfoManageController {
|
||||
@SaCheckPermission(value = {"activity.culture.infoManage.school", "activity.culture.infoManage.union", "activity.culture.infoManage.club"}, mode = SaMode.OR)
|
||||
public Result activityStatusChange(@Valid String id, @Valid Boolean isUnseal) {
|
||||
activityCultureService.update(Chain.make("isUnseal", isUnseal), Cnd.where("id", "=", id));
|
||||
activityCultureService.dao().update(Sys_home_activity.class,
|
||||
Chain.make("enable", isUnseal),
|
||||
Cnd.where("id", "=", id));
|
||||
ActivityTissue tissue = activityCultureService.fetch(id);
|
||||
tissue.setIsUnseal(isUnseal);
|
||||
if (Boolean.TRUE.equals(isUnseal)) {
|
||||
activityCultureService.syncHomeActivity(tissue);
|
||||
} else {
|
||||
activityCultureService.dao().update(Sys_home_activity.class,
|
||||
Chain.make("enable", false),
|
||||
Cnd.where("id", "=", id));
|
||||
}
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,4 +24,14 @@ public interface ActivityCultureService extends BaseService<ActivityTissue> {
|
||||
Object pageData(PageForm page, String year, String name, String unionId, Integer activity_type);
|
||||
|
||||
NutMap findOne(String id);
|
||||
|
||||
/**
|
||||
* 同步文化活动到首页活动表。
|
||||
* 1. 非报名类活动不推送首页,直接清理首页记录。
|
||||
* 2. 校工会活动没有审核流,提交后默认可推首页。
|
||||
* 3. 分工会、协会活动仅在已审核通过或已存在首页记录时更新首页信息。
|
||||
*
|
||||
* @param tissue 文化活动
|
||||
*/
|
||||
void syncHomeActivity(ActivityTissue tissue);
|
||||
}
|
||||
|
||||
+37
@@ -5,6 +5,7 @@ import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.model.Audit;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_home_activity;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService;
|
||||
@@ -80,6 +81,7 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
|
||||
@Override
|
||||
public void doEditActivity(ActivityTissue tissue) {
|
||||
update(tissue);
|
||||
syncHomeActivity(tissue);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -123,6 +125,7 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
|
||||
cnd.andEX("tissue.projectTypeCode", "!=", "50004");
|
||||
cnd.andEX("tissue.unionId", "=", unionId);
|
||||
cnd.andEX("tissue.activity_type", "=", activity_type);
|
||||
cnd.groupBy("tissue.id");
|
||||
|
||||
if (Strings.isNotBlank(name)) {
|
||||
cnd.where().andLike("tissue.name", name);
|
||||
@@ -188,4 +191,38 @@ public class ActivityCultureServiceImpl extends BaseServiceImpl<ActivityTissue>
|
||||
|
||||
return nutMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void syncHomeActivity(ActivityTissue tissue) {
|
||||
if (tissue == null || Strings.isBlank(tissue.getId())) {
|
||||
return;
|
||||
}
|
||||
// 非报名活动不需要出现在首页,编辑成活动管理模式时同步移除首页记录。
|
||||
if (!Boolean.TRUE.equals(tissue.getIsEnrollSystem())) {
|
||||
dao().delete(Sys_home_activity.class, tissue.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
Sys_home_activity oldHomeActivity = dao().fetch(Sys_home_activity.class, tissue.getId());
|
||||
boolean canCreateHomeActivity = (tissue.getActivity_type() != null
|
||||
&& tissue.getActivity_type() == 40001)
|
||||
|| Boolean.TRUE.equals(tissue.getIsUnseal())
|
||||
|| oldHomeActivity != null;
|
||||
if (!canCreateHomeActivity) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sys_home_activity sysHomeActivity = tissue.covertToSysHomeActivity();
|
||||
// 校工会文化活动没有审核环节,前端未回传启用状态时默认直接上首页。
|
||||
if (tissue.getActivity_type() != null && tissue.getActivity_type() == 40001 && tissue.getIsUnseal() == null) {
|
||||
sysHomeActivity.setEnable(true);
|
||||
}
|
||||
// 保留首页管理中手工设置的置顶、大图和排序,避免活动编辑时被覆盖。
|
||||
if (oldHomeActivity != null) {
|
||||
sysHomeActivity.setTop(oldHomeActivity.getTop());
|
||||
sysHomeActivity.setPush(oldHomeActivity.getPush());
|
||||
sysHomeActivity.setSortNo(oldHomeActivity.getSortNo());
|
||||
}
|
||||
dao().insertOrUpdate(sysHomeActivity);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -60,6 +60,7 @@ public class H5ActivityWorksUploadCollectionController {
|
||||
awc.*
|
||||
FROM
|
||||
`activity_works_collection` awc
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("YEAR(awc.startDateTime)", "=", year);
|
||||
@@ -68,9 +69,9 @@ public class H5ActivityWorksUploadCollectionController {
|
||||
cnd.and(new Static("now() > awc.startDateTime and now() < awc.endDateTime"));
|
||||
}//查询已结束的
|
||||
else if (activityType == 3) {
|
||||
cnd.and(new Static("now() > awc.startDateTime"));
|
||||
cnd.and(new Static("now() >= awc.endDateTime"));
|
||||
} else if (activityType == 4) {
|
||||
cnd.and(new Static("now() < awc.endDateTime"));
|
||||
cnd.and(new Static("now() < awc.startDateTime"));
|
||||
}
|
||||
cnd.and("awc.enable", "=", 1);
|
||||
cnd.and("awc.type", "=", 1);
|
||||
|
||||
+19
-8
@@ -28,6 +28,7 @@ import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.web.controllers.open.commons.service.CommonService;
|
||||
import com.budwk.app.zhgh.club.model.ClubUser;
|
||||
import com.budwk.app.zhgh.club.model.ClubUserApply;
|
||||
import com.budwk.app.zhgh.club.service.ClubUserJoinService;
|
||||
import com.budwk.app.zhgh.staffbenefit.condolence.model.Condolence;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
@@ -64,6 +65,8 @@ public class ClubUserJoinApplyController {
|
||||
private FlowEngine flowEngine;
|
||||
@Inject
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private ClubUserJoinService clubUserJoinService;
|
||||
|
||||
@At("/")
|
||||
@SaCheckPermission("club.join.apply")
|
||||
@@ -112,6 +115,8 @@ public class ClubUserJoinApplyController {
|
||||
clubUserApply.setRoleCode(RoleConstant.CLUB_MEMBER.name());
|
||||
clubUserApply.setMode(true);
|
||||
clubUserApply.setApplyDate(new Date());
|
||||
clubUserApply.setJoinTime(clubUserJoinService.resolveJoinTime(clubUserApply.getClubId(), clubUserApply.getUserId()));
|
||||
clubUserApply.setExitTime(null);
|
||||
dao.insertOrUpdate(clubUserApply);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -124,12 +129,10 @@ public class ClubUserJoinApplyController {
|
||||
public Result submit(@Param("data") ClubUserApply clubUserApply,
|
||||
@Param("mode") Boolean mode) {
|
||||
if(mode == false) {
|
||||
clubUserApply = dao.fetch(
|
||||
ClubUserApply.class,
|
||||
Cnd.where("userId", "=", SecurityUtil.getUserId())
|
||||
.and("clubId", "=", clubUserApply.getClubId())
|
||||
.desc("applyDate")
|
||||
);
|
||||
clubUserApply = clubUserJoinService.buildExitApply(clubUserApply.getClubId(), SecurityUtil.getUserId());
|
||||
if (ObjectUtil.isEmpty(clubUserApply)) {
|
||||
return Result.error("当前不是该社团成员,无法申请退出!");
|
||||
}
|
||||
}
|
||||
ClubUserApply userApply = dao.fetch(ClubUserApply.class, Cnd.where("userId", "=", clubUserApply.getUserId()).and("clubId", "=", clubUserApply.getClubId()).and("mode", "=", mode).desc(ClubUserApply::getApplyDate));
|
||||
if (ObjectUtil.isNotEmpty(userApply) && StrUtil.isNotBlank(userApply.getId())) {
|
||||
@@ -142,9 +145,17 @@ public class ClubUserJoinApplyController {
|
||||
if(!mode) {
|
||||
clubUserApply.setId(null);
|
||||
}
|
||||
clubUserApply.setRoleCode(RoleConstant.CLUB_MEMBER.name());
|
||||
clubUserApply.setMode(mode);
|
||||
clubUserApply.setApplyDate(new Date());
|
||||
Date applyDate = new Date();
|
||||
clubUserApply.setApplyDate(applyDate);
|
||||
if (mode) {
|
||||
clubUserApply.setRoleCode(RoleConstant.CLUB_MEMBER.name());
|
||||
clubUserApply.setJoinTime(clubUserJoinService.resolveJoinTime(clubUserApply.getClubId(), clubUserApply.getUserId()));
|
||||
clubUserApply.setExitTime(null);
|
||||
} else {
|
||||
clubUserApply.setJoinTime(clubUserJoinService.resolveJoinTime(clubUserApply.getClubId(), clubUserApply.getUserId()));
|
||||
clubUserApply.setExitTime(applyDate);
|
||||
}
|
||||
dao.insertOrUpdate(clubUserApply);
|
||||
|
||||
// 开启流程实例
|
||||
|
||||
+19
-1
@@ -22,6 +22,7 @@ import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.club.model.*;
|
||||
import com.budwk.app.zhgh.club.param.ClubUserPageForm;
|
||||
import com.budwk.app.zhgh.club.service.SysClubInfoManageService;
|
||||
import com.budwk.app.zhgh.club.service.SysClubService;
|
||||
import com.budwk.app.zhgh.club.service.impl.SysClubUserServiceImpl;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
@@ -64,6 +65,8 @@ public class ClubChangeManagerController {
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private SysClubInfoManageService infoManageService;
|
||||
@Inject
|
||||
private SysClubService sysClubService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/club/infoManage/change/index.html")
|
||||
@@ -102,7 +105,10 @@ public class ClubChangeManagerController {
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
List<String> clubIdList = sysClubService.getMyManageClub().stream().map(SysClub::getId).toList();
|
||||
cnd.and("info.clubId", "in", clubIdList);
|
||||
}
|
||||
cnd.andEX("year(info.creatTime)", "=", pageForm.getYear());
|
||||
if (StrUtil.isNotBlank(pageForm.getClubName())) {
|
||||
cnd.and("club.clubName", "LIKE", "%" + pageForm.getClubName() + "%");
|
||||
@@ -112,6 +118,7 @@ public class ClubChangeManagerController {
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
cnd.groupBy("info.id");
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = infoManageService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
List<NutMap> listMap = pagination.getList(NutMap.class);
|
||||
@@ -130,6 +137,17 @@ public class ClubChangeManagerController {
|
||||
@SaCheckPermission("club.infoManage.change")
|
||||
@SLog(tag = "社团管理系统-信息管理", msg = "提交变更理事机构")
|
||||
public Object submit(@Param("data") SysClubManager clubManager) {
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(SysClubManager::getClubId, "=", clubManager.getClubId());
|
||||
if (StrUtil.isNotBlank(clubManager.getId())) {
|
||||
cnd.and(SysClubManager::getId, "!=", clubManager.getId());
|
||||
}
|
||||
List<SysClubManager> managerList = dao.query(SysClubManager.class, cnd);
|
||||
List<String> pendingProcessIds = managerList.stream().map(SysClubManager::getId).toList();
|
||||
int pendingCount = dao.count(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "in", pendingProcessIds).and(ProcessInstance::getState, "not in", List.of(ProcessInstanceStateEnum.FINISHED.getCode(), ProcessInstanceStateEnum.REJECT.getCode())));
|
||||
if (pendingCount > 0) {
|
||||
return Result.error("您有该社团的申请记录尚未完成,请核对!");
|
||||
}
|
||||
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
String errMsg = "校工会审核" + clubManager.getPeriod() + "的换届报告通过后才能变更理事成员";
|
||||
|
||||
+9
-1
@@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
@@ -15,6 +16,7 @@ import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.club.model.SysClub;
|
||||
import com.budwk.app.zhgh.club.model.SysClubRefresh;
|
||||
@@ -58,6 +60,8 @@ public class ClubRefreshReportController {
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private SysClubService sysClubService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/club/infoManage/refreshReport/index.html")
|
||||
@@ -96,7 +100,10 @@ public class ClubRefreshReportController {
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
List<String> clubIdList = sysClubService.getMyManageClub().stream().map(SysClub::getId).toList();
|
||||
cnd.and("info.clubId", "in", clubIdList);
|
||||
}
|
||||
cnd.andEX("year(info.creatTime)", "=", pageForm.getYear());
|
||||
if (StrUtil.isNotBlank(pageForm.getClubName())) {
|
||||
cnd.and("club.clubName", "LIKE", "%" + pageForm.getClubName() + "%");
|
||||
@@ -119,6 +126,7 @@ public class ClubRefreshReportController {
|
||||
public Object submit(@Param("data") SysClubRefresh clubRefresh) {
|
||||
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(SysClubRefresh::getClubId, "=", clubRefresh.getClubId());
|
||||
if(StrUtil.isNotBlank(clubRefresh.getId())) {
|
||||
cnd.and(SysClubRefresh::getId, "!=", clubRefresh.getId());
|
||||
}
|
||||
|
||||
+9
-1
@@ -4,6 +4,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
@@ -15,6 +16,7 @@ import com.budwk.app.flow.entity.ProcessTask;
|
||||
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
|
||||
import com.budwk.app.flow.enums.ProcessSubmitTypeEnum;
|
||||
import com.budwk.app.flow.service.FlowCommonService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.club.model.SysClub;
|
||||
import com.budwk.app.zhgh.club.model.SysClubRefresh;
|
||||
@@ -59,6 +61,8 @@ public class ClubRuleUpdateController {
|
||||
private FlowCommonService flowCommonService;
|
||||
@Inject
|
||||
private Dao dao;
|
||||
@Inject
|
||||
private SysClubService sysClubService;
|
||||
|
||||
@At("")
|
||||
@Ok("beetl:/platform/zhgh/club/infoManage/ruleUpdate/index.html")
|
||||
@@ -97,7 +101,10 @@ public class ClubRuleUpdateController {
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
List<String> clubIdList = sysClubService.getMyManageClub().stream().map(SysClub::getId).toList();
|
||||
cnd.and("info.clubId", "in", clubIdList);
|
||||
}
|
||||
cnd.andEX("year(info.creatTime)", "=", pageForm.getYear());
|
||||
if (StrUtil.isNotBlank(pageForm.getClubName())) {
|
||||
cnd.and("club.clubName", "LIKE", "%" + pageForm.getClubName() + "%");
|
||||
@@ -120,6 +127,7 @@ public class ClubRuleUpdateController {
|
||||
public Object submit(@Param("data")SysClubRule clubRule) {
|
||||
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and(SysClubRule::getClubId, "=", clubRule.getClubId());
|
||||
if(StrUtil.isNotBlank(clubRule.getId())) {
|
||||
cnd.and(SysClubRule::getId, "!=", clubRule.getId());
|
||||
}
|
||||
|
||||
@@ -85,4 +85,14 @@ public class ClubUserApply extends BaseModel {
|
||||
@Comment("申请时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date applyDate;
|
||||
|
||||
@Column
|
||||
@Comment("入会时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date joinTime;
|
||||
|
||||
@Column
|
||||
@Comment("退会时间")
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date exitTime;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class SysClubExamineRegister extends BaseModel {
|
||||
|
||||
@Column
|
||||
@Comment("社团名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@ColDefine(type = ColType.VARCHAR)
|
||||
private String clubName;
|
||||
|
||||
@Column
|
||||
|
||||
@@ -4,4 +4,25 @@ import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.club.model.ClubUserApply;
|
||||
|
||||
public interface ClubUserJoinService extends BaseService<ClubUserApply> {
|
||||
|
||||
/**
|
||||
* 构造退会申请数据。
|
||||
* 当用户没有历史入会申请记录时,使用当前社团成员关系和人员基础信息兜底生成一份退会申请,
|
||||
* 以保证会长等通过社团注册直接入会的人员也能正常发起退会流程。
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param userId 用户ID
|
||||
* @return 退会申请对象,不存在当前成员关系时返回null
|
||||
*/
|
||||
ClubUserApply buildExitApply(String clubId, String userId);
|
||||
|
||||
/**
|
||||
* 获取社团成员的入会时间,优先取历史有效入会申请记录,
|
||||
* 没有时兜底为社团创办时间。
|
||||
*
|
||||
* @param clubId 社团ID
|
||||
* @param userId 用户ID
|
||||
* @return 入会时间
|
||||
*/
|
||||
java.util.Date resolveJoinTime(String clubId, String userId);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.zhgh.club.param.ClubUserPageForm;
|
||||
import com.budwk.app.zhgh.club.vo.ClubCommonPageVo;
|
||||
import com.budwk.app.zhgh.club.vo.ClubUserCommonPageVo;
|
||||
import com.budwk.app.zhgh.club.vo.ClubUserJoinVo;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -23,8 +24,12 @@ public interface SysClubInfoManageService extends BaseService<ClubCommonPageVo>
|
||||
|
||||
Pagination<ClubUserCommonPageVo> infoManageUserPageData(@Valid ClubUserPageForm pageForm);
|
||||
|
||||
Pagination<ClubUserCommonPageVo> exitManagePageData(@Valid ClubUserPageForm pageForm);
|
||||
|
||||
Pagination<ClubUserCommonPageVo> clubManagePersonAuditPageData(@Valid ClubUserPageForm pageForm);
|
||||
|
||||
ClubUserJoinVo exitManageInfo(String id);
|
||||
|
||||
List<NutMap> getClubTreeData();
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,94 @@
|
||||
package com.budwk.app.zhgh.club.service.impl;
|
||||
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.budwk.app.sys.views.View_user;
|
||||
import com.budwk.app.zhgh.club.model.ClubUser;
|
||||
import com.budwk.app.zhgh.club.model.ClubUserApply;
|
||||
import com.budwk.app.zhgh.club.model.SysClub;
|
||||
import com.budwk.app.zhgh.club.service.ClubUserJoinService;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class ClubUserJoinServiceImpl extends BaseServiceImpl<ClubUserApply> implements ClubUserJoinService {
|
||||
public ClubUserJoinServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClubUserApply buildExitApply(String clubId, String userId) {
|
||||
// 优先复用最近一次申请记录中的补充信息,避免用户重复填写基础资料。
|
||||
ClubUserApply latestApply = fetch(
|
||||
Cnd.where("userId", "=", userId)
|
||||
.and("clubId", "=", clubId)
|
||||
.desc(ClubUserApply::getApplyDate)
|
||||
);
|
||||
if (latestApply != null) {
|
||||
latestApply.setId(null);
|
||||
return latestApply;
|
||||
}
|
||||
|
||||
// 对于会长等注册社团时直接入会的人员,没有申请记录时从当前成员信息兜底生成退会申请。
|
||||
ClubUser clubUser = dao().fetch(ClubUser.class, Cnd.where("clubId", "=", clubId).and("userId", "=", userId));
|
||||
if (clubUser == null) {
|
||||
return null;
|
||||
}
|
||||
View_user viewUser = dao().fetch(View_user.class, Cnd.where("id", "=", userId));
|
||||
|
||||
ClubUserApply clubUserApply = new ClubUserApply();
|
||||
clubUserApply.setClubId(clubId);
|
||||
clubUserApply.setUserId(userId);
|
||||
clubUserApply.setClubPosition(clubUser.getClubPosition());
|
||||
clubUserApply.setEmail(clubUser.getEmail());
|
||||
clubUserApply.setAvatar(clubUser.getAvatar());
|
||||
clubUserApply.setSameTimeJoinOtherClubSituation(clubUser.getSameTimeJoinOtherClubSituation());
|
||||
clubUserApply.setAwardsExperience(clubUser.getAwardsExperience());
|
||||
clubUserApply.setJoinTime(resolveJoinTime(clubId, userId));
|
||||
|
||||
List<String> roleCodes = clubUser.getRoleCode();
|
||||
if (roleCodes != null && !roleCodes.isEmpty()) {
|
||||
String exitRoleCode = roleCodes.stream()
|
||||
.filter(roleCode -> !RoleConstant.CLUB_MEMBER.name().equals(roleCode))
|
||||
.findFirst()
|
||||
.orElse(RoleConstant.CLUB_MEMBER.name());
|
||||
clubUserApply.setRoleCode(exitRoleCode);
|
||||
} else {
|
||||
clubUserApply.setRoleCode(RoleConstant.CLUB_MEMBER.name());
|
||||
}
|
||||
|
||||
if (viewUser != null) {
|
||||
clubUserApply.setBirthday(viewUser.getBirthday());
|
||||
clubUserApply.setMobile(viewUser.getMobile());
|
||||
if (clubUserApply.getEmail() == null) {
|
||||
clubUserApply.setEmail(viewUser.getEmail());
|
||||
}
|
||||
if (clubUserApply.getAvatar() == null) {
|
||||
clubUserApply.setAvatar(viewUser.getAvatar());
|
||||
}
|
||||
}
|
||||
return clubUserApply;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date resolveJoinTime(String clubId, String userId) {
|
||||
ClubUserApply latestJoinApply = fetch(
|
||||
Cnd.where("userId", "=", userId)
|
||||
.and("clubId", "=", clubId)
|
||||
.and("mode", "=", true)
|
||||
.desc(ClubUserApply::getApplyDate)
|
||||
);
|
||||
if (latestJoinApply != null && latestJoinApply.getJoinTime() != null) {
|
||||
return latestJoinApply.getJoinTime();
|
||||
}
|
||||
|
||||
SysClub club = dao().fetch(SysClub.class, clubId);
|
||||
if (club != null && club.getFoundTime() != null) {
|
||||
return DateUtil.parse(club.getFoundTime());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+108
-1
@@ -20,6 +20,7 @@ import com.budwk.app.zhgh.club.service.SysClubInfoManageService;
|
||||
import com.budwk.app.zhgh.club.service.SysClubService;
|
||||
import com.budwk.app.zhgh.club.vo.ClubCommonPageVo;
|
||||
import com.budwk.app.zhgh.club.vo.ClubUserCommonPageVo;
|
||||
import com.budwk.app.zhgh.club.vo.ClubUserJoinVo;
|
||||
import com.deepoove.poi.XWPFTemplate;
|
||||
import com.deepoove.poi.config.Configure;
|
||||
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
|
||||
@@ -139,11 +140,27 @@ public class SysClubInfoManageServiceImpl extends BaseServiceImpl<ClubCommonPage
|
||||
u.unitid as unitId,
|
||||
u.mobile,
|
||||
club.clubName,
|
||||
u.unitname as unitName
|
||||
u.unitname as unitName,
|
||||
DATE_FORMAT(IFNULL(joinInfo.joinTime, club.foundTime), '%Y-%m-%d %H:%i:%s') as joinTime
|
||||
FROM
|
||||
club_user scu
|
||||
LEFT JOIN sys_club club ON scu.clubId = club.id
|
||||
RIGHT JOIN `vw_user` u ON scu.userId = u.id
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
joinApply.userId,
|
||||
joinApply.clubId,
|
||||
MAX(joinApply.joinTime) AS joinTime
|
||||
FROM
|
||||
club_user_apply joinApply
|
||||
LEFT JOIN wf_process_instance joinIns ON joinIns.businessNo = joinApply.id
|
||||
WHERE
|
||||
joinApply.mode = true
|
||||
AND joinIns.state = 20
|
||||
GROUP BY
|
||||
joinApply.userId,
|
||||
joinApply.clubId
|
||||
) joinInfo ON joinInfo.userId = scu.userId AND joinInfo.clubId = scu.clubId
|
||||
$condition
|
||||
$order
|
||||
""");
|
||||
@@ -206,6 +223,96 @@ public class SysClubInfoManageServiceImpl extends BaseServiceImpl<ClubCommonPage
|
||||
return listPageVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination<ClubUserCommonPageVo> exitManagePageData(ClubUserPageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
info.id,
|
||||
info.clubId,
|
||||
info.userId,
|
||||
info.roleCode AS applyRoleCode,
|
||||
info.clubPosition,
|
||||
info.email,
|
||||
info.mobile,
|
||||
info.birthday,
|
||||
info.avatar,
|
||||
info.sameTimeJoinOtherClubSituation,
|
||||
info.awardsExperience,
|
||||
info.signature,
|
||||
info.applyDate,
|
||||
u.username AS userName,
|
||||
u.loginname AS loginName,
|
||||
u.sex,
|
||||
u.personType,
|
||||
u.userState,
|
||||
club.clubName,
|
||||
u.unitname AS unitName,
|
||||
DATE_FORMAT(IFNULL(info.joinTime, club.foundTime), '%Y-%m-%d %H:%i:%s') AS joinTime,
|
||||
DATE_FORMAT(info.exitTime, '%Y-%m-%d %H:%i:%s') AS exitTime,
|
||||
ins.id AS instanceId,
|
||||
ins.businessNo,
|
||||
ins.state instanceState,
|
||||
ins.variable instanceVariable,
|
||||
ins.processDefineId instanceProcessDefineId
|
||||
FROM
|
||||
club_user_apply info
|
||||
LEFT JOIN sys_club club ON club.id = info.clubId
|
||||
LEFT JOIN vw_user u ON u.id = info.userId
|
||||
LEFT JOIN wf_process_instance ins ON ins.businessNo = info.id
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("info.mode", "=", false);
|
||||
cnd.and("ins.state", "=", ProcessInstanceStateEnum.FINISHED.getCode());
|
||||
cnd.andEX("info.clubId", "=", pageForm.getClubId());
|
||||
cnd.andEX("u.personType", "=", pageForm.getPersonType());
|
||||
cnd.andEX("u.userState", "=", pageForm.getUserState());
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
cnd.and(Cnd.exps("u.loginname", "like", "%" + pageForm.getSearchKeyword() + "%").or("u.username", "like", "%" + pageForm.getSearchKeyword() + "%"));
|
||||
}
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
List<String> clubIdList = commonService.findUserRoleByRoleCode(List.of(RoleConstant.CLUB_PRESIDENT.name(), RoleConstant.CLUB_VICE_PRESIDENT.name(), RoleConstant.CLUB_SECRETARY.name(), RoleConstant.CLUB_VICE_SECRETARY.name(), RoleConstant.CLUB_OPERATOR.name()));
|
||||
List<Sys_user_role> clubList = dao().query(Sys_user_role.class, Cnd.where("roleId", "in", clubIdList).and("userId", "=", SecurityUtil.getUserId()).and("clubId", "is not", null));
|
||||
cnd.and("info.clubId", "in", clubList.stream().map(Sys_user_role::getClubId).toList());
|
||||
}
|
||||
cnd.groupBy("info.id");
|
||||
cnd.desc("info.applyDate");
|
||||
sql.setCondition(cnd);
|
||||
Pagination<ClubUserCommonPageVo> pagination = listPageVO(pageForm, sql, ClubUserCommonPageVo.class);
|
||||
List<ClubUserCommonPageVo> list = pagination.getList(ClubUserCommonPageVo.class);
|
||||
for (ClubUserCommonPageVo vo : list) {
|
||||
vo.setRoleName(SysClubUserServiceImpl.convertRoleName(List.of(vo.getApplyRoleCode())));
|
||||
}
|
||||
pagination.setList(list);
|
||||
return pagination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClubUserJoinVo exitManageInfo(String id) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
cua.*,
|
||||
club.clubName,
|
||||
u.loginname AS loginName,
|
||||
u.username AS userName,
|
||||
u.sex,
|
||||
u.mobile,
|
||||
u.unitName,
|
||||
u.unionName,
|
||||
u.technicalTitle,
|
||||
u.education,
|
||||
u.academicDegree,
|
||||
u.position
|
||||
FROM
|
||||
club_user_apply cua
|
||||
LEFT JOIN vw_user u ON u.id = cua.userId
|
||||
LEFT JOIN sys_club club ON club.id = cua.clubId
|
||||
WHERE cua.id = @id
|
||||
""");
|
||||
sql.setParam("id", id);
|
||||
return fetchVO(sql, ClubUserJoinVo.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pagination<ClubUserCommonPageVo> clubManagePersonAuditPageData(ClubUserPageForm pageForm) {
|
||||
Sql sql = Sqls.create("""
|
||||
|
||||
@@ -29,6 +29,9 @@ public class ClubUserCommonPageVo extends ClubUser {
|
||||
private String unionName;
|
||||
private String birthday;
|
||||
private String unionId;
|
||||
private String joinTime;
|
||||
private String exitTime;
|
||||
private String applyRoleCode;
|
||||
|
||||
private String roleName;
|
||||
}
|
||||
|
||||
+3
-1
@@ -80,7 +80,9 @@ public class OutlayManageClubQueryController {
|
||||
SELECT * FROM `outlay_manage_club` $condition
|
||||
""");
|
||||
cnd.andEX("year", "=", year);
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
// if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
// 现逻辑:系统管理员、校工会社团管理员可查看全部社团分页数据,会长仅查看自己负责的社团。
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_CLUB_ADMIN.name())) {
|
||||
List<String> roleIds = sysRoleService.getRoleIdsByCode(List.of(RoleConstant.CLUB_PRESIDENT, RoleConstant.CLUB_SECRETARY));
|
||||
List<Sys_user_role> userRoles = clubQueryService.dao().query(Sys_user_role.class,
|
||||
Cnd.where("userId", "=", SecurityUtil.getUserId())
|
||||
|
||||
+1
-1
@@ -75,7 +75,7 @@ public class OutlayManageClub extends BaseModel implements Serializable {
|
||||
|
||||
@Column
|
||||
@Comment("社团名称")
|
||||
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||
@ColDefine(type = ColType.VARCHAR)
|
||||
private String clubName;
|
||||
|
||||
@Column
|
||||
|
||||
+25
-79
@@ -27,6 +27,7 @@ import com.budwk.app.zhgh.staffbenefit.condolence.service.CondolenceTypeService;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
||||
import com.budwk.app.zhgh.staffbenefit.condolence.model.CondolenceType;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.vo.UnionReimburseBankHistoryVO;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -85,19 +86,7 @@ public class UnionReimburseApplyController {
|
||||
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
|
||||
@SLog(type = "unionReimburse", tag = "工会报销-报销申请", msg = "保存报销申请")
|
||||
public Result save(@Param("data") UnionReimburse unionReimburse) {
|
||||
if (StrUtil.isBlank(unionReimburse.getId())) {
|
||||
unionReimburse.setCreateTime(new Date());
|
||||
String documentNo = generateDocumentNo();
|
||||
unionReimburse.setDocumentNo(documentNo);
|
||||
}
|
||||
unionReimburse.setStateId(1);//待提交
|
||||
if (("UNION_REIMBURSE_PROJECT_1").equals(unionReimburse.getReimburseProject())){
|
||||
unionReimburse.setRealMoney(unionReimburse.getCondolenceMoney());
|
||||
}else {
|
||||
unionReimburse.setRealMoney(unionReimburse.getMoney());
|
||||
}
|
||||
dao.insertOrUpdate(unionReimburse);
|
||||
return Result.success();
|
||||
return unionReimburseService.saveApply(unionReimburse, 1);
|
||||
}
|
||||
|
||||
@At
|
||||
@@ -105,18 +94,10 @@ public class UnionReimburseApplyController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
|
||||
public Result submit(@Param("data") UnionReimburse unionReimburse) {
|
||||
if (StrUtil.isBlank(unionReimburse.getId())) {
|
||||
unionReimburse.setCreateTime(new Date());
|
||||
String documentNo = generateDocumentNo();
|
||||
unionReimburse.setDocumentNo(documentNo);
|
||||
Result result = unionReimburseService.saveApply(unionReimburse, 2);
|
||||
if (result.getCode() != 0) {
|
||||
return result;
|
||||
}
|
||||
unionReimburse.setStateId(2);//待审核
|
||||
if (("UNION_REIMBURSE_PROJECT_1").equals(unionReimburse.getReimburseProject())){
|
||||
unionReimburse.setRealMoney(unionReimburse.getCondolenceMoney());
|
||||
}else {
|
||||
unionReimburse.setRealMoney(unionReimburse.getMoney());
|
||||
}
|
||||
dao.insertOrUpdate(unionReimburse);
|
||||
// // 开启流程实例
|
||||
// Dict args = Dict.create();
|
||||
// args.set(FlowConst.SUBMIT_TYPE, ProcessSubmitTypeEnum.APPLY.getCode());
|
||||
@@ -153,7 +134,7 @@ public class UnionReimburseApplyController {
|
||||
@SaCheckLogin
|
||||
@ApiOperation("获取当前登录人的申请信息")
|
||||
public Result info(@Param("id") String id) {
|
||||
UnionReimburse unionReimburse = dao.fetch(UnionReimburse.class, id);
|
||||
UnionReimburse unionReimburse = unionReimburseService.getApplyForm(id);
|
||||
return Result.success(unionReimburse);
|
||||
}
|
||||
|
||||
@@ -190,14 +171,9 @@ public class UnionReimburseApplyController {
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.and(View_user::getId, "!=", SecurityUtil.getUserId());
|
||||
/*if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
if (AuthUtil.hasRoleOr(RoleConstant.BRANCH_UNION_ADMIN.name(), RoleConstant.BRANCH_UNION_CHAIRMAN.name())) {
|
||||
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
|
||||
} else {
|
||||
cnd.and(View_user::getId, "=", SecurityUtil.getUserId());
|
||||
}
|
||||
|
||||
}*/
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
cnd.and(View_user::getUnionId, "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
sql.setCondition(cnd);
|
||||
Pagination pagination = unionReimburseService.listPageMap(1, 50, sql);
|
||||
return Result.success(pagination.getList());
|
||||
@@ -215,20 +191,25 @@ public class UnionReimburseApplyController {
|
||||
@ApiOperation("查询厉害账号信息")
|
||||
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
|
||||
public Result findUserBankHistory(String payer) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT DISTINCT
|
||||
bankCardNumber,
|
||||
bankOfDeposit
|
||||
FROM union_reimburse
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.andEX("payer", "=", payer);
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> result = unionReimburseService.listMap(sql);
|
||||
List<UnionReimburseBankHistoryVO> result = unionReimburseService.getUserBankHistory(payer);
|
||||
return Result.success(result);
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("校验发票号码是否重复")
|
||||
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
|
||||
public Result checkInvoiceDuplicate(String invoiceNo, String reimburseId) {
|
||||
Result result = unionReimburseService.checkInvoiceDuplicate(invoiceNo, reimburseId);
|
||||
return result == null ? Result.success() : result;
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("自动识别发票信息")
|
||||
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
|
||||
public Result recognizeInvoice(String fileId, @Param("verifySwitch") Boolean verifySwitch) {
|
||||
return unionReimburseService.recognizeInvoice(fileId, verifySwitch);
|
||||
}
|
||||
|
||||
|
||||
@At
|
||||
@ApiOperation("查询校工会经费余额")
|
||||
@@ -281,39 +262,4 @@ public class UnionReimburseApplyController {
|
||||
// 如果没有找到该社团的经费记录,返回0
|
||||
return Result.success(0.0);
|
||||
}
|
||||
@At
|
||||
@ApiOperation("生成文件编号")
|
||||
private String generateDocumentNo() {
|
||||
int currentYear = DateUtil.thisYear();
|
||||
String yearPrefix = String.valueOf(currentYear);
|
||||
|
||||
org.nutz.dao.Cnd cnd = org.nutz.dao.Cnd.where("documentNo", "LIKE", yearPrefix + "%");
|
||||
cnd.desc("documentNo");
|
||||
cnd.limit(1);
|
||||
|
||||
List<UnionReimburse> list = dao.query(UnionReimburse.class, cnd);
|
||||
|
||||
int nextSeq = 1; // 默认从01开始
|
||||
if (!list.isEmpty()) {
|
||||
String maxNo = list.get(0).getDocumentNo();
|
||||
if (maxNo != null && maxNo.startsWith(yearPrefix)) {
|
||||
// 提取序号部分(去掉年份前缀)
|
||||
String seqPart = maxNo.substring(yearPrefix.length());
|
||||
try {
|
||||
int currentMaxSeq = Integer.parseInt(seqPart);
|
||||
nextSeq = currentMaxSeq + 1;
|
||||
} catch (NumberFormatException e) {
|
||||
// 如果解析失败,使用默认值1
|
||||
nextSeq = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化序号为两位数
|
||||
String seqStr = String.format("%02d", nextSeq);
|
||||
return yearPrefix + seqStr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+25
-2
@@ -3,11 +3,13 @@ package com.budwk.app.zhgh.dayofficework.unionReimburse.controller;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
import io.swagger.annotations.Api;
|
||||
@@ -105,6 +107,9 @@ public class UnionReimburseCertifierUserSignController {
|
||||
// 工会、单位名称查询条件
|
||||
cnd.andEX("info.unionId", "=", unionId);
|
||||
cnd.andEX("info.unitId", "=", unitId);
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("info.unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
|
||||
// 报销项目查询条件
|
||||
cnd.andEX("info.reimburseProject", "=", reimburseProject);
|
||||
@@ -116,10 +121,11 @@ public class UnionReimburseCertifierUserSignController {
|
||||
seg.orLike("info.loginName",pageForm.getSearchKeyword());
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
String orderField = normalizeSortField(pageForm.getPageOrderName());
|
||||
if (StrUtil.isAllBlank(orderField, pageForm.getPageOrderBy())) {
|
||||
cnd.desc("info.createTime");
|
||||
} else {
|
||||
cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
cnd.orderBy(orderField, PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
cnd.groupBy("t.id");
|
||||
cnd.desc("t.createdAt");
|
||||
@@ -128,4 +134,21 @@ public class UnionReimburseCertifierUserSignController {
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
private boolean isAdmin() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
}
|
||||
|
||||
private String normalizeSortField(String pageOrderName) {
|
||||
if (StrUtil.isBlank(pageOrderName)) {
|
||||
return null;
|
||||
}
|
||||
return switch (pageOrderName) {
|
||||
case "loginName" -> "info.loginName";
|
||||
case "unionName" -> "info.unionName";
|
||||
case "unitName" -> "info.unitName";
|
||||
case "createTime" -> "info.createTime";
|
||||
case "reimburseProject" -> "info.reimburseProject";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+43
-4
@@ -12,6 +12,7 @@ import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.sys.models.Sys_dict;
|
||||
@@ -93,6 +94,9 @@ public class UnionReimburseCollectController {
|
||||
// 工会、单位名称查询条件
|
||||
cnd.andEX("info.unionId", "=", unionId);
|
||||
cnd.andEX("info.unitId", "=", unitId);
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("info.unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
|
||||
// 报销项目查询条件
|
||||
cnd.andEX("info.reimburseProject", "=", reimburseProject);
|
||||
@@ -106,7 +110,7 @@ public class UnionReimburseCollectController {
|
||||
|
||||
cnd.and("info.stateId", "in", List.of(3, 2));
|
||||
|
||||
cnd.desc("info.createTime");
|
||||
applyListSort(cnd, pageForm);
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> pagination = unionReimburseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
@@ -149,7 +153,7 @@ public class UnionReimburseCollectController {
|
||||
cnd.andEX("YEAR(rei.createTime)", "=", year);
|
||||
cnd.andEX("u.unitid", "=", unitId);
|
||||
cnd.andEX("u.unionid", "=", unionId);
|
||||
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("u.unionid", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
cnd.desc("rei.createTime");
|
||||
@@ -166,8 +170,10 @@ public class UnionReimburseCollectController {
|
||||
|
||||
try{
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + new String(("收款人名册.xls").getBytes("utf-8"), "ISO8859-1"));
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), excelExportEntities, list);
|
||||
response.setHeader("Content-Disposition", "attachment;filename=" + new String(("收款人名册.xlsx").getBytes("utf-8"), "ISO8859-1"));
|
||||
ExportParams exportParams = new ExportParams();
|
||||
exportParams.setType(ExcelType.XSSF);
|
||||
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, excelExportEntities, list);
|
||||
workbook.write(response.getOutputStream());
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
@@ -197,6 +203,9 @@ public class UnionReimburseCollectController {
|
||||
Cnd cnd = buildCondition(year, unionId, unitId, reimburseProject, userName, "t1.");
|
||||
// 只查询流程实例状态为20的数据(已完成状态)
|
||||
cnd.and("ins.state", "=", 20);
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("t1.unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
cnd.desc("t1.createTime");
|
||||
|
||||
sql.setCondition(cnd);
|
||||
@@ -275,4 +284,34 @@ public class UnionReimburseCollectController {
|
||||
|
||||
return cnd;
|
||||
}
|
||||
|
||||
private boolean isAdmin() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* 收集页列表只允许固定字段排序,前端传入原序时回退到默认申请时间倒序。
|
||||
*/
|
||||
private void applyListSort(Cnd cnd, PageForm pageForm) {
|
||||
String orderField = normalizeSortField(pageForm.getPageOrderName());
|
||||
if (StrUtil.isAllBlank(orderField, pageForm.getPageOrderBy())) {
|
||||
cnd.desc("info.createTime");
|
||||
return;
|
||||
}
|
||||
cnd.orderBy(orderField, PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
|
||||
private String normalizeSortField(String pageOrderName) {
|
||||
if (StrUtil.isBlank(pageOrderName)) {
|
||||
return null;
|
||||
}
|
||||
return switch (pageOrderName) {
|
||||
case "loginName" -> "info.loginName";
|
||||
case "unionName" -> "info.unionName";
|
||||
case "unitName" -> "info.unitName";
|
||||
case "createTime" -> "info.createTime";
|
||||
case "reimburseProject" -> "info.reimburseProject";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+34
-1
@@ -9,14 +9,17 @@ import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.annotation.SLog;
|
||||
import com.budwk.app.base.model.Audit;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.base.utils.MoneyUtil;
|
||||
import com.budwk.app.base.utils.OfficePlusUtil;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.base.utils.SysOfficeTemplateUtil;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
@@ -133,6 +136,9 @@ public class UnionReimburseMineController {
|
||||
// 工会、单位名称查询条件
|
||||
cnd.andEX("info.unionId", "=", unionId);
|
||||
cnd.andEX("info.unitId", "=", unitId);
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("info.unionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
|
||||
// 报销项目查询条件
|
||||
cnd.andEX("info.reimburseProject", "=", reimburseProject);
|
||||
@@ -143,13 +149,40 @@ public class UnionReimburseMineController {
|
||||
seg.orLike("info.loginName", "%" + searchKeyword + "%");
|
||||
cnd.and(seg);
|
||||
}
|
||||
cnd.desc("info.createTime");
|
||||
applyListSort(cnd, pageForm);
|
||||
cnd.and("info.userId", "=", SecurityUtil.getUserId());
|
||||
sql.setCondition(cnd);
|
||||
Pagination<NutMap> pagination = unionReimburseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql);
|
||||
return Result.success(pagination);
|
||||
}
|
||||
|
||||
private boolean isAdmin() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
}
|
||||
|
||||
private void applyListSort(Cnd cnd, PageForm pageForm) {
|
||||
String orderField = normalizeSortField(pageForm.getPageOrderName());
|
||||
if (StrUtil.isAllBlank(orderField, pageForm.getPageOrderBy())) {
|
||||
cnd.desc("info.createTime");
|
||||
return;
|
||||
}
|
||||
cnd.orderBy(orderField, PageUtil.getOrder(pageForm.getPageOrderBy()));
|
||||
}
|
||||
|
||||
private String normalizeSortField(String pageOrderName) {
|
||||
if (StrUtil.isBlank(pageOrderName)) {
|
||||
return null;
|
||||
}
|
||||
return switch (pageOrderName) {
|
||||
case "loginName" -> "info.loginName";
|
||||
case "unionName" -> "info.unionName";
|
||||
case "unitName" -> "info.unitName";
|
||||
case "createTime" -> "info.createTime";
|
||||
case "reimburseProject" -> "info.reimburseProject";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
@At
|
||||
@ApiOperation("删除")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
|
||||
+8
-31
@@ -1,7 +1,5 @@
|
||||
package com.budwk.app.zhgh.dayofficework.unionReimburse.controller;
|
||||
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -10,15 +8,12 @@ import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.param.PageForm;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.PageUtil;
|
||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||
import org.nutz.dao.Chain;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
@@ -35,8 +30,6 @@ import org.nutz.mvc.annotation.Param;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static org.openjdk.nashorn.internal.runtime.regexp.joni.Config.log;
|
||||
|
||||
@IocBean
|
||||
@At("/platform/unionReimburse/review")
|
||||
@Ok("json:full")
|
||||
@@ -49,12 +42,12 @@ public class UnionReimburseReviewController {
|
||||
@Inject
|
||||
private UnionReimburseService unionReimburseService;
|
||||
|
||||
|
||||
@At("/index")
|
||||
@Ok("beetl:/platform/zhgh/dayofficework/unionReimburse/review/index.html")
|
||||
@SaCheckPermission("unionReimburse.review")
|
||||
public void index() {
|
||||
}
|
||||
|
||||
@At("/h5")
|
||||
@Ok("beetl:/platform/zhghh5/dayofficework/unionReimburse/review/index.html")
|
||||
@SaCheckPermission("h5.unionReimburse.review")
|
||||
@@ -71,37 +64,26 @@ public class UnionReimburseReviewController {
|
||||
String unitId,
|
||||
String reimburseProject) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
SELECT
|
||||
info.*
|
||||
FROM
|
||||
union_reimburse info
|
||||
$condition
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
|
||||
if (approval) {
|
||||
// 已审核:查询 stateId 为 3(报销成功)、4(拒绝)、5(退回)的记录
|
||||
cnd.and("info.stateId", "in", List.of(3, 4, 5));
|
||||
} else {
|
||||
// 未审核:只查询 stateId 为 2(待审核确认)的记录
|
||||
cnd.and("info.stateId", "=", 2);
|
||||
}
|
||||
// 年度查询条件
|
||||
cnd.andEX("year(info.createTime)", "=", year);
|
||||
|
||||
// 工会、单位名称查询条件
|
||||
cnd.andEX("info.unionId", "=", unionId);
|
||||
cnd.andEX("info.unitId", "=", unitId);
|
||||
|
||||
// 报销项目查询条件
|
||||
cnd.andEX("info.reimburseProject", "=", reimburseProject);
|
||||
|
||||
|
||||
// 姓名和工号查询条件
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.orLike("info.userName",pageForm.getSearchKeyword());
|
||||
seg.orLike("info.loginName",pageForm.getSearchKeyword());
|
||||
seg.orLike("info.userName", pageForm.getSearchKeyword());
|
||||
seg.orLike("info.loginName", pageForm.getSearchKeyword());
|
||||
cnd.and(seg);
|
||||
}
|
||||
if (StrUtil.isAllBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) {
|
||||
@@ -119,21 +101,18 @@ public class UnionReimburseReviewController {
|
||||
@ApiOperation("审核")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"unionReimburse.review", "h5.unionReimburse.review"}, mode = SaMode.OR)
|
||||
@SLog( tag = "审核工会报销", msg = "审核工会报销")
|
||||
public Result reviewTask(@Param("data") UnionReimburse unionReimburse,String submitType) {
|
||||
@SLog(tag = "审核工会报销", msg = "审核工会报销")
|
||||
public Result reviewTask(@Param("data") UnionReimburse unionReimburse, String submitType) {
|
||||
if (submitType == null || !List.of("3", "4", "5").contains(submitType)) {
|
||||
return Result.error("无效的审核操作类型");
|
||||
}
|
||||
|
||||
UnionReimburse dbRecord = dao.fetch(UnionReimburse.class, unionReimburse.getId());
|
||||
if (dbRecord == null) {
|
||||
return Result.error("记录不存在");
|
||||
}
|
||||
|
||||
dbRecord.setReviewTime(new Date());
|
||||
dbRecord.setStateId(Integer.parseInt(submitType));
|
||||
dbRecord.setReviewOpinion(unionReimburse.getReviewOpinion());
|
||||
|
||||
dao.update(dbRecord);
|
||||
return Result.success();
|
||||
}
|
||||
@@ -142,7 +121,7 @@ public class UnionReimburseReviewController {
|
||||
@ApiOperation("一键审核")
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission(value = {"unionReimburse.review", "h5.unionReimburse.review"}, mode = SaMode.OR)
|
||||
@SLog( tag = "一键审核", msg = "一键审核")
|
||||
@SLog(tag = "一键审核", msg = "一键审核")
|
||||
public Result allReview() {
|
||||
try {
|
||||
List<UnionReimburse> reimbursements = unionReimburseService.query(Cnd.where("stateId", "=", 2));
|
||||
@@ -158,6 +137,4 @@ public class UnionReimburseReviewController {
|
||||
return Result.error("一键审核失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+8
@@ -6,11 +6,14 @@ import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.page.Pagination;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||
import com.budwk.app.flow.engine.FlowEngine;
|
||||
import com.budwk.app.sys.services.SysDictService;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.param.UnionReimbursePageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
import io.swagger.annotations.Api;
|
||||
@@ -93,6 +96,8 @@ public class UnionReimburseStatisticsController {
|
||||
}
|
||||
if (Strings.isNotBlank(unionId)) {
|
||||
sql.setVar("unionIdCnd", String.format("AND us.unionId = '%s' ", unionId));
|
||||
} else if (!isAdmin()) {
|
||||
sql.setVar("unionIdCnd", String.format("AND us.unionId = '%s' ", SecurityUtil.getUnionId()));
|
||||
}
|
||||
if (Strings.isNotBlank(condolenceTypeId)) {
|
||||
sql.setVar("typeCnd", String.format("AND con.condolenceTypeId = '%s' ", condolenceTypeId));
|
||||
@@ -150,4 +155,7 @@ public class UnionReimburseStatisticsController {
|
||||
}
|
||||
|
||||
|
||||
private boolean isAdmin() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -415,4 +415,9 @@ public class UnionReimburse extends BaseModel {
|
||||
@ColDefine(type = ColType.DATETIME)
|
||||
private Date reviewTime;
|
||||
|
||||
/**
|
||||
* 发票明细列表仅用于申请页表单回显和提交,不直接映射主表字段。
|
||||
*/
|
||||
private List<UnionReimburseInvoiceDetail> invoiceDetails;
|
||||
|
||||
}
|
||||
|
||||
+30
@@ -1,11 +1,41 @@
|
||||
package com.budwk.app.zhgh.dayofficework.unionReimburse.service;
|
||||
|
||||
import com.budwk.app.base.service.BaseService;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.param.UnionReimbursePageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.vo.UnionReimburseBankHistoryVO;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface UnionReimburseService extends BaseService<UnionReimburse> {
|
||||
|
||||
Sql getSql(UnionReimbursePageForm pageForm);
|
||||
|
||||
/**
|
||||
* 保存或提交报销申请,并同步保存发票明细。
|
||||
*/
|
||||
Result saveApply(UnionReimburse unionReimburse, int stateId);
|
||||
|
||||
/**
|
||||
* 查询申请表单详情,补齐发票明细回显数据。
|
||||
*/
|
||||
UnionReimburse getApplyForm(String id);
|
||||
|
||||
/**
|
||||
* 查询付款人的历史收款信息。
|
||||
*/
|
||||
List<UnionReimburseBankHistoryVO> getUserBankHistory(String payer);
|
||||
|
||||
/**
|
||||
* 校验发票号码是否与历史报销记录重复。
|
||||
*/
|
||||
Result checkInvoiceDuplicate(String invoiceNo, String reimburseId);
|
||||
|
||||
/**
|
||||
* 识别单张发票文件,并在需要时调用腾讯云验真接口补齐票面信息。
|
||||
*/
|
||||
Result recognizeInvoice(String fileId, Boolean verifySwitch);
|
||||
|
||||
}
|
||||
|
||||
+638
-14
@@ -1,24 +1,69 @@
|
||||
package com.budwk.app.zhgh.dayofficework.unionReimburse.service.impl;
|
||||
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.budwk.app.base.constant.RoleConstant;
|
||||
import com.budwk.app.base.result.Result;
|
||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||
import com.budwk.app.sys.models.Sys_file;
|
||||
import com.budwk.app.sys.services.SysFileService;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburse;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.model.UnionReimburseInvoiceDetail;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.param.UnionReimbursePageForm;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.service.UnionReimburseService;
|
||||
import com.budwk.app.zhgh.dayofficework.unionReimburse.vo.UnionReimburseBankHistoryVO;
|
||||
import com.budwk.app.web.commons.auth.utils.AuthUtil;
|
||||
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.nutz.dao.Cnd;
|
||||
import org.nutz.dao.Dao;
|
||||
import org.nutz.dao.Sqls;
|
||||
import org.nutz.dao.sql.Sql;
|
||||
import org.nutz.dao.util.cri.SqlExpressionGroup;
|
||||
import org.nutz.ioc.impl.PropertiesProxy;
|
||||
import org.nutz.ioc.loader.annotation.Inject;
|
||||
import org.nutz.ioc.loader.annotation.IocBean;
|
||||
import org.nutz.lang.Lang;
|
||||
import org.nutz.lang.util.NutMap;
|
||||
|
||||
import com.tencentcloudapi.common.Credential;
|
||||
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
||||
import com.tencentcloudapi.common.profile.ClientProfile;
|
||||
import com.tencentcloudapi.common.profile.HttpProfile;
|
||||
import com.tencentcloudapi.ocr.v20181119.OcrClient;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.TextVatInvoice;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoice;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceItem;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceOCRRequest;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceOCRResponse;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceVerifyRequest;
|
||||
import com.tencentcloudapi.ocr.v20181119.models.VatInvoiceVerifyResponse;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.Date;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> implements UnionReimburseService {
|
||||
public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> implements UnionReimburseService {
|
||||
@Inject
|
||||
private SysFileService sysFileService;
|
||||
@Inject
|
||||
private PropertiesProxy conf;
|
||||
public UnionReimburseServiceImpl(Dao dao) {
|
||||
super(dao);
|
||||
}
|
||||
@@ -35,30 +80,609 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse>
|
||||
$condition
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
// 年度查询条件
|
||||
cnd.andEX("year(info.createTime)", "=", pageForm.getYear());
|
||||
|
||||
// 工会、单位名称查询条件
|
||||
cnd.andEX("info.condolenceUnionId", "=", pageForm.getUnionId());
|
||||
cnd.andEX("info.unitId", "=", pageForm.getUnitId());
|
||||
|
||||
cnd.andEX("info.condolenceTypeId", "=", pageForm.getCondolenceTypeId());
|
||||
cnd.andEX("info.way", "=", pageForm.getWay());
|
||||
|
||||
// 报销项目查询条件
|
||||
cnd.andEX("info.reimburseProject", "=", pageForm.getReimburseProject());
|
||||
// 姓名和工号查询条件
|
||||
if (!isAdmin()) {
|
||||
cnd.andEX("info.condolenceUnionId", "=", SecurityUtil.getUnionId());
|
||||
}
|
||||
if (StrUtil.isNotBlank(pageForm.getSearchKeyword())) {
|
||||
SqlExpressionGroup seg = new SqlExpressionGroup();
|
||||
seg.orLike("info.condolenceUserName",pageForm.getSearchKeyword());
|
||||
seg.orLike("info.condolenceLoginName",pageForm.getSearchKeyword());
|
||||
seg.orLike("info.condolenceUserName", pageForm.getSearchKeyword());
|
||||
seg.orLike("info.condolenceLoginName", pageForm.getSearchKeyword());
|
||||
cnd.and(seg);
|
||||
}
|
||||
|
||||
cnd.and("info.stateId", "in", List.of(3, 2));
|
||||
|
||||
cnd.desc("info.createTime");
|
||||
applyStatisticsSort(cnd, pageForm);
|
||||
sql.setCondition(cnd);
|
||||
return sql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result saveApply(UnionReimburse unionReimburse, int stateId) {
|
||||
if (unionReimburse == null) {
|
||||
return Result.error("报销数据不能为空");
|
||||
}
|
||||
UnionReimburse oldRecord = null;
|
||||
if (StrUtil.isNotBlank(unionReimburse.getId())) {
|
||||
oldRecord = this.fetch(unionReimburse.getId());
|
||||
if (oldRecord == null) {
|
||||
return Result.error("未找到对应的报销记录");
|
||||
}
|
||||
}
|
||||
|
||||
normalizeInvoiceDetails(unionReimburse);
|
||||
if (needInvoiceDetails(unionReimburse)) {
|
||||
fillInvoiceSummary(unionReimburse);
|
||||
}
|
||||
if (stateId == 2) {
|
||||
Result validateResult = validateBeforeSubmit(unionReimburse);
|
||||
if (validateResult != null) {
|
||||
return validateResult;
|
||||
}
|
||||
Result duplicateResult = validateInvoiceDuplicate(unionReimburse);
|
||||
if (duplicateResult != null) {
|
||||
return duplicateResult;
|
||||
}
|
||||
}
|
||||
|
||||
if (oldRecord == null) {
|
||||
unionReimburse.setCreateTime(DateUtil.date());
|
||||
unionReimburse.setDocumentNo(generateDocumentNo());
|
||||
} else {
|
||||
unionReimburse.setCreateTime(oldRecord.getCreateTime());
|
||||
unionReimburse.setDocumentNo(oldRecord.getDocumentNo());
|
||||
}
|
||||
unionReimburse.setStateId(stateId);
|
||||
if ("UNION_REIMBURSE_PROJECT_1".equals(unionReimburse.getReimburseProject())) {
|
||||
unionReimburse.setRealMoney(unionReimburse.getCondolenceMoney());
|
||||
} else {
|
||||
unionReimburse.setRealMoney(unionReimburse.getMoney());
|
||||
}
|
||||
this.dao().insertOrUpdate(unionReimburse);
|
||||
saveInvoiceDetails(unionReimburse.getId(), unionReimburse.getInvoiceDetails());
|
||||
return Result.success(stateId == 2 ? "提交成功" : "保存成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnionReimburse getApplyForm(String id) {
|
||||
UnionReimburse unionReimburse = this.fetch(id);
|
||||
if (unionReimburse == null) {
|
||||
return null;
|
||||
}
|
||||
List<UnionReimburseInvoiceDetail> invoiceDetails = this.dao().query(
|
||||
UnionReimburseInvoiceDetail.class,
|
||||
Cnd.where("reimburseId", "=", id).asc("createdAt")
|
||||
);
|
||||
unionReimburse.setInvoiceDetails(invoiceDetails == null ? new ArrayList<>() : invoiceDetails);
|
||||
return unionReimburse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UnionReimburseBankHistoryVO> getUserBankHistory(String payer) {
|
||||
if (StrUtil.isBlank(payer)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
bankUserName,
|
||||
bankCardNumber,
|
||||
bankOfDeposit
|
||||
FROM
|
||||
union_reimburse
|
||||
$condition
|
||||
GROUP BY
|
||||
bankUserName,
|
||||
bankCardNumber,
|
||||
bankOfDeposit
|
||||
ORDER BY
|
||||
MAX(createTime) DESC
|
||||
""");
|
||||
Cnd cnd = Cnd.NEW();
|
||||
cnd.and("payer", "=", payer);
|
||||
cnd.and("bankUserName", "is not", null);
|
||||
cnd.and("bankCardNumber", "is not", null);
|
||||
cnd.and("bankOfDeposit", "is not", null);
|
||||
sql.setCondition(cnd);
|
||||
return this.listVO(sql, UnionReimburseBankHistoryVO.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result checkInvoiceDuplicate(String invoiceNo, String reimburseId) {
|
||||
String currentInvoiceNo = StrUtil.blankToDefault(StrUtil.trim(invoiceNo), "");
|
||||
if (StrUtil.isBlank(currentInvoiceNo)) {
|
||||
return Result.error("发票号码不能为空");
|
||||
}
|
||||
return queryHistoryInvoiceDuplicate(currentInvoiceNo, reimburseId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result recognizeInvoice(String fileId, Boolean verifySwitch) {
|
||||
if (StrUtil.isBlank(fileId)) {
|
||||
return Result.error("请先上传发票文件");
|
||||
}
|
||||
Sys_file sysFile = sysFileService.fetch(fileId);
|
||||
if (sysFile == null) {
|
||||
return Result.error("发票文件不存在");
|
||||
}
|
||||
Credential credential = getInvoiceCredential();
|
||||
if (credential == null) {
|
||||
return Result.error("未配置腾讯云发票识别密钥,请先在 application-dev.yaml 中配置 invoice.tencent.secret-id 和 invoice.tencent.secret-key");
|
||||
}
|
||||
try {
|
||||
byte[] fileBytes = sysFileService.download(fileId);
|
||||
VatInvoiceOCRResponse response = executeOcr(credential, sysFile, fileBytes);
|
||||
NutMap result = buildOcrResult(response);
|
||||
String msg = "发票识别成功";
|
||||
if (Boolean.TRUE.equals(verifySwitch)) {
|
||||
String verifyMsg = enrichByVerify(credential, result);
|
||||
msg = StrUtil.isBlank(verifyMsg) ? "发票识别并校验成功" : verifyMsg;
|
||||
}
|
||||
return Result.success(msg, result);
|
||||
} catch (TencentCloudSDKException e) {
|
||||
log.error("腾讯云发票识别失败,fileId:{}", fileId, e);
|
||||
return Result.error("腾讯云发票识别失败:" + e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.error("发票识别失败,fileId:{}", fileId, e);
|
||||
return Result.error("发票识别失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一规整发票明细中的文本和金额,避免空格、空数组等脏数据进入库表。
|
||||
*/
|
||||
private void normalizeInvoiceDetails(UnionReimburse unionReimburse) {
|
||||
if (unionReimburse.getInvoiceDetails() == null) {
|
||||
unionReimburse.setInvoiceDetails(new ArrayList<>());
|
||||
return;
|
||||
}
|
||||
List<UnionReimburseInvoiceDetail> invoiceDetails = unionReimburse.getInvoiceDetails().stream()
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
invoiceDetails.forEach(detail -> {
|
||||
detail.setInvoiceNo(StrUtil.trim(detail.getInvoiceNo()));
|
||||
detail.setSellerName(StrUtil.trim(detail.getSellerName()));
|
||||
detail.setItemName(StrUtil.trim(detail.getItemName()));
|
||||
detail.setRemark(StrUtil.trim(detail.getRemark()));
|
||||
if (detail.getInvoiceFiles() == null) {
|
||||
detail.setInvoiceFiles(new ArrayList<>());
|
||||
}
|
||||
if (detail.getInvoiceAmount() != null) {
|
||||
detail.setInvoiceAmount(BigDecimal.valueOf(detail.getInvoiceAmount())
|
||||
.setScale(2, RoundingMode.HALF_UP)
|
||||
.doubleValue());
|
||||
}
|
||||
});
|
||||
unionReimburse.setInvoiceDetails(invoiceDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* 活动类报销由发票明细自动汇总金额和发票张数,减少手工输入出错。
|
||||
*/
|
||||
private void fillInvoiceSummary(UnionReimburse unionReimburse) {
|
||||
double totalMoney = 0D;
|
||||
int invoiceFileCount = 0;
|
||||
for (UnionReimburseInvoiceDetail detail : unionReimburse.getInvoiceDetails()) {
|
||||
if (detail.getInvoiceAmount() != null) {
|
||||
totalMoney = BigDecimal.valueOf(totalMoney)
|
||||
.add(BigDecimal.valueOf(detail.getInvoiceAmount()))
|
||||
.doubleValue();
|
||||
}
|
||||
if (Lang.isNotEmpty(detail.getInvoiceFiles())) {
|
||||
invoiceFileCount++;
|
||||
}
|
||||
}
|
||||
unionReimburse.setMoney(BigDecimal.valueOf(totalMoney).setScale(2, RoundingMode.HALF_UP).doubleValue());
|
||||
unionReimburse.setInvoiceNumber(String.valueOf(invoiceFileCount));
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交前补一层后端校验,防止前端绕过校验直接提交。
|
||||
*/
|
||||
private Result validateBeforeSubmit(UnionReimburse unionReimburse) {
|
||||
if (StrUtil.isBlank(unionReimburse.getMobile())) {
|
||||
return Result.error("请填写联系方式");
|
||||
}
|
||||
if (!isValidContact(unionReimburse.getMobile())) {
|
||||
return Result.error("请输入正确的联系方式");
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getBankUserName())) {
|
||||
return Result.error("请填写户名");
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getBankCardNumber())) {
|
||||
return Result.error("请填写银行账号");
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getBankOfDeposit())) {
|
||||
return Result.error("请填写开户行");
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getPaymentNotes())) {
|
||||
return Result.error("请填写支付内容");
|
||||
}
|
||||
if (!needInvoiceDetails(unionReimburse)) {
|
||||
return null;
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getActivityName())) {
|
||||
return Result.error("请填写活动名称");
|
||||
}
|
||||
if (StrUtil.isBlank(unionReimburse.getActivityPlace())) {
|
||||
return Result.error("请填写活动地点");
|
||||
}
|
||||
if (unionReimburse.getActivityTime() == null) {
|
||||
return Result.error("请选择活动时间");
|
||||
}
|
||||
if (Lang.isEmpty(unionReimburse.getFiles())) {
|
||||
return Result.error("请上传附件");
|
||||
}
|
||||
if (Lang.isEmpty(unionReimburse.getInvoiceDetails())) {
|
||||
return Result.error("请至少维护一条发票明细");
|
||||
}
|
||||
for (int i = 0; i < unionReimburse.getInvoiceDetails().size(); i++) {
|
||||
UnionReimburseInvoiceDetail detail = unionReimburse.getInvoiceDetails().get(i);
|
||||
int rowIndex = i + 1;
|
||||
if (Lang.isEmpty(detail.getInvoiceFiles())) {
|
||||
return Result.error("第" + rowIndex + "条发票明细请上传发票文件");
|
||||
}
|
||||
if (StrUtil.isBlank(detail.getInvoiceNo())) {
|
||||
return Result.error("第" + rowIndex + "条发票明细请填写发票号码");
|
||||
}
|
||||
if (detail.getInvoiceAmount() == null || detail.getInvoiceAmount() <= 0) {
|
||||
return Result.error("第" + rowIndex + "条发票明细请填写正确的发票金额");
|
||||
}
|
||||
if (StrUtil.isBlank(detail.getSellerName())) {
|
||||
return Result.error("第" + rowIndex + "条发票明细请填写销售方信息名称");
|
||||
}
|
||||
if (StrUtil.isBlank(detail.getItemName())) {
|
||||
return Result.error("第" + rowIndex + "条发票明细请填写项目名称");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同次提交和历史记录都要拦截重复发票,避免重复报销。
|
||||
*/
|
||||
private Result validateInvoiceDuplicate(UnionReimburse unionReimburse) {
|
||||
Map<String, List<Integer>> currentInvoiceMap = new LinkedHashMap<>();
|
||||
List<UnionReimburseInvoiceDetail> details = unionReimburse.getInvoiceDetails();
|
||||
for (int i = 0; i < details.size(); i++) {
|
||||
String invoiceNo = StrUtil.trim(details.get(i).getInvoiceNo());
|
||||
if (StrUtil.isBlank(invoiceNo)) {
|
||||
continue;
|
||||
}
|
||||
currentInvoiceMap.computeIfAbsent(invoiceNo, key -> new ArrayList<>()).add(i + 1);
|
||||
}
|
||||
for (Map.Entry<String, List<Integer>> entry : currentInvoiceMap.entrySet()) {
|
||||
if (entry.getValue().size() > 1) {
|
||||
String rowText = entry.getValue().stream().map(String::valueOf).collect(Collectors.joining("、"));
|
||||
return Result.error("发票号码【" + entry.getKey() + "】与本次提交的第" + rowText + "条发票重复,不能提交");
|
||||
}
|
||||
}
|
||||
for (String invoiceNo : currentInvoiceMap.keySet()) {
|
||||
Result duplicateResult = queryHistoryInvoiceDuplicate(invoiceNo, unionReimburse.getId());
|
||||
if (duplicateResult != null) {
|
||||
return duplicateResult;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 历史重复校验会排除当前单据自身,避免编辑回显时误判。
|
||||
*/
|
||||
private Result queryHistoryInvoiceDuplicate(String invoiceNo, String reimburseId) {
|
||||
Sql sql = Sqls.create("""
|
||||
SELECT
|
||||
d.invoiceNo,
|
||||
r.activityName
|
||||
FROM
|
||||
union_reimburse_invoice_detail d
|
||||
LEFT JOIN union_reimburse r ON r.id = d.reimburseId
|
||||
WHERE
|
||||
d.invoiceNo = @invoiceNo
|
||||
AND (@reimburseId = '' OR d.reimburseId <> @reimburseId)
|
||||
LIMIT 1
|
||||
""");
|
||||
sql.params().set("invoiceNo", invoiceNo);
|
||||
sql.params().set("reimburseId", StrUtil.blankToDefault(StrUtil.trim(reimburseId), ""));
|
||||
List<NutMap> repeatList = this.listMap(sql);
|
||||
if (Lang.isEmpty(repeatList)) {
|
||||
return null;
|
||||
}
|
||||
String activityName = repeatList.get(0).getString("activityName");
|
||||
if (StrUtil.isBlank(activityName)) {
|
||||
activityName = "历史报销记录";
|
||||
}
|
||||
return Result.error("发票号码【" + invoiceNo + "】与以往活动名称【" + activityName + "】中提交的发票重复,不能提交");
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次按当前表单全量覆盖明细,避免旧明细残留。
|
||||
*/
|
||||
/**
|
||||
* 发票识别优先读取当前项目配置的 SecretId/SecretKey,没有时再回退读取用户提供的 csv 文件。
|
||||
*/
|
||||
private Credential getInvoiceCredential() {
|
||||
String secretId = StrUtil.trim(conf.get("invoice.tencent.secret-id"));
|
||||
String secretKey = StrUtil.trim(conf.get("invoice.tencent.secret-key"));
|
||||
if (StrUtil.isNotBlank(secretId) && StrUtil.isNotBlank(secretKey)) {
|
||||
return new Credential(secretId, secretKey);
|
||||
}
|
||||
return loadCredentialFromSecretFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容腾讯云控制台下载的密钥 csv,便于本地开发时不把明文密钥直接写进配置文件。
|
||||
*/
|
||||
private Credential loadCredentialFromSecretFile() {
|
||||
String secretFile = StrUtil.trim(conf.get("invoice.tencent.secret-file"));
|
||||
if (StrUtil.isBlank(secretFile)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Path path = Paths.get(secretFile);
|
||||
if (!Files.exists(path)) {
|
||||
return null;
|
||||
}
|
||||
List<String> lines = Files.readAllLines(path);
|
||||
if (lines.size() < 2) {
|
||||
return null;
|
||||
}
|
||||
String[] values = lines.get(1).split(",", -1);
|
||||
if (values.length < 2) {
|
||||
return null;
|
||||
}
|
||||
String secretId = StrUtil.trim(values[0]);
|
||||
String secretKey = StrUtil.trim(values[1]);
|
||||
if (StrUtil.isBlank(secretId) || StrUtil.isBlank(secretKey)) {
|
||||
return null;
|
||||
}
|
||||
return new Credential(secretId, secretKey);
|
||||
} catch (Exception e) {
|
||||
log.warn("读取腾讯云发票识别密钥文件失败,file:{}", secretFile, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一创建腾讯云 OCR 客户端,避免控制器直接依赖第三方 SDK。
|
||||
*/
|
||||
private OcrClient createOcrClient(Credential credential) {
|
||||
HttpProfile httpProfile = new HttpProfile();
|
||||
httpProfile.setEndpoint("ocr.tencentcloudapi.com");
|
||||
ClientProfile clientProfile = new ClientProfile();
|
||||
clientProfile.setHttpProfile(httpProfile);
|
||||
return new OcrClient(credential, "", clientProfile);
|
||||
}
|
||||
|
||||
private VatInvoiceOCRResponse executeOcr(Credential credential, Sys_file sysFile, byte[] fileBytes) throws TencentCloudSDKException {
|
||||
OcrClient client = createOcrClient(credential);
|
||||
VatInvoiceOCRRequest request = new VatInvoiceOCRRequest();
|
||||
request.setImageBase64(Base64.getEncoder().encodeToString(fileBytes));
|
||||
String fileName = StrUtil.blankToDefault(sysFile.getName(), "").toLowerCase();
|
||||
if (fileName.endsWith(".pdf")) {
|
||||
request.setIsPdf(true);
|
||||
request.setPdfPageNumber(1L);
|
||||
}
|
||||
return client.VatInvoiceOCR(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将腾讯云 OCR 返回的票面字段规整成页面可直接回填的键值结构。
|
||||
*/
|
||||
private NutMap buildOcrResult(VatInvoiceOCRResponse response) {
|
||||
NutMap result = NutMap.NEW();
|
||||
TextVatInvoice[] infos = response.getVatInvoiceInfos();
|
||||
VatInvoiceItem[] items = response.getItems();
|
||||
result.setv("invoiceNo", pickValue(infos, "发票号码", "号码", "No"));
|
||||
result.setv("invoiceCode", pickValue(infos, "发票代码", "代码", "Code"));
|
||||
result.setv("invoiceDate", normalizeDate(pickValue(infos, "开票日期", "日期", "Date")));
|
||||
result.setv("invoiceCheckCode", pickValue(infos, "校验码", "校验码后6位", "CheckCode"));
|
||||
result.setv("invoiceAmount", parseMoney(pickValue(infos, "小写金额", "价税合计(小写)", "价税合计", "合计金额", "AmountWithTax")));
|
||||
result.setv("sellerName", pickValue(infos, "销售方名称", "销售方信息名称", "销售方", "SellerName"));
|
||||
result.setv("itemName", joinItemNames(items));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动校验需要票面关键信息,缺字段时只提示人工核对,不阻塞用户继续录入。
|
||||
*/
|
||||
private String enrichByVerify(Credential credential, NutMap result) {
|
||||
String invoiceCode = result.getString("invoiceCode");
|
||||
String invoiceNo = result.getString("invoiceNo");
|
||||
String invoiceDate = result.getString("invoiceDate");
|
||||
String checkCode = lastDigits(result.getString("invoiceCheckCode"), 6);
|
||||
if (StrUtil.isBlank(checkCode)) {
|
||||
checkCode = moneyToVerifyValue(result.get("invoiceAmount"));
|
||||
}
|
||||
if (StrUtil.hasBlank(invoiceCode, invoiceNo, invoiceDate, checkCode)) {
|
||||
return "发票识别成功,但自动校验信息不完整,请人工核对后提交";
|
||||
}
|
||||
try {
|
||||
OcrClient client = createOcrClient(credential);
|
||||
VatInvoiceVerifyRequest request = new VatInvoiceVerifyRequest();
|
||||
request.setInvoiceCode(invoiceCode);
|
||||
request.setInvoiceNo(invoiceNo);
|
||||
request.setInvoiceDate(invoiceDate.replace("-", ""));
|
||||
request.setAdditional(checkCode);
|
||||
VatInvoiceVerifyResponse response = client.VatInvoiceVerify(request);
|
||||
VatInvoice invoice = response.getInvoice();
|
||||
if (invoice == null) {
|
||||
return "发票识别成功,但自动校验未返回有效结果,请人工核对后提交";
|
||||
}
|
||||
result.setv("invoiceCode", invoice.getCode());
|
||||
result.setv("invoiceNo", invoice.getNumber());
|
||||
result.setv("invoiceDate", normalizeDate(invoice.getDate()));
|
||||
result.setv("invoiceCheckCode", invoice.getCheckCode());
|
||||
result.setv("sellerName", invoice.getSellerName());
|
||||
result.setv("invoiceAmount", parseMoney(invoice.getAmountWithTax()));
|
||||
result.setv("itemName", joinItemNames(invoice.getItems()));
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.warn("腾讯云发票验真失败,invoiceNo:{}", invoiceNo, e);
|
||||
return "发票识别成功,但自动校验失败,请人工核对后提交";
|
||||
}
|
||||
}
|
||||
|
||||
private String pickValue(TextVatInvoice[] infos, String... aliases) {
|
||||
if (infos == null || aliases == null) {
|
||||
return "";
|
||||
}
|
||||
Set<String> aliasSet = new LinkedHashSet<>();
|
||||
for (String alias : aliases) {
|
||||
aliasSet.add(normalizeFieldName(alias));
|
||||
}
|
||||
for (TextVatInvoice info : infos) {
|
||||
if (info == null) {
|
||||
continue;
|
||||
}
|
||||
if (aliasSet.contains(normalizeFieldName(info.getName()))) {
|
||||
return StrUtil.blankToDefault(StrUtil.trim(info.getValue()), "");
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private String normalizeFieldName(String name) {
|
||||
return StrUtil.blankToDefault(name, "")
|
||||
.replace(":", "")
|
||||
.replace(":", "")
|
||||
.replace(" ", "")
|
||||
.replace("\u00A0", "")
|
||||
.trim();
|
||||
}
|
||||
|
||||
private String normalizeDate(String dateText) {
|
||||
String date = StrUtil.blankToDefault(StrUtil.trim(dateText), "");
|
||||
if (StrUtil.isBlank(date)) {
|
||||
return "";
|
||||
}
|
||||
String digits = date.replaceAll("[^0-9]", "");
|
||||
if (digits.length() == 8) {
|
||||
return digits.substring(0, 4) + "-" + digits.substring(4, 6) + "-" + digits.substring(6);
|
||||
}
|
||||
return date.replace("年", "-").replace("月", "-").replace("日", "");
|
||||
}
|
||||
|
||||
private Double parseMoney(Object moneyObj) {
|
||||
String moneyText = StrUtil.blankToDefault(StrUtil.trim(ObjectUtil.defaultIfNull(moneyObj, "").toString()), "");
|
||||
if (StrUtil.isBlank(moneyText)) {
|
||||
return null;
|
||||
}
|
||||
moneyText = moneyText.replace(",", "").replace("¥", "").replace("¥", "");
|
||||
try {
|
||||
return BigDecimal.valueOf(Double.parseDouble(moneyText)).setScale(2, RoundingMode.HALF_UP).doubleValue();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String joinItemNames(VatInvoiceItem[] items) {
|
||||
if (items == null || items.length == 0) {
|
||||
return "";
|
||||
}
|
||||
return Arrays.stream(items)
|
||||
.map(VatInvoiceItem::getName)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.collect(Collectors.joining(";"));
|
||||
}
|
||||
|
||||
private String lastDigits(String text, int length) {
|
||||
String digits = StrUtil.blankToDefault(text, "").replaceAll("[^0-9]", "");
|
||||
if (digits.length() <= length) {
|
||||
return digits;
|
||||
}
|
||||
return digits.substring(digits.length() - length);
|
||||
}
|
||||
|
||||
private String moneyToVerifyValue(Object moneyObj) {
|
||||
Double money = parseMoney(moneyObj);
|
||||
if (money == null) {
|
||||
return "";
|
||||
}
|
||||
return BigDecimal.valueOf(money).setScale(2, RoundingMode.HALF_UP).toPlainString();
|
||||
}
|
||||
|
||||
private void saveInvoiceDetails(String reimburseId, List<UnionReimburseInvoiceDetail> invoiceDetails) {
|
||||
this.dao().clear(UnionReimburseInvoiceDetail.class, Cnd.where("reimburseId", "=", reimburseId));
|
||||
if (Lang.isEmpty(invoiceDetails)) {
|
||||
return;
|
||||
}
|
||||
invoiceDetails.forEach(detail -> {
|
||||
detail.setId(null);
|
||||
detail.setReimburseId(reimburseId);
|
||||
this.dao().insert(detail);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前仅活动类报销维护发票明细,慰问类仍按原有逻辑处理金额。
|
||||
*/
|
||||
private boolean needInvoiceDetails(UnionReimburse unionReimburse) {
|
||||
return unionReimburse != null && !"UNION_REIMBURSE_PROJECT_1".equals(unionReimburse.getReimburseProject());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成年度流水号,保持与现有单据编号规则一致。
|
||||
*/
|
||||
private String generateDocumentNo() {
|
||||
int currentYear = DateUtil.thisYear();
|
||||
String yearPrefix = String.valueOf(currentYear);
|
||||
Cnd cnd = Cnd.where("documentNo", "like", yearPrefix + "%");
|
||||
cnd.desc("documentNo");
|
||||
cnd.limit(1);
|
||||
List<UnionReimburse> list = this.query(cnd);
|
||||
int nextSeq = 1;
|
||||
if (Lang.isNotEmpty(list) && StrUtil.isNotBlank(list.get(0).getDocumentNo())) {
|
||||
String maxNo = list.get(0).getDocumentNo();
|
||||
if (maxNo.startsWith(yearPrefix)) {
|
||||
String seqPart = maxNo.substring(yearPrefix.length());
|
||||
if (StrUtil.isNumeric(seqPart)) {
|
||||
nextSeq = Integer.parseInt(seqPart) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return yearPrefix + String.format("%02d", nextSeq);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计页排序字段仅允许白名单列,避免传入非法字段。
|
||||
*/
|
||||
private void applyStatisticsSort(Cnd cnd, UnionReimbursePageForm pageForm) {
|
||||
String orderField = normalizeStatisticsSortField(pageForm.getPageOrderName());
|
||||
if (StrUtil.isBlank(orderField) || StrUtil.isBlank(pageForm.getPageOrderBy())) {
|
||||
cnd.desc("info.createTime");
|
||||
return;
|
||||
}
|
||||
cnd.orderBy(orderField, "ascending".equals(pageForm.getPageOrderBy()) ? "asc" : "desc");
|
||||
}
|
||||
|
||||
private String normalizeStatisticsSortField(String pageOrderName) {
|
||||
if (StrUtil.isBlank(pageOrderName)) {
|
||||
return null;
|
||||
}
|
||||
return switch (pageOrderName) {
|
||||
case "condolenceLoginName" -> "info.condolenceLoginName";
|
||||
case "condolenceUnionName" -> "info.condolenceUnionName";
|
||||
case "unitName" -> "info.unitName";
|
||||
case "newCreateTime", "createTime" -> "info.createTime";
|
||||
case "newCondolenceTime" -> "info.condolenceTime";
|
||||
case "reimburseProject" -> "info.reimburseProject";
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isAdmin() {
|
||||
return AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name());
|
||||
}
|
||||
|
||||
/**
|
||||
* 联系方式支持手机号和座机,和前端规则保持一致。
|
||||
*/
|
||||
private boolean isValidContact(String mobile) {
|
||||
return mobile.matches("^(1[3-9]\\d{9}|0\\d{2,3}-?\\d{7,8})$");
|
||||
}
|
||||
}
|
||||
|
||||
+10
-2
@@ -150,7 +150,7 @@ public class TeacherCongressDelegatePushController {
|
||||
@Aop(TransAop.READ_COMMITTED)
|
||||
@SaCheckPermission("tc.delegate.push")
|
||||
// @SLog(tag = "民主管理-教代会代表推选", msg = "获取本分工会下的非代表用户")
|
||||
public Result getUnionUser(String sessionId, String unionId) {
|
||||
public Result getUnionUser(String sessionId, String unionId, String keyword) {
|
||||
// 查询预选中的代表
|
||||
Cnd cndx = Cnd.where("sessionId", "=", sessionId);
|
||||
cndx.andEX("unionId", "=", SecurityUtil.getUnionId());
|
||||
@@ -173,7 +173,7 @@ public class TeacherCongressDelegatePushController {
|
||||
`vw_user` u
|
||||
LEFT JOIN teacher_congress_delegate tcd ON tcd.userId = u.id
|
||||
AND tcd.sessionId = @sessionId
|
||||
LEFT JOIN teacher_congress_delegate_push tcdp ON tcdp.userId = tcdp.id
|
||||
LEFT JOIN teacher_congress_delegate_push tcdp ON tcdp.userId = u.id
|
||||
AND tcdp.sessionId = @sessionId
|
||||
$condition
|
||||
""");
|
||||
@@ -185,6 +185,14 @@ public class TeacherCongressDelegatePushController {
|
||||
cnd.and("tcd.userId", "is", null);
|
||||
cnd.and("tcdp.id", "is", null);
|
||||
cnd.and("u.unionId", "=", SecurityUtil.getUnionId());
|
||||
if (StrUtil.isNotBlank(keyword)) {
|
||||
SqlExpressionGroup group = new SqlExpressionGroup();
|
||||
group.orLike("u.username", keyword);
|
||||
group.orLike("u.loginname", keyword);
|
||||
cnd.and(group);
|
||||
}
|
||||
// 搜索候选人时只返回少量命中数据,避免前端大列表筛选导致严重卡顿
|
||||
cnd.limit(1, 100);
|
||||
sql.setCondition(cnd);
|
||||
List<NutMap> userList = baseService.listMap(sql);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user