This commit is contained in:
2026-04-25 18:20:04 +08:00
parent 9edd627390
commit 568dc5e169
115 changed files with 1781 additions and 1093 deletions
@@ -27,7 +27,6 @@ import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @ClassName ActivitySportsInfoManageController
@@ -152,37 +151,12 @@ public class ActivitySportsInfoManageController {
@SLog(tag = "体育活动", msg = "修改活动")
@SaCheckPermission("activity.sports.info")
public Result doEdit(@Param(value = "data") ActivitySchool activitySchool,
@Param(value = "events") ActivitySchoolEvent[] events,
@Param(value = "forceReduceTeam") boolean forceReduceTeam) {
// 编辑活动减少队伍时,先把即将删除且已有报名人员的队伍返回给前端二次确认;确认后由 service 继续保存。
List<NutMap> teamApplyList = activitySportsService.checkTeamReduceApply(activitySchool.getId(), events);
if (!forceReduceTeam && teamApplyList.size() > 0) {
return Result.NEW().addCode(2).addMsg(buildTeamReduceMsg(teamApplyList)).addData(teamApplyList);
}
activitySportsService.doEdit(activitySchool, events, forceReduceTeam);
@Param(value = "events") ActivitySchoolEvent[] events) {
activitySportsService.doEdit(activitySchool, events);
return Result.success();
}
private String buildTeamReduceMsg(List<NutMap> teamApplyList) {
// 返回给前端确认框的报名占用说明:包含项目名称、队伍名称、报名人数,便于用户判断是否强制删除。
StringBuilder msg = new StringBuilder();
for (NutMap teamApply : teamApplyList) {
if (msg.length() > 0) {
msg.append("");
}
msg.append("项目【")
.append(teamApply.getString("eventName"))
.append("】的【")
.append(teamApply.getString("teamName"))
.append("】已有")
.append(teamApply.getInt("applyNum"))
.append("名报名人员");
}
msg.append(",确认删除这些队伍并保存吗?");
return msg.toString();
}
@At
@SLog(tag = "体育活动", msg = "添加活动")
@@ -5,21 +5,28 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.param.PageForm;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.base.utils.DateUtil;
import com.budwk.app.base.utils.PwdUtil;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.models.ActivityBasicUnion;
import com.budwk.app.zhgh.activity.basic.models.ActivityBasicUnit;
import com.budwk.app.zhgh.activity.sports.models.ActivityResults;
import com.budwk.app.zhgh.activity.sports.models.ActivitySchoolApply;
import com.budwk.app.zhgh.activity.sports.models.ActivitySchoolEvent;
import com.budwk.app.zhgh.activity.sports.service.ActivitySportsApplyUserService;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.random.R;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.trans.Trans;
import java.util.Arrays;
/**
* @author zhf
@@ -46,12 +53,11 @@ public class ActivitySportsResultsController {
@At
@SaCheckPermission("activity.results.input")
public Result pageData(PageForm page,
public Result pageData(String groupName,
PageForm page,
String activityId,
String eventId,
Integer isMenWomen,
String projectType,
String competitionCategory) {
String[] isMenWomen) {
Cnd cnd = Cnd.NEW();
Sql sql = Sqls.create("""
SELECT
@@ -71,10 +77,24 @@ public class ActivitySportsResultsController {
$condition
""");
cnd.and("ase.activityId", "=", activityId);
cnd.andEX("abs.`name`", "=", groupName);
cnd.andEX("ae.`id`", "=", eventId);
cnd.andEX("ae.isMenWomen", "=", isMenWomen);
cnd.andEX("ae.projectType", "=", projectType);
cnd.andEX("ae.competitionCategory", "=", competitionCategory);
SqlExpressionGroup sqlExpressionGroup = new SqlExpressionGroup();
if (Arrays.stream(isMenWomen).anyMatch(a -> a.equals("2"))) {
sqlExpressionGroup.and("ae.isMenWomen", "=", 1);
}
if (Arrays.stream(isMenWomen).anyMatch(a -> a.equals("3"))) {
sqlExpressionGroup.or("ae.isMenWomen", "=", 2);
}
if (Arrays.stream(isMenWomen).anyMatch(a -> a.equals("4"))) {
sqlExpressionGroup.and("ae.projectType", "=", 1);
}
if (Arrays.stream(isMenWomen).anyMatch(a -> a.equals("5"))) {
sqlExpressionGroup.or("ae.projectType", "=", 2);
}
if (sqlExpressionGroup.getExps().size() > 0) {
cnd.and(sqlExpressionGroup);
}
cnd.desc("allName");
sql.setCondition(cnd);
return Result.success(baseService.listPageMap(page.getPageNumber(), page.getPageSize(), sql));
@@ -94,7 +114,53 @@ public class ActivitySportsResultsController {
@At
@SaCheckPermission("activity.results.input")
public Result doAddUser(ActivitySchoolApply activitySchoolApply) {
activitySchoolApplyViService.doAddTemporaryApplyUser(activitySchoolApply);
Sys_user sysUser = baseService.dao().fetch(Sys_user.class, Cnd.where("loginname", "=", activitySchoolApply.getLoginname()));
if (sysUser != null && sysUser.getLoginname().equals(activitySchoolApply.getLoginname()) && !sysUser.getUsername().equals(activitySchoolApply.getUsername())) {
return Result.error("工号已存在,请检查姓名和工号是否一致!");
}
if (sysUser == null) {
Trans.exec(() -> {
String pwd = "@dd3s#3618!";
String salt = R.UU32();
Sys_user user = new Sys_user();
user.setId(R.UU32());
user.setSalt(R.UU32());
user.setPassword(PwdUtil.getPassword(pwd, salt));
user.setUsername(activitySchoolApply.getUsername());
user.setLoginname(activitySchoolApply.getLoginname());
user.setSex(activitySchoolApply.getSex());
user.setUnitId(activitySchoolApply.getUnitId());
user.setMobile(activitySchoolApply.getMobile());
baseService.insert(user);
ActivityBasicUnit activityBasicUnit = activitySchoolApplyViService.dao().fetch(ActivityBasicUnit.class, Cnd.where("id", "=", user.getUnitId()));
ActivityBasicUnion basicUnion = activitySchoolApplyViService.dao().fetch(ActivityBasicUnion.class, Cnd.where("id", "=", activityBasicUnit.getUnionId()));
activitySchoolApply.setUserId(user.getId());
activitySchoolApply.setApplyDate(DateUtil.getDate());
activitySchoolApply.setSex(user.getSex());
activitySchoolApply.setUnitId(user.getUnitId());
activitySchoolApply.setActivityUnionId(basicUnion.getId());
activitySchoolApply.setActivityUnionName(basicUnion.getName());
activitySchoolApplyViService.insert(activitySchoolApply);
});
return null;
}
sysUser.setSex(activitySchoolApply.getSex());
baseService.update(sysUser);
ActivityBasicUnit activityBasicUnit = activitySchoolApplyViService.dao().fetch(ActivityBasicUnit.class, Cnd.where("id", "=", sysUser.getUnitId()));
ActivityBasicUnion basicUnion = activitySchoolApplyViService.dao().fetch(ActivityBasicUnion.class, Cnd.where("id", "=", activityBasicUnit.getUnionId()));
activitySchoolApply.setUserId(sysUser.getId());
activitySchoolApply.setApplyUser(SecurityUtil.getUserId());
activitySchoolApply.setApplyDate(DateUtil.getDate());
activitySchoolApply.setUnitId(sysUser.getUnitId());
activitySchoolApply.setActivityUnionId(basicUnion.getId());
activitySchoolApply.setActivityUnionName(basicUnion.getName());
activitySchoolApplyViService.insert(activitySchoolApply);
return Result.success();
}
@@ -135,10 +201,8 @@ public class ActivitySportsResultsController {
@At
@SaCheckPermission("activity.results.input")
public Result getUnionDetails(String activityId, String eventId, String unionId) {
// 团体成绩录入的人数按活动项目配置的“每队(项)运动员人数”展示,不再按该分工会实际报名人数统计。
ActivitySchoolEvent schoolEvent = activitySchoolApplyViService.dao().fetch(ActivitySchoolEvent.class,
Cnd.where("activityId", "=", activityId).and("eventId", "=", eventId));
return Result.success(schoolEvent == null || schoolEvent.getAthletesMaxNum() == null ? 0 : schoolEvent.getAthletesMaxNum());
int count = activitySchoolApplyViService.count(Cnd.where("activityId", "=", activityId).and("eventId", "=", eventId).and("unionId", "=", unionId));
return Result.success(count);
}
@@ -188,11 +188,6 @@ public class ActivitySchool extends BaseModel implements Serializable , SysHomeC
@ColDefine(type = ColType.VARCHAR, width = 32)
private String belongClubId;
@Column
@Comment("报多队工会")
@ColDefine(type = ColType.MYSQL_JSON)
private List<String> moreTeamUnionIds;
@Column
@Comment("创建时间")
@ColDefine(type = ColType.VARCHAR, width = 30)
@@ -23,8 +23,6 @@ public interface ActivitySportsApplyUserService extends BaseService<ActivityScho
Object getUniteApplyInfo(ActivitySportsApplyUserPageParam applyUserPageParam, Integer isMenWomen);
void doAddTemporaryApplyUser(ActivitySchoolApply activitySchoolApply);
void doApplyUser(ActivitySchoolApply[] userList, String eventId, String activityId, Boolean pass, String unionId);
Pagination applyPageData(PageForm page, String activityId, String eventId, String unionId);
@@ -4,10 +4,8 @@ package com.budwk.app.zhgh.activity.sports.service;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.activity.sports.models.ActivitySchool;
import com.budwk.app.zhgh.activity.sports.models.ActivitySchoolEvent;
import org.nutz.lang.util.NutMap;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* @author Aaron
@@ -16,9 +14,7 @@ public interface ActivitySportsService extends BaseService<ActivitySchool> {
String doAdd(ActivitySchool activitySchool, ActivitySchoolEvent[] events);
void doEdit(ActivitySchool activitySchool, ActivitySchoolEvent[] events, boolean forceReduceTeam);
List<NutMap> checkTeamReduceApply(String activityId, ActivitySchoolEvent[] events);
void doEdit(ActivitySchool activitySchool, ActivitySchoolEvent[] events);
void doDelete(String id);
@@ -6,7 +6,6 @@ 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.service.impl.BaseServiceImpl;
import com.budwk.app.base.utils.PwdUtil;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.web.commons.auth.utils.AuthUtil;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
@@ -31,7 +30,6 @@ import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.random.R;
import org.nutz.lang.util.NutMap;
import java.util.ArrayList;
@@ -367,10 +365,9 @@ public class ActivitySportsApplyUserServiceImpl extends BaseServiceImpl<Activity
result.put("awardsModeT", awardsModeT);
result.put("awardsModeG", awardsModeG);
boolean allowMoreTeam = allowMoreTeam(activity);
result.put("allowMoreTeam", allowMoreTeam);
// 团体项目队伍范围按活动“报多队工会”控制:命中的工会返回全部队伍,否则只返回第一队。
result.put("team", getApplyTeamList(applyUserPageParam.getActivityId(), applyUserPageParam.getEventId(), allowMoreTeam));
result.put("team", dao().query(ActivitySchoolTeam.class,
Cnd.where("eventId", "=", applyUserPageParam.getEventId())
.and("activityId", "=", applyUserPageParam.getActivityId()).asc("location")));
result.put("activity", activity);
List<NutMap> events = getEvents(applyUserPageParam.getActivityId());
@@ -380,80 +377,12 @@ public class ActivitySportsApplyUserServiceImpl extends BaseServiceImpl<Activity
return result;
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void doAddTemporaryApplyUser(ActivitySchoolApply activitySchoolApply) {
// 成绩录入临时补报名:单项只补人员和工会,团体还需要补默认第1队,保证后续团体成绩下拉能出现该工会。
Sys_user sysUser = dao().fetch(Sys_user.class, Cnd.where("loginname", "=", activitySchoolApply.getLoginname()));
if (sysUser != null && sysUser.getLoginname().equals(activitySchoolApply.getLoginname()) && !sysUser.getUsername().equals(activitySchoolApply.getUsername())) {
throw Lang.makeThrow("工号已存在,请检查姓名和工号是否一致!");
}
if (sysUser == null) {
sysUser = createTemporaryUser(activitySchoolApply);
} else {
sysUser.setSex(activitySchoolApply.getSex());
update(sysUser);
}
fillTemporaryApplyUser(activitySchoolApply, sysUser);
insert(activitySchoolApply);
}
private Sys_user createTemporaryUser(ActivitySchoolApply activitySchoolApply) {
// 临时人员不存在系统账号时,按原逻辑创建基础账号,保证报名记录能关联 userId。
String pwd = "@dd3s#3618!";
String salt = R.UU32();
Sys_user user = new Sys_user();
user.setId(R.UU32());
user.setSalt(salt);
user.setPassword(PwdUtil.getPassword(pwd, salt));
user.setUsername(activitySchoolApply.getUsername());
user.setLoginname(activitySchoolApply.getLoginname());
user.setSex(activitySchoolApply.getSex());
user.setUnitId(activitySchoolApply.getUnitId());
user.setMobile(activitySchoolApply.getMobile());
dao().insert(user);
return user;
}
private void fillTemporaryApplyUser(ActivitySchoolApply activitySchoolApply, Sys_user sysUser) {
ActivityBasicUnit activityBasicUnit = dao().fetch(ActivityBasicUnit.class, Cnd.where("id", "=", sysUser.getUnitId()));
if (activityBasicUnit == null) {
throw Lang.makeThrow("未找到临时人员所属单位!");
}
ActivityBasicUnion basicUnion = dao().fetch(ActivityBasicUnion.class, Cnd.where("id", "=", activityBasicUnit.getUnionId()));
if (basicUnion == null) {
throw Lang.makeThrow("未找到临时人员所属工会!");
}
activitySchoolApply.setUserId(sysUser.getId());
activitySchoolApply.setApplyUser(SecurityUtil.getUserId());
activitySchoolApply.setApplyDate(DateUtil.now());
activitySchoolApply.setSex(sysUser.getSex());
activitySchoolApply.setUnitId(sysUser.getUnitId());
activitySchoolApply.setUnionId(basicUnion.getId());
activitySchoolApply.setActivityUnionId(basicUnion.getId());
activitySchoolApply.setActivityUnionName(basicUnion.getName());
activitySchoolApply.setStatus(activitySchoolApply.getStatus() == null ? 2 : activitySchoolApply.getStatus());
if ("2".equals(activitySchoolApply.getAwardsMode())) {
ActivitySchoolTeam team = getFirstTeam(activitySchoolApply.getActivityId(), activitySchoolApply.getEventId());
if (team == null) {
throw Lang.makeThrow("当前团体项目未创建队伍,无法添加临时人员!");
}
activitySchoolApply.setTeamId(team.getId());
activitySchoolApply.setTeam(team.getName());
}
}
@Override
@Aop(TransAop.READ_COMMITTED)
public void doApplyUser(ActivitySchoolApply[] userList, String eventId, String activityId, Boolean pass, String unionId) {
ActivityBasicUnit basicUnit = dao().fetch(ActivityBasicUnit.class, Cnd.where("id", "=", SecurityUtil.getUnitId()));
ActivityBasicUnion basicUnion = dao().fetch(ActivityBasicUnion.class, Cnd.where("id", "=", StrUtil.isNotBlank(unionId) ? unionId : basicUnit.getUnionId()));
ActivitySchool activity = dao().fetch(ActivitySchool.class, activityId);
ActivitySchoolTeam firstTeam = null;
if (!allowMoreTeam(activity)) {
firstTeam = getFirstTeam(activityId, eventId);
}
for (ActivitySchoolApply apply : userList) {
@@ -462,11 +391,6 @@ public class ActivitySportsApplyUserServiceImpl extends BaseServiceImpl<Activity
apply.setApplyDate(DateUtil.now());
apply.setActivityUnionId(basicUnion.getId());
apply.setActivityUnionName(basicUnion.getName());
// 未配置为可报多队的工会,保存时统一落到第一队,避免绕过前端提交其他队伍。
if (firstTeam != null) {
apply.setTeamId(firstTeam.getId());
apply.setTeam(firstTeam.getName());
}
}
@@ -487,29 +411,6 @@ public class ActivitySportsApplyUserServiceImpl extends BaseServiceImpl<Activity
}
private boolean allowMoreTeam(ActivitySchool activity) {
// 当前登录人工会在活动“报多队工会”列表中时,才允许选择第一队以外的队伍。
return activity != null
&& activity.getMoreTeamUnionIds() != null
&& activity.getMoreTeamUnionIds().contains(getUnionId());
}
private List<ActivitySchoolTeam> getApplyTeamList(String activityId, String eventId, boolean allowMoreTeam) {
List<ActivitySchoolTeam> teams = dao().query(ActivitySchoolTeam.class,
Cnd.where("eventId", "=", eventId)
.and("activityId", "=", activityId)
.asc("location"));
if (allowMoreTeam || teams.size() <= 1) {
return teams;
}
return teams.subList(0, 1);
}
private ActivitySchoolTeam getFirstTeam(String activityId, String eventId) {
List<ActivitySchoolTeam> teams = getApplyTeamList(activityId, eventId, false);
return teams.size() > 0 ? teams.get(0) : null;
}
@Override
public Pagination applyPageData(PageForm page, String activityId, String eventId, String unionId) {
Cnd cnd = Cnd.NEW();
@@ -9,7 +9,6 @@ import com.budwk.app.base.utils.CommonDownloadUtil;
import com.budwk.app.base.utils.DateUtil;
import com.budwk.app.sys.models.Sys_home_activity;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.activity.basic.models.ActivityEvent;
import com.budwk.app.zhgh.activity.basic.models.ActivityBasicUnit;
import com.budwk.app.zhgh.activity.culture.models.ActivityTissue;
import com.budwk.app.zhgh.activity.sports.models.ActivitySchool;
@@ -29,7 +28,6 @@ import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
@@ -98,11 +96,7 @@ public class ActivitySportsServiceImpl extends BaseServiceImpl<ActivitySchool> i
@Override
@Aop(TransAop.READ_COMMITTED)
public void doEdit(ActivitySchool activitySchool, ActivitySchoolEvent[] events, boolean forceReduceTeam) {
// 防止绕过 controller 直接调用编辑逻辑时误删已有报名人员使用的队伍,未确认时直接中断本次保存。
if (!forceReduceTeam && checkTeamReduceApply(activitySchool.getId(), events).size() > 0) {
throw Lang.makeThrow("减少队伍时存在已报名人员,请确认后再保存");
}
public void doEdit(ActivitySchool activitySchool, ActivitySchoolEvent[] events) {
ActivitySchool school = dao().fetch(ActivitySchool.class, activitySchool.getId());
if (school.getActivityLevel() == 40002) {
school.setBelongUnionId(SecurityUtil.getUnionId());
@@ -132,7 +126,6 @@ public class ActivitySportsServiceImpl extends BaseServiceImpl<ActivitySchool> i
}
for (ActivitySchoolEvent event : events) {
update(event);
syncTeam(activitySchool.getId(), event);
}
dao().delete(ActivityTissue.class, activitySchool.getId());
ActivityTissue activityTissue = new ActivityTissue();
@@ -164,85 +157,6 @@ public class ActivitySportsServiceImpl extends BaseServiceImpl<ActivitySchool> i
dao().insertOrUpdate(sysHomeActivity);
}
@Override
public List<NutMap> checkTeamReduceApply(String activityId, ActivitySchoolEvent[] events) {
// 检查“最多创建几队”减少后将被删除的队伍,返回仍有报名人员占用的队伍清单给前端确认。
List<NutMap> result = new ArrayList<>();
if (Strings.isBlank(activityId) || events == null || events.length == 0) {
return result;
}
for (ActivitySchoolEvent event : events) {
if (event == null || Strings.isBlank(event.getEventId()) || "allItems".equals(event.getEventId()) || event.getRestrictTotalTeam() == null) {
continue;
}
List<ActivitySchoolTeam> reduceTeams = getReduceTeams(activityId, event);
if (reduceTeams.size() == 0) {
continue;
}
ActivityEvent activityEvent = dao().fetch(ActivityEvent.class, event.getEventId());
for (ActivitySchoolTeam team : reduceTeams) {
int applyNum = dao().count(ActivitySchoolApply.class, Cnd.where("activityId", "=", activityId)
.and("eventId", "=", event.getEventId())
.and("teamId", "=", team.getId()));
if (applyNum > 0) {
result.add(NutMap.NEW()
.setv("eventId", event.getEventId())
.setv("eventName", activityEvent == null ? "" : activityEvent.getAllName())
.setv("teamId", team.getId())
.setv("teamName", team.getName())
.setv("applyNum", applyNum));
}
}
}
return result;
}
private List<ActivitySchoolTeam> getReduceTeams(String activityId, ActivitySchoolEvent event) {
// 按队伍位置保留前 N 队,超过目标队伍数的部分就是本次减少队伍时需要删除的队伍。
List<ActivitySchoolTeam> teams = dao().query(ActivitySchoolTeam.class, Cnd.where("activityId", "=", activityId)
.and("eventId", "=", event.getEventId())
.asc("location"));
int targetTotalTeam = event.getRestrictTotalTeam() == null ? 0 : Math.max(event.getRestrictTotalTeam(), 0);
List<ActivitySchoolTeam> reduceTeams = new ArrayList<>();
for (int i = targetTotalTeam; i < teams.size(); i++) {
reduceTeams.add(teams.get(i));
}
return reduceTeams;
}
private void syncTeam(String schoolId, ActivitySchoolEvent event) {
// 保存项目时同步 activity_school_team:增加队伍只补插缺少的队伍,减少队伍只删除超过目标数量的后续队伍。
if (event == null || Strings.isBlank(event.getEventId()) || "allItems".equals(event.getEventId()) || event.getRestrictTotalTeam() == null) {
return;
}
List<ActivitySchoolTeam> teams = dao().query(ActivitySchoolTeam.class, Cnd.where("activityId", "=", schoolId)
.and("eventId", "=", event.getEventId())
.asc("location"));
int currentTotalTeam = teams.size();
int targetTotalTeam = Math.max(event.getRestrictTotalTeam(), 0);
for (int i = 0; i < teams.size(); i++) {
ActivitySchoolTeam team = teams.get(i);
team.setMinNum(event.getRestrictMinNum());
team.setMaxNum(event.getRestrictMaxNum());
dao().updateIgnoreNull(team);
}
if (targetTotalTeam > currentTotalTeam) {
for (int i = currentTotalTeam + 1; i <= targetTotalTeam; i++) {
ActivitySchoolTeam team = new ActivitySchoolTeam();
team.setActivityId(schoolId);
team.setEventId(event.getEventId());
team.setName(String.format("第%d队", i));
team.setMinNum(event.getRestrictMinNum());
team.setMaxNum(event.getRestrictMaxNum());
dao().insert(team);
}
} else if (targetTotalTeam < currentTotalTeam) {
for (int i = targetTotalTeam; i < teams.size(); i++) {
dao().delete(ActivitySchoolTeam.class, teams.get(i).getId());
}
}
}
@Aop(TransAop.READ_COMMITTED)
private void addTeam(String schoolId, ActivitySchoolEvent[] events) {
if (events.length > 0) {
@@ -8,11 +8,9 @@ import com.budwk.app.base.service.BaseService;
import com.budwk.app.bpm.enums.BpmProcessInstanceStatusEnum;
import com.budwk.app.bpm.enums.BpmProcessTaskStatusEnum;
import com.budwk.app.flow.enums.ProcessInstanceStateEnum;
import com.budwk.app.sys.models.Sys_role;
import com.budwk.app.sys.models.Sys_user_role;
import com.budwk.app.sys.services.SysRoleService;
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.ClubUser;
import com.budwk.app.zhgh.club.model.SysClub;
import com.budwk.app.zhgh.club.service.SysClubService;
import org.nutz.dao.Cnd;
@@ -38,8 +36,6 @@ public class ClubCommonController {
@Inject
private SysClubService sysClubService;
@Inject
private SysRoleService sysRoleService;
@At
@SaCheckLogin
@@ -62,9 +58,9 @@ public class ClubCommonController {
public Result listClubByRole() {
Cnd cnd = Cnd.NEW();
if (!AuthUtil.hasRoleOr(RoleConstant.SYSADMIN.name(), RoleConstant.SCHOOL_UNION_ADMIN.name())) {
Sys_role sysRole = sysRoleService.getByCode(RoleConstant.CLUB_PRESIDENT);
List<Sys_user_role> userRoles = sysClubService.dao().query(Sys_user_role.class, Cnd.where("userId", "=", SecurityUtil.getUserId()).and("roleId", "=", sysRole.getId()));
List<String> myClubId = userRoles.stream().map(Sys_user_role::getClubId).toList();
// 报销申请只允许选择当前用户已加入的协会,避免看到未加入的协会数据。
List<ClubUser> clubUsers = sysClubService.dao().query(ClubUser.class, Cnd.where("userId", "=", SecurityUtil.getUserId()));
List<String> myClubId = clubUsers.stream().map(ClubUser::getClubId).distinct().toList();
cnd.and("c.id", "in", myClubId);
}
cnd.and("inst.state","=",ProcessInstanceStateEnum.FINISHED.getCode());
@@ -3,8 +3,12 @@ package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutLayAllocateUnion;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.vo.OutlayUnionAllocateImportVo;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.mvc.upload.TempFile;
import java.math.BigDecimal;
import java.util.List;
/**
* 分工会季度额度分配服务。
@@ -36,12 +40,63 @@ public interface OutlayManageUnionAllocateService extends BaseService<OutLayAllo
Result doBatchAllocate(BigDecimal allocateMoney, Integer quarterly, Integer year);
/**
* 重置当前季度的分配记录
* 判断某年某季度是否已经做过额度分配
*
* <p>重置时会先回滚 outlay_manage_union.totalQuota
* 再将当前季度的 outlay_allocate_union 记录标记删除。</p>
* <p>只要当前季度记录中存在分配额度大于 0 的有效记录
* 就认为该季度已经分配过额度,前端据此决定是否提示再次分配。</p>
*
* @param quarterly 要检查的季度,例如 1/2/3/4
* @param year 要检查的年份
* @return true 已分配过;false 未分配
*/
boolean hasAllocated(Integer quarterly, Integer year);
/**
* 解析导入文件并返回预览数据。
*
* @param file Excel 文件
* @return 解析后的预览数据
*/
List<OutlayUnionAllocateImportVo> readImportExcel(TempFile file);
/**
* 根据导入数据按分工会逐条分配季度额度。
*
* @param importList 导入预览数据
* @param quarterly 当前季度
* @param year 当前年度
* @return 导入分配结果
*/
Result doImportAllocate(List<OutlayUnionAllocateImportVo> importList, Integer quarterly, Integer year);
/**
* 导出分工会额度导入模板。
*
* @return 模板工作簿
*/
Workbook exportImportTemplate();
/**
* 重置指定年度季度的分配记录。
*
* <p>页面支持切换年度和季度,所以重置动作必须严格使用前端当前选择值,
* 不能再按系统当前自然季度处理,否则会出现页面筛选季度和实际重置季度不一致的问题。</p>
*
* @param quarterly 要重置的季度,例如 1/2/3/4
* @param year 要重置的年份
* @return Result 成功时返回 success;失败时返回错误信息
*/
Result deleteAllocateRecord();
Result deleteAllocateRecord(Integer quarterly, Integer year);
/**
* 按指定年度季度生成分工会预算记录。
*
* <p>生成前会先校验该年度季度是否已存在有效记录;
* 若已存在,则直接提示前端需要先重置后再重新生成。</p>
*
* @param quarterly 要生成的季度,例如 1/2/3/4
* @param year 要生成的年份
* @return Result 成功时返回 success;失败时返回错误信息
*/
Result doAllocateRecord(Integer quarterly, Integer year);
}
@@ -1,20 +1,36 @@
package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.impl;
import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayManageUnionAllocateService;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutLayAllocateUnion;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutlayManageUnion;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.vo.OutlayUnionAllocateImportVo;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.mvc.upload.TempFile;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 分工会季度额度分配实现。
@@ -44,6 +60,10 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl<OutLay
@Override
public Result doBatchAllocate(BigDecimal allocateMoney, Integer quarterly, Integer year) {
Result validateResult = validateCurrentQuarterOperation(quarterly);
if (validateResult != null) {
return validateResult;
}
List<OutLayAllocateUnion> allocateUnionList = dao().query(OutLayAllocateUnion.class,
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", quarterly)
.and(OutLayAllocateUnion::getYear, "=", year)
@@ -58,11 +78,155 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl<OutLay
}
@Override
public Result deleteAllocateRecord() {
int currentQuarter = getCurrentQuarter();
public boolean hasAllocated(Integer quarterly, Integer year) {
if (quarterly == null || year == null) {
return false;
}
int count = dao().count(OutLayAllocateUnion.class,
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", quarterly)
.and(OutLayAllocateUnion::getYear, "=", year)
.and(OutLayAllocateUnion::getDelFlag, "=", false)
.and("allocateMoney", ">", BigDecimal.ZERO));
return count > 0;
}
@Override
public List<OutlayUnionAllocateImportVo> readImportExcel(TempFile file) {
String extName = FileUtil.extName(file.getFile());
if (!"xlsx".equalsIgnoreCase(extName) && !"xls".equalsIgnoreCase(extName)) {
throw Lang.makeThrow("请上传xlsx或xls格式文件");
}
List<OutlayUnionAllocateImportVo> importList = ExcelImportUtil.importExcel(file.getFile(),
OutlayUnionAllocateImportVo.class, new ImportParams());
List<Sys_union> unionList = dao().query(Sys_union.class, Cnd.NEW());
Map<String, Sys_union> unionMap = new HashMap<>();
for (Sys_union union : unionList) {
unionMap.put(union.getUnionCode(), union);
}
Set<String> duplicateUnionCodeSet = new LinkedHashSet<>();
Set<String> existUnionCodeSet = new LinkedHashSet<>();
for (OutlayUnionAllocateImportVo item : importList) {
if (StrUtil.isBlank(item.getUnionCode())) {
continue;
}
if (!existUnionCodeSet.add(item.getUnionCode())) {
duplicateUnionCodeSet.add(item.getUnionCode());
}
}
for (int i = 0; i < importList.size(); i++) {
OutlayUnionAllocateImportVo item = importList.get(i);
item.setRowNum(i + 2);
if (StrUtil.isBlank(item.getUnionCode())) {
item.setErrMsg("工会编码不能为空");
continue;
}
if (item.getAllocateMoney() == null) {
item.setErrMsg("分配额度不能为空");
continue;
}
if (item.getAllocateMoney().compareTo(BigDecimal.ZERO) < 0) {
item.setErrMsg("分配额度不能小于0");
continue;
}
Sys_union union = unionMap.get(item.getUnionCode());
if (Lang.isEmpty(union)) {
item.setErrMsg("工会编码不存在");
continue;
}
item.setUnionName(union.getName());
if (duplicateUnionCodeSet.contains(item.getUnionCode())) {
item.setErrMsg("工会编码重复");
}
}
return importList;
}
@Override
public Result doImportAllocate(List<OutlayUnionAllocateImportVo> importList, Integer quarterly, Integer year) {
Result validateResult = validateCurrentQuarterOperation(quarterly);
if (validateResult != null) {
return validateResult;
}
if (importList == null || importList.isEmpty()) {
return Result.error("请先上传导入数据");
}
List<OutLayAllocateUnion> allocateUnionList = dao().query(OutLayAllocateUnion.class,
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", currentQuarter)
.and(OutLayAllocateUnion::getYear, "=", DateUtil.thisYear())
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", quarterly)
.and(OutLayAllocateUnion::getYear, "=", year)
.and(OutLayAllocateUnion::getDelFlag, "=", false));
if (allocateUnionList == null || allocateUnionList.isEmpty()) {
return Result.error("当前季度没有分配记录!");
}
List<Sys_union> unionList = dao().query(Sys_union.class, Cnd.NEW());
Map<String, Sys_union> unionMap = new HashMap<>();
for (Sys_union union : unionList) {
unionMap.put(union.getUnionCode(), union);
}
Map<String, OutLayAllocateUnion> allocateUnionMap = new HashMap<>();
for (OutLayAllocateUnion allocateUnion : allocateUnionList) {
allocateUnionMap.put(allocateUnion.getUnionId(), allocateUnion);
}
List<String> errorList = new ArrayList<>();
for (OutlayUnionAllocateImportVo item : importList) {
if (StrUtil.isBlank(item.getUnionCode())) {
errorList.add("" + item.getRowNum() + "行:工会编码不能为空");
continue;
}
if (item.getAllocateMoney() == null) {
errorList.add("" + item.getRowNum() + "行:分配额度不能为空");
continue;
}
if (item.getAllocateMoney().compareTo(BigDecimal.ZERO) < 0) {
errorList.add("" + item.getRowNum() + "行:分配额度不能小于0");
continue;
}
if (StrUtil.isNotBlank(item.getErrMsg())) {
errorList.add("" + item.getRowNum() + "行:" + item.getErrMsg());
continue;
}
Sys_union union = unionMap.get(item.getUnionCode());
if (Lang.isEmpty(union)) {
errorList.add("" + item.getRowNum() + "行:工会编码不存在");
continue;
}
if (!allocateUnionMap.containsKey(union.getId())) {
errorList.add("" + item.getRowNum() + "行:当前季度未生成该分工会分配记录");
}
}
if (!errorList.isEmpty()) {
return Result.error(String.join("", errorList));
}
for (OutlayUnionAllocateImportVo item : importList) {
Sys_union union = unionMap.get(item.getUnionCode());
OutLayAllocateUnion allocateUnion = allocateUnionMap.get(union.getId());
// 导入分配与手工分配保持同一套金额同步规则,确保季度表和年度预算表数据一致。
applyAllocateMoney(allocateUnion, item.getAllocateMoney());
}
return Result.success("导入分配成功");
}
@Override
public Workbook exportImportTemplate() {
List<ExcelExportEntity> entityList = new ArrayList<>();
entityList.add(new ExcelExportEntity("工会编码", "unionCode", 20));
entityList.add(new ExcelExportEntity("分配额度", "allocateMoney", 20));
ExportParams exportParams = new ExportParams();
exportParams.setType(ExcelType.XSSF);
return ExcelExportUtil.exportExcel(exportParams, entityList, new ArrayList<>());
}
@Override
public Result deleteAllocateRecord(Integer quarterly, Integer year) {
if (quarterly == null || year == null) {
return Result.error("参数错误!");
}
Result validateResult = validateCurrentQuarterOperation(quarterly);
if (validateResult != null) {
return validateResult;
}
List<OutLayAllocateUnion> allocateUnionList = dao().query(OutLayAllocateUnion.class,
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", quarterly)
.and(OutLayAllocateUnion::getYear, "=", year)
.and(OutLayAllocateUnion::getDelFlag, "=", false));
if (allocateUnionList == null || allocateUnionList.isEmpty()) {
return Result.error("当前季度还未分配,无法重置!");
@@ -73,12 +237,38 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl<OutLay
}
dao().update(OutLayAllocateUnion.class, Chain.make("delFlag", true),
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", currentQuarter)
.and(OutLayAllocateUnion::getYear, "=", DateUtil.thisYear())
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", quarterly)
.and(OutLayAllocateUnion::getYear, "=", year)
.and(OutLayAllocateUnion::getDelFlag, "=", false));
return Result.success();
}
@Override
public Result doAllocateRecord(Integer quarterly, Integer year) {
if (quarterly == null || year == null) {
return Result.error("参数错误!");
}
Result validateResult = validateCurrentQuarterOperation(quarterly);
if (validateResult != null) {
return validateResult;
}
int count = dao().count(OutLayAllocateUnion.class,
Cnd.where(OutLayAllocateUnion::getQuarterly, "=", quarterly)
.and(OutLayAllocateUnion::getYear, "=", year)
.and(OutLayAllocateUnion::getDelFlag, "=", false));
if (count > 0) {
return Result.error("当前季度已分配,如需重新分配请点击重置分配记录!");
}
// 第一季度需要承接上一年度剩余额度,其余季度承接当年预算额度,确保生成记录时的分配前额度准确。
Integer sourceYear = quarterly == 1 ? year - 1 : year;
List<OutlayManageUnion> outlayManageUnionList = dao().query(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getYear, "=", sourceYear));
List<OutLayAllocateUnion> insertList = buildAllocateUnionList(outlayManageUnionList, quarterly, year);
insert(insertList);
return Result.success();
}
/**
* 按“先回退旧额度,再写入新额度”的方式同步季度记录和年度预算表。
*
@@ -89,7 +279,7 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl<OutLay
BigDecimal oldAllocateMoney = defaultValue(allocateUnion.getAllocateMoney());
OutlayManageUnion manageUnion = dao().fetch(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getUnionId, "=", allocateUnion.getUnionId())
.and(OutlayManageUnion::getYear, "=", DateUtil.thisYear()));
.and(OutlayManageUnion::getYear, "=", allocateUnion.getYear()));
if (Lang.isEmpty(manageUnion)) {
manageUnion = buildManageUnion(allocateUnion, newAllocateMoney);
@@ -115,7 +305,7 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl<OutLay
private void rollbackAllocateMoney(OutLayAllocateUnion allocateUnion) {
OutlayManageUnion manageUnion = dao().fetch(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getUnionId, "=", allocateUnion.getUnionId())
.and(OutlayManageUnion::getYear, "=", DateUtil.thisYear()));
.and(OutlayManageUnion::getYear, "=", allocateUnion.getYear()));
if (Lang.isEmpty(manageUnion)) {
return;
}
@@ -135,7 +325,7 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl<OutLay
private OutlayManageUnion buildManageUnion(OutLayAllocateUnion allocateUnion, BigDecimal allocateMoney) {
Sys_union union = dao().fetch(Sys_union.class, allocateUnion.getUnionId());
OutlayManageUnion manageUnion = new OutlayManageUnion();
manageUnion.setYear(DateUtil.thisYear());
manageUnion.setYear(allocateUnion.getYear());
manageUnion.setUnionId(allocateUnion.getUnionId());
manageUnion.setTotalQuota(defaultValue(allocateUnion.getAllocateHeadMoney()).add(allocateMoney));
manageUnion.setUsedQuota(BigDecimal.ZERO);
@@ -164,4 +354,54 @@ public class OutlayManageUnionAllocateServiceImpl extends BaseServiceImpl<OutLay
private int getCurrentQuarter() {
return DateUtil.month(DateUtil.date()) / 3 + 1;
}
/**
* 预算季度记录相关操作只能针对当前自然季度执行。
*
* @param quarterly 前端传入的目标季度
* @return Result 不允许操作时返回错误结果;允许操作时返回 null
*/
private Result validateCurrentQuarterOperation(Integer quarterly) {
if (quarterly == null) {
return Result.error("参数错误!");
}
int currentQuarter = getCurrentQuarter();
if (!quarterly.equals(currentQuarter)) {
return Result.error("当前仅允许操作第" + currentQuarter + "季度数据,请切换后再操作!");
}
return null;
}
/**
* 按目标年度季度初始化要生成的分工会分配记录。
*
* @param outlayManageUnionList 用于计算“分配前额度”的年度预算数据
* @param quarterly 目标季度
* @param year 目标年度
* @return List<OutLayAllocateUnion> 待插入的季度分配记录
*/
private List<OutLayAllocateUnion> buildAllocateUnionList(List<OutlayManageUnion> outlayManageUnionList, Integer quarterly, Integer year) {
List<Sys_union> unionList = dao().query(Sys_union.class, Cnd.NEW());
List<OutLayAllocateUnion> insertList = new ArrayList<>();
for (Sys_union union : unionList) {
OutLayAllocateUnion allocateUnion = new OutLayAllocateUnion();
allocateUnion.setYear(year);
allocateUnion.setQuarterly(quarterly);
allocateUnion.setUnionId(union.getId());
allocateUnion.setAllocateMoney(BigDecimal.ZERO);
OutlayManageUnion outlayManageUnion = outlayManageUnionList.stream()
.filter(o -> o.getUnionId().equals(union.getId()))
.findFirst()
.orElse(null);
if (Lang.isNotEmpty(outlayManageUnion)) {
BigDecimal surplusMoney = defaultValue(outlayManageUnion.getTotalQuota())
.subtract(defaultValue(outlayManageUnion.getUsedQuota()));
allocateUnion.setAllocateHeadMoney(surplusMoney);
} else {
allocateUnion.setAllocateHeadMoney(BigDecimal.ZERO);
}
insertList.add(allocateUnion);
}
return insertList;
}
}
@@ -1,6 +1,7 @@
package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.impl;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.club.model.OutlayManageClub;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.model.OutlayUseDetail;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.school.model.OutlayManageSchool;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayUseDetailService;
@@ -21,49 +22,65 @@ public class OutlayUseDetailServiceImpl extends BaseServiceImpl<OutlayUseDetail>
@Override
public void doDeleteDetail(String id, String outlayType) {
//更新预算表的金额
updateOutlayManage(id, null,outlayType,false);
//更新完删除
// 先回滚对应预算的已使用额度,再删除详情记录。
updateOutlayManage(id, null, outlayType, false);
delete(id);
}
@Override
public void doEditDetail(OutlayUseDetail outlayUseDetail,String outlayType) {
updateOutlayManage(outlayUseDetail.getId(), outlayUseDetail,outlayType,true);
public void doEditDetail(OutlayUseDetail outlayUseDetail, String outlayType) {
// 编辑详情时需要先回退旧金额,再叠加新金额,保证预算台账准确。
updateOutlayManage(outlayUseDetail.getId(), outlayUseDetail, outlayType, true);
update(outlayUseDetail);
}
/**
* 更新预算表
* 同步预算主表的已使用额度,保证校工会、分工会、协会三类台账口径一致。
*
* @param id
* @param outlayType
* @param id 详情主键
* @param outlayUseDetail 编辑后的详情对象,删除场景可为空
* @param outlayType 预算类型:school/union/club
* @param isEdit 是否为编辑场景
*/
private void updateOutlayManage(String id, OutlayUseDetail outlayUseDetail,String outlayType,Boolean isEdit) {
//找到是哪一条的预算详情
private void updateOutlayManage(String id, OutlayUseDetail outlayUseDetail, String outlayType, Boolean isEdit) {
OutlayUseDetail detail = fetch(id);
//拿到预算详情的调整金额
if (outlayType.equals("school")) {
//找到预算分配的记录
if (detail == null) {
return;
}
if ("school".equals(outlayType)) {
OutlayManageSchool manageSchool = dao().fetch(OutlayManageSchool.class, detail.getOutlayManageId());
if (manageSchool == null) {
return;
}
manageSchool.setUsedQuota(manageSchool.getUsedQuota().subtract(detail.getAdjustMoney()));
if (isEdit){
//如果是修改,就先减去原来的值在加上现在新的值
if (Boolean.TRUE.equals(isEdit) && outlayUseDetail != null) {
manageSchool.setUsedQuota(manageSchool.getUsedQuota().add(outlayUseDetail.getAdjustMoney()));
}
update(manageSchool);
} else if (outlayType.equals("union")) {
return;
}
if ("union".equals(outlayType)) {
OutlayManageUnion manageUnion = dao().fetch(OutlayManageUnion.class, detail.getOutlayManageId());
if (manageUnion == null) {
return;
}
manageUnion.setUsedQuota(manageUnion.getUsedQuota().subtract(detail.getAdjustMoney()));
if (isEdit){
//如果是修改,就先减去原来的值在加上现在新的值
if (Boolean.TRUE.equals(isEdit) && outlayUseDetail != null) {
manageUnion.setUsedQuota(manageUnion.getUsedQuota().add(outlayUseDetail.getAdjustMoney()));
}
update(manageUnion);
return;
}
if ("club".equals(outlayType)) {
OutlayManageClub manageClub = dao().fetch(OutlayManageClub.class, detail.getOutlayManageId());
if (manageClub == null) {
return;
}
manageClub.setUsedQuota(manageClub.getUsedQuota().subtract(detail.getAdjustMoney()));
if (Boolean.TRUE.equals(isEdit) && outlayUseDetail != null) {
manageClub.setUsedQuota(manageClub.getUsedQuota().add(outlayUseDetail.getAdjustMoney()));
}
update(manageClub);
}
}
}
@@ -1,20 +1,19 @@
package com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.controller;
import com.budwk.app.base.utils.CommonDownloadUtil;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
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.service.BaseService;
import com.budwk.app.sys.models.Sys_union;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.service.OutlayManageUnionAllocateService;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutLayAllocateUnion;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutlayManageUnion;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.vo.OutlayUnionAllocateImportVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
@@ -22,13 +21,18 @@ import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Lang;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.annotation.POST;
import org.nutz.mvc.upload.TempFile;
import org.nutz.mvc.upload.UploadAdaptor;
import org.nutz.mvc.annotation.AdaptBy;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
@@ -107,76 +111,82 @@ public class OutlayManageUnionAllocateController {
return outlayManageUnionAllocateService.doBatchAllocate(allocateMoney, quarterly, year);
}
@At
@ApiOperation("校验当前季度是否已分配额度")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public Result hasAllocated(@Param("quarterly") Integer quarterly,
@Param("year") Integer year) {
if (quarterly == null || year == null) {
return Result.error("参数错误!");
}
return Result.success(outlayManageUnionAllocateService.hasAllocated(quarterly, year));
}
@At
@POST
@AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"})
@ApiOperation("读取导入分配Excel")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public Result readImportExcel(TempFile file) {
try {
return Result.success(outlayManageUnionAllocateService.readImportExcel(file));
} catch (Exception e) {
log.error("读取分工会额度导入文件失败", e);
return Result.error(e.getMessage());
}
}
@At
@ApiOperation("导入分配分工会额度")
@Aop(TransAop.READ_COMMITTED)
@SLog(tag = "分工会预算-季度预算分配", msg = "导入分配分工会额度")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public Result doImportAllocate(String data,
@Param("quarterly") Integer quarterly,
@Param("year") Integer year) {
if (StrUtil.isBlank(data) || quarterly == null || year == null) {
return Result.error("参数错误!");
}
List<OutlayUnionAllocateImportVo> importList = Json.fromJsonAsList(OutlayUnionAllocateImportVo.class, data);
return outlayManageUnionAllocateService.doImportAllocate(importList, quarterly, year);
}
@At
@Ok("void")
@ApiOperation("下载导入分配模板")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public void downloadImportTemplate(HttpServletResponse response) {
try {
Workbook workbook = outlayManageUnionAllocateService.exportImportTemplate();
CommonDownloadUtil.download("分工会额度导入模板.xlsx", workbook, response);
} catch (Exception e) {
log.error("下载分工会额度导入模板失败", e);
}
}
@At
@ApiOperation("重置预算季度记录")
@Aop(TransAop.READ_COMMITTED)
@SLog(tag = "分工会预算-季度预算分配", msg = "重置预算季度记录")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public Result deleteAllocateRecord() {
return outlayManageUnionAllocateService.deleteAllocateRecord();
public Result deleteAllocateRecord(@Param("quarterly") Integer quarterly,
@Param("year") Integer year) {
if (quarterly == null || year == null) {
return Result.error("参数错误!");
}
return outlayManageUnionAllocateService.deleteAllocateRecord(quarterly, year);
}
@At
@ApiOperation("预算季度记录生成")
@SLog(tag = "分工会预算-季度预算分配", msg = "生成了预算分配记录")
@SaCheckPermission("outlay.outlayManage.union.allocate")
public Result doAllocateRecord() {
int quarter = DateUtil.month(DateUtil.date()) / 3 + 1;
// 查询当前季度
int count = baseService.dao().count(OutLayAllocateUnion.class, Cnd.where(OutLayAllocateUnion::getQuarterly, "=", quarter)
.and(OutLayAllocateUnion::getYear, "=", DateUtil.thisYear())
.and(OutLayAllocateUnion::getDelFlag, "=", 0));
if (count > 0) {
return Result.error("当前季度已分配,如需重新分配请点击重置分配记录!");
public Result doAllocateRecord(@Param("quarterly") Integer quarterly,
@Param("year") Integer year) {
if (quarterly == null || year == null) {
return Result.error("参数错误!");
}
List<OutlayManageUnion> outlayManageUnionList;
if (quarter == 1) {
//如果是第一季度,查询去年剩余额度
outlayManageUnionList = baseService.dao().query(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getYear, "=", DateUtil.thisYear() - 1));
} else {
//非第一季度
outlayManageUnionList = baseService.dao().query(OutlayManageUnion.class,
Cnd.where(OutlayManageUnion::getYear, "=", DateUtil.thisYear()));
}
List<OutLayAllocateUnion> insertList = this.initOutLayAllocateUnion(outlayManageUnionList);
baseService.insert(insertList);
return Result.success();
return outlayManageUnionAllocateService.doAllocateRecord(quarterly, year);
}
/**
* 初始化需要添加的数据
*
* @param outlayManageUnionList
* @return
*/
public List<OutLayAllocateUnion> initOutLayAllocateUnion(List<OutlayManageUnion> outlayManageUnionList) {
int quarter = DateUtil.month(DateUtil.date()) / 3 + 1;
List<Sys_union> unionList = baseService.dao().query(Sys_union.class, Cnd.NEW());
List<OutLayAllocateUnion> insertList = new ArrayList<>();
for (Sys_union union : unionList) {
OutLayAllocateUnion allocateUnion = new OutLayAllocateUnion();
allocateUnion.setYear(DateUtil.thisYear());
allocateUnion.setQuarterly(quarter);
allocateUnion.setUnionId(union.getId());
allocateUnion.setAllocateMoney(BigDecimal.ZERO);
//根据院级工会ID查询
OutlayManageUnion outlayManageUnion = outlayManageUnionList.stream().filter(o -> o.getUnionId().equals(union.getId())).findFirst().orElse(null);
if (Lang.isNotEmpty(outlayManageUnion)) {
BigDecimal surplusMoney = outlayManageUnion.getTotalQuota().subtract(outlayManageUnion.getUsedQuota());
allocateUnion.setAllocateHeadMoney(surplusMoney);
} else {
allocateUnion.setAllocateHeadMoney(BigDecimal.ZERO);
}
insertList.add(allocateUnion);
}
return insertList;
}
}
@@ -259,7 +259,14 @@ public class UnionReimburseApplyController {
return Result.success(value);
}
// 如果没有找到该社团的经费记录,返回0
return Result.success(0.0);
// 协会在年度预算分配之后才创建时,不会自动生成当年预算记录,这里给出明确提示。
return Result.error("该协会本年度未生成预算记录,请先在协会预算分配中补分配");
}
@At
@ApiOperation("统一查询经费余额")
@SaCheckPermission(value = {"unionReimburse.apply", "h5.unionReimburse.apply"}, mode = SaMode.OR)
public Result getBudgetBalance(String reimburseFundSource, String clubId) {
return unionReimburseService.getBudgetBalance(reimburseFundSource, clubId);
}
}
@@ -15,7 +15,6 @@ import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.nutz.aop.interceptor.ioc.TransAop;
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;
@@ -27,18 +26,15 @@ import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.Date;
import java.util.List;
@IocBean
@At("/platform/unionReimburse/review")
@Ok("json:full")
@Api("审核报销")
@Api("工会报销审核")
@Slf4j
public class UnionReimburseReviewController {
@Inject
private Dao dao;
@Inject
private UnionReimburseService unionReimburseService;
@@ -98,42 +94,34 @@ public class UnionReimburseReviewController {
}
@At
@ApiOperation("审核")
@ApiOperation("审核报销")
@Aop(TransAop.READ_COMMITTED)
@SaCheckPermission(value = {"unionReimburse.review", "h5.unionReimburse.review"}, mode = SaMode.OR)
@SLog(tag = "审核工会报销", msg = "审核工会报销")
@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();
return unionReimburseService.reviewApply(unionReimburse.getId(), unionReimburse.getReviewOpinion(), Integer.parseInt(submitType));
}
@At
@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));
for (UnionReimburse reimbursement : reimbursements) {
reimbursement.setStateId(3);
reimbursement.setReviewTime(new Date());
reimbursement.setReviewOpinion("通过");
dao.update(reimbursement);
Result result = unionReimburseService.reviewApply(reimbursement.getId(), "通过", 3);
if (result.getCode() != 0) {
return result;
}
}
return Result.success("一键审核完成,共处理 " + reimbursements.size() + " 条记录");
return Result.success("一键审核完成,共处理" + reimbursements.size() + "条记录");
} catch (Exception e) {
log.error("一键审核失败");
log.error("一键审核失败", e);
return Result.error("一键审核失败: " + e.getMessage());
}
}
@@ -1,7 +1,7 @@
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.base.service.BaseService;
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;
@@ -9,7 +9,7 @@ import org.nutz.dao.sql.Sql;
import java.util.List;
public interface UnionReimburseService extends BaseService<UnionReimburse> {
public interface UnionReimburseService extends BaseService<UnionReimburse> {
Sql getSql(UnionReimbursePageForm pageForm);
@@ -19,7 +19,7 @@ public interface UnionReimburseService extends BaseService<UnionReimburse> {
Result saveApply(UnionReimburse unionReimburse, int stateId);
/**
* 查询申请表单详情,补齐发票明细回显数据。
* 查询申请表单详情,补齐发票明细回显数据。
*/
UnionReimburse getApplyForm(String id);
@@ -34,8 +34,17 @@ public interface UnionReimburseService extends BaseService<UnionReimburse> {
Result checkInvoiceDuplicate(String invoiceNo, String reimburseId);
/**
* 识别单张发票文件,并在需要时调用腾讯云验真接口补齐票面信息。
* 识别单张发票文件,并在需要时调用验真接口补齐票面信息。
*/
Result recognizeInvoice(String fileId, Boolean verifySwitch);
/**
* 查询报销可用经费余额,同时校验是否已分配以及协会归属权限。
*/
Result getBudgetBalance(String reimburseFundSource, String clubId);
/**
* 审核报销,审核通过时扣减对应预算并新增预算使用详情。
*/
Result reviewApply(String reimburseId, String reviewOpinion, int submitType);
}
@@ -8,6 +8,11 @@ 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.club.model.ClubUser;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.club.model.OutlayManageClub;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.model.OutlayUseDetail;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.school.model.OutlayManageSchool;
import com.budwk.app.zhgh.dayofficework.outlay.outlayManage.union.model.OutlayManageUnion;
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;
@@ -123,6 +128,10 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
if (validateResult != null) {
return validateResult;
}
Result fundValidateResult = validateFundSourceBeforeSubmit(unionReimburse);
if (fundValidateResult != null) {
return fundValidateResult;
}
Result duplicateResult = validateInvoiceDuplicate(unionReimburse);
if (duplicateResult != null) {
return duplicateResult;
@@ -232,8 +241,80 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
}
/**
* 统一规整发票明细中的文本和金额,避免空格、空数组等脏数据进入库表
* 按经费来源统一查询当前可用余额,未分配或权限不匹配时直接拦截
*/
@Override
public Result getBudgetBalance(String reimburseFundSource, String clubId) {
if (StrUtil.isBlank(reimburseFundSource)) {
return Result.error("请选择经费来源");
}
if ("UNION_REIMBURSE_FUND_SOURCE_1".equals(reimburseFundSource)) {
OutlayManageSchool outlayManageSchool = dao().fetch(OutlayManageSchool.class,
Cnd.where("year", "=", DateUtil.thisYear()));
if (outlayManageSchool == null) {
return Result.error("校工会经费未分配");
}
return Result.success(formatMoney(outlayManageSchool.getTotalQuota().subtract(outlayManageSchool.getUsedQuota())));
}
if ("UNION_REIMBURSE_FUND_SOURCE_2".equals(reimburseFundSource)) {
OutlayManageUnion outlayManageUnion = dao().fetch(OutlayManageUnion.class,
Cnd.where("unionId", "=", SecurityUtil.getUnionId()).and("year", "=", DateUtil.thisYear()));
if (outlayManageUnion == null) {
return Result.error("分工会经费未分配");
}
return Result.success(formatMoney(outlayManageUnion.getTotalQuota().subtract(outlayManageUnion.getUsedQuota())));
}
if ("UNION_REIMBURSE_FUND_SOURCE_3".equals(reimburseFundSource)) {
if (StrUtil.isBlank(clubId)) {
return Result.error("请选择协会");
}
List<String> myClubIds = getCurrentUserClubIds();
if (!isAdmin() && !myClubIds.contains(clubId)) {
return Result.error("当前用户无权使用该协会经费");
}
OutlayManageClub outlayManageClub = dao().fetch(OutlayManageClub.class,
Cnd.where("clubId", "=", clubId).and("year", "=", DateUtil.thisYear()));
if (outlayManageClub == null) {
return Result.error("该协会本年度未生成预算记录,请先在协会预算分配中补分配");
}
return Result.success(formatMoney(outlayManageClub.getTotalQuota().subtract(outlayManageClub.getUsedQuota())));
}
return Result.error("不支持的经费来源");
}
/**
* 审核通过时统一校验余额、扣减预算并写入预算使用详情,避免控制器分散业务逻辑。
*/
@Override
public Result reviewApply(String reimburseId, String reviewOpinion, int submitType) {
if (!List.of(3, 4, 5).contains(submitType)) {
return Result.error("无效的审核操作类型");
}
UnionReimburse dbRecord = this.fetch(reimburseId);
if (dbRecord == null) {
return Result.error("记录不存在");
}
if (submitType == 3) {
// 已通过的单据再次触发通过时直接返回,避免重复扣减预算。
if (Integer.valueOf(3).equals(dbRecord.getStateId())) {
return Result.success();
}
Result validateResult = validateFundSourceBeforeSubmit(dbRecord);
if (validateResult != null) {
return validateResult;
}
Result deductResult = deductBudgetAndSaveUseDetail(dbRecord);
if (deductResult != null && deductResult.getCode() != 0) {
return deductResult;
}
}
dbRecord.setReviewTime(new Date());
dbRecord.setStateId(submitType);
dbRecord.setReviewOpinion(reviewOpinion);
dao().update(dbRecord);
return Result.success();
}
private void normalizeInvoiceDetails(UnionReimburse unionReimburse) {
if (unionReimburse.getInvoiceDetails() == null) {
unionReimburse.setInvoiceDetails(new ArrayList<>());
@@ -289,15 +370,15 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
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.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("请填写支付内容");
}
@@ -342,8 +423,159 @@ public class UnionReimburseServiceImpl extends BaseServiceImpl<UnionReimburse> i
}
/**
* 同次提交和历史记录都要拦截重复发票,避免重复报销
* 提交和审核前统一校验预算是否已分配、余额是否充足
*/
private Result validateFundSourceBeforeSubmit(UnionReimburse unionReimburse) {
Result balanceResult = getBudgetBalance(unionReimburse.getReimburseFundSource(), unionReimburse.getClubId());
if (balanceResult == null || balanceResult.getCode() != 0) {
return balanceResult == null ? Result.error("经费余额校验失败") : balanceResult;
}
BigDecimal applyMoney = getApplyMoney(unionReimburse);
if (applyMoney.compareTo(BigDecimal.ZERO) <= 0) {
return Result.error("报销金额必须大于0");
}
BigDecimal balance = new BigDecimal(String.valueOf(balanceResult.getData()));
if (balance.compareTo(applyMoney) < 0) {
return Result.error("经费余额不足,当前余额:" + formatMoney(balance));
}
unionReimburse.setFundBalance(balance.doubleValue());
return null;
}
/**
* 审核通过后按经费来源扣减预算,并补写预算使用详情,便于后续台账追踪。
*/
private Result deductBudgetAndSaveUseDetail(UnionReimburse unionReimburse) {
BigDecimal applyMoney = getApplyMoney(unionReimburse);
String reimburseFundSource = unionReimburse.getReimburseFundSource();
if ("UNION_REIMBURSE_FUND_SOURCE_1".equals(reimburseFundSource)) {
OutlayManageSchool outlayManageSchool = dao().fetch(OutlayManageSchool.class,
Cnd.where("year", "=", DateUtil.thisYear()));
if (outlayManageSchool == null) {
return Result.error("校工会经费未分配");
}
if (outlayManageSchool.getTotalQuota().subtract(outlayManageSchool.getUsedQuota()).compareTo(applyMoney) < 0) {
return Result.error("校工会经费余额不足");
}
outlayManageSchool.setUsedQuota(outlayManageSchool.getUsedQuota().add(applyMoney));
dao().updateIgnoreNull(outlayManageSchool);
insertUseDetail(unionReimburse, outlayManageSchool.getId(), applyMoney);
return Result.success();
}
if ("UNION_REIMBURSE_FUND_SOURCE_2".equals(reimburseFundSource)) {
OutlayManageUnion outlayManageUnion = dao().fetch(OutlayManageUnion.class,
Cnd.where("unionId", "=", unionReimburse.getUnionId()).and("year", "=", DateUtil.thisYear()));
if (outlayManageUnion == null) {
return Result.error("分工会经费未分配");
}
if (outlayManageUnion.getTotalQuota().subtract(outlayManageUnion.getUsedQuota()).compareTo(applyMoney) < 0) {
return Result.error("分工会经费余额不足");
}
outlayManageUnion.setUsedQuota(outlayManageUnion.getUsedQuota().add(applyMoney));
dao().updateIgnoreNull(outlayManageUnion);
insertUseDetail(unionReimburse, outlayManageUnion.getId(), applyMoney);
return Result.success();
}
if ("UNION_REIMBURSE_FUND_SOURCE_3".equals(reimburseFundSource)) {
OutlayManageClub outlayManageClub = dao().fetch(OutlayManageClub.class,
Cnd.where("clubId", "=", unionReimburse.getClubId()).and("year", "=", DateUtil.thisYear()));
if (outlayManageClub == null) {
return Result.error("该协会本年度未生成预算记录,请先在协会预算分配中补分配");
}
if (outlayManageClub.getTotalQuota().subtract(outlayManageClub.getUsedQuota()).compareTo(applyMoney) < 0) {
return Result.error("协会经费余额不足");
}
outlayManageClub.setUsedQuota(outlayManageClub.getUsedQuota().add(applyMoney));
dao().updateIgnoreNull(outlayManageClub);
insertUseDetail(unionReimburse, outlayManageClub.getId(), applyMoney);
return Result.success();
}
return Result.error("不支持的经费来源");
}
/**
* 一张报销单只写入一条预算使用详情,避免重复通过或重复点击造成重复明细。
*/
private void insertUseDetail(UnionReimburse unionReimburse, String outlayManageId, BigDecimal applyMoney) {
OutlayUseDetail oldDetail = dao().fetch(OutlayUseDetail.class, Cnd.where("outlayReimburseId", "=", unionReimburse.getId()));
if (oldDetail != null) {
return;
}
OutlayUseDetail detail = new OutlayUseDetail();
detail.setOutlayManageId(outlayManageId);
detail.setOutlayReimburseId(unionReimburse.getId());
detail.setAdjustMoney(applyMoney);
detail.setAdjustReason(StrUtil.blankToDefault(unionReimburse.getPaymentNotes(), getReimburseProjectName(unionReimburse.getReimburseProject())));
detail.setAdjustUserId(SecurityUtil.getUserId());
detail.setAdjustUserName(SecurityUtil.getUserUsername());
detail.setAdjustLoginName(SecurityUtil.getUserLoginname());
detail.setProjectName(buildUseDetailProjectName(unionReimburse));
detail.setActivityNumber(unionReimburse.getActivityNumber());
detail.setActivityTime(buildUseDetailTime(unionReimburse));
dao().insert(detail);
}
private BigDecimal getApplyMoney(UnionReimburse unionReimburse) {
Double money = "UNION_REIMBURSE_PROJECT_1".equals(unionReimburse.getReimburseProject())
? unionReimburse.getCondolenceMoney() : unionReimburse.getMoney();
return BigDecimal.valueOf(money == null ? 0D : money).setScale(2, RoundingMode.HALF_UP);
}
private String buildUseDetailProjectName(UnionReimburse unionReimburse) {
if (StrUtil.isNotBlank(unionReimburse.getActivityName())) {
return unionReimburse.getActivityName();
}
if (StrUtil.isNotBlank(unionReimburse.getCondolenceUserName())) {
return getReimburseProjectName(unionReimburse.getReimburseProject()) + "-" + unionReimburse.getCondolenceUserName();
}
return StrUtil.blankToDefault(unionReimburse.getDocumentNo(), getReimburseProjectName(unionReimburse.getReimburseProject()));
}
private String buildUseDetailTime(UnionReimburse unionReimburse) {
if (unionReimburse.getActivityTime() != null) {
return DateUtil.formatDate(unionReimburse.getActivityTime());
}
if (unionReimburse.getCondolenceTime() != null) {
return DateUtil.formatDate(unionReimburse.getCondolenceTime());
}
if (unionReimburse.getCreateTime() != null) {
return DateUtil.formatDate(unionReimburse.getCreateTime());
}
return "";
}
private String getReimburseProjectName(String reimburseProject) {
if ("UNION_REIMBURSE_PROJECT_1".equals(reimburseProject)) {
return "慰问申请";
}
if ("UNION_REIMBURSE_PROJECT_2".equals(reimburseProject)) {
return "文体活动申请";
}
if ("UNION_REIMBURSE_PROJECT_3".equals(reimburseProject)) {
return "日常活动申请";
}
if ("UNION_REIMBURSE_PROJECT_4".equals(reimburseProject)) {
return "专项活动申请";
}
return "报销申请";
}
private Double formatMoney(BigDecimal money) {
return money == null ? 0D : money.setScale(2, RoundingMode.HALF_UP).doubleValue();
}
private List<String> getCurrentUserClubIds() {
if (isAdmin()) {
return new ArrayList<>();
}
List<ClubUser> clubUsers = dao().query(ClubUser.class, Cnd.where("userId", "=", SecurityUtil.getUserId()));
return clubUsers.stream()
.map(ClubUser::getClubId)
.filter(StrUtil::isNotBlank)
.distinct()
.collect(Collectors.toList());
}
private Result validateInvoiceDuplicate(UnionReimburse unionReimburse) {
Map<String, List<Integer>> currentInvoiceMap = new LinkedHashMap<>();
List<UnionReimburseInvoiceDetail> details = unionReimburse.getInvoiceDetails();
@@ -84,6 +84,9 @@ public class DifficultHelpApplyController {
public Result getIsCanPlay() {
//获取申请次数,不想再写一个接口, are you ok? .and("zt", "=", 600)
int applyCount = dao.count(DifficultHelpInfo.class, Cnd.where("proxyUserId", "=", SecurityUtil.getUserId()));
// 页面初始化时需要先判断当前登录人本年度是否已经申请过,避免重复进入新增申请。
boolean hasCurrentYearApply = dao.count(DifficultHelpInfo.class, Cnd.where("userId", "=", SecurityUtil.getUserId())
.and("YEAR(applyTime)", "=", DateUtil.getYear())) > 0;
Sys_config startConfig = dao.fetch(Sys_config.class, Cnd.where("configKey", "=", "DifficultyApplyStartTime"));
Sys_config endConfig = dao.fetch(Sys_config.class, Cnd.where("configKey", "=", "DifficultyApplyEndTime"));
if(startConfig != null && endConfig != null) {
@@ -98,9 +101,9 @@ public class DifficultHelpApplyController {
int endResult = cn.hutool.core.date.DateUtil.compare(cn.hutool.core.date.DateUtil.parse(today), cn.hutool.core.date.DateUtil.parse(end));
String time = startConfig.getConfigValue().replace("-", "") + "日-" + endConfig.getConfigValue().replace("-", "") + "";
return Result.success(Map.of("applyCount", applyCount,"time", time, "result", startResult >=0 && endResult <= 0));
return Result.success(Map.of("applyCount", applyCount,"time", time, "result", startResult >=0 && endResult <= 0, "hasCurrentYearApply", hasCurrentYearApply));
} else {
return Result.success(Map.of("applyCount", applyCount,"time", "", "result", false));
return Result.success(Map.of("applyCount", applyCount,"time", "", "result", false, "hasCurrentYearApply", hasCurrentYearApply));
}
}
@@ -110,6 +113,10 @@ public class DifficultHelpApplyController {
@SLog(tag = "困难补助申请", msg = "保存申请,填写人: ${args[0].proxyUserName}")
public Result save(@Param("data") DifficultHelpInfo difficultHelpInfo) {
difficultHelpInfo.setApplyTime(ObjectUtil.defaultIfNull(difficultHelpInfo.getApplyTime(), new Date()));
difficultHelpCommonService.refreshApplyCount(difficultHelpInfo);
if (difficultHelpCommonService.hasAppliedInYear(difficultHelpInfo.getUserId(), difficultHelpInfo.getApplyTime(), difficultHelpInfo.getId())) {
return Result.error("该人员本年度已申请困难帮扶,不能重复申请");
}
dao.insertOrUpdate(difficultHelpInfo);
return Result.success();
}
@@ -122,6 +129,10 @@ public class DifficultHelpApplyController {
@SLog(tag = "困难补助申请", msg = "提交申请,填写人: ${args[0].proxyUserName}")
public Result submit(@Param("data") DifficultHelpInfo difficultHelpInfo){
difficultHelpInfo.setApplyTime(new Date());
difficultHelpCommonService.refreshApplyCount(difficultHelpInfo);
if (difficultHelpCommonService.hasAppliedInYear(difficultHelpInfo.getUserId(), difficultHelpInfo.getApplyTime(), difficultHelpInfo.getId())) {
return Result.error("该人员本年度已申请困难帮扶,不能重复申请");
}
dao.insertOrUpdate(difficultHelpInfo);
// 开启流程实例
@@ -146,6 +157,10 @@ public class DifficultHelpApplyController {
@SLog(tag = "困难补助申请", msg = "重新提交申请,填写人: ${args[0].proxyUserName}")
public Result submitAgain(@Param("data") DifficultHelpInfo difficultHelpInfo, @Param("taskId") Long taskId) {
difficultHelpInfo.setApplyTime(ObjectUtil.defaultIfNull(difficultHelpInfo.getApplyTime(), new Date()));
difficultHelpCommonService.refreshApplyCount(difficultHelpInfo);
if (difficultHelpCommonService.hasAppliedInYear(difficultHelpInfo.getUserId(), difficultHelpInfo.getApplyTime(), difficultHelpInfo.getId())) {
return Result.error("该人员本年度已申请困难帮扶,不能重复申请");
}
dao.insertOrUpdate(difficultHelpInfo);
Dict dict = Dict.create();
@@ -7,6 +7,7 @@ import com.budwk.app.zhgh.staffbenefit.medicalMutualAid.aidFund.param.AidFundPag
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.upload.TempFile;
import java.util.Date;
import java.util.List;
/**
@@ -26,4 +27,21 @@ public interface DifficultHelpCommonService extends BaseService<DifficultHelpInf
NutMap handlingMoneyImport(TempFile file, Boolean isFlag);
List<NutMap> getYearPayList(DifficultHelpPageParam pageForm);
/**
* 校验同一受补助人同一年是否已存在申请记录。
*
* @param userId 受补助人id
* @param applyTime 申请时间
* @param excludeRecordId 排除的当前记录id,编辑/重新提交时使用
* @return true 已存在同年申请记录
*/
boolean hasAppliedInYear(String userId, Date applyTime, String excludeRecordId);
/**
* 新申请时按历史总申请次数重新计算申请次数字段,已有记录则保留原值。
*
* @param difficultHelpInfo 申请信息
*/
void refreshApplyCount(DifficultHelpInfo difficultHelpInfo);
}
@@ -50,6 +50,38 @@ public class DifficultHelpCommonServiceImpl extends BaseServiceImpl<DifficultHel
@Inject
private ManyAddOrRenewUtil manyAddOrRenewUtil;
@Override
public boolean hasAppliedInYear(String userId, Date applyTime, String excludeRecordId) {
if (StrUtil.isBlank(userId) || applyTime == null) {
return false;
}
Cnd cnd = Cnd.where("userId", "=", userId);
cnd.and("YEAR(applyTime)", "=", DateUtil.year(applyTime));
if (StrUtil.isNotBlank(excludeRecordId)) {
cnd.and("id", "<>", excludeRecordId);
}
// 按受补助人和申请年份校验,确保同一个人每年只能保留一条申请记录。
return dao().count(DifficultHelpInfo.class, cnd) > 0;
}
@Override
public void refreshApplyCount(DifficultHelpInfo difficultHelpInfo) {
if (difficultHelpInfo == null || StrUtil.isBlank(difficultHelpInfo.getUserId())) {
return;
}
if (StrUtil.isNotBlank(difficultHelpInfo.getId())) {
DifficultHelpInfo dbInfo = dao().fetch(DifficultHelpInfo.class, difficultHelpInfo.getId());
if (dbInfo != null) {
// 已存在的申请记录沿用原申请次数,避免编辑或重新提交时重复累加。
difficultHelpInfo.setApplyCount(dbInfo.getApplyCount());
return;
}
}
int historyApplyCount = dao().count(DifficultHelpInfo.class, Cnd.where("userId", "=", difficultHelpInfo.getUserId()));
// 新申请记录按历史总申请次数 + 1 重新计算申请次数,不使用前端传入值。
difficultHelpInfo.setApplyCount(historyApplyCount + 1);
}
@Override
public List<NutMap> getYearPayList(DifficultHelpPageParam pageForm) {
// 1. 生成年份列表