Browse Source

fix:修改问题

master
wang 1 month ago
parent
commit
8a998f7eb0
  1. 16
      yun-admin/src/main/java/net/lab1024/sa/admin/module/cost/controller/FirmReportsController.java
  2. 11
      yun-admin/src/main/java/net/lab1024/sa/admin/module/cost/dao/FirmReportsDao.java
  3. 116
      yun-admin/src/main/java/net/lab1024/sa/admin/module/cost/service/FirmReportsService.java
  4. 11
      yun-admin/src/main/java/net/lab1024/sa/admin/module/service/dao/ServiceApplicationsDao.java
  5. 8
      yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/ServiceApplicationsQueryForm.java
  6. 3
      yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/ServiceLawyerImportForm.java
  7. 197
      yun-admin/src/main/java/net/lab1024/sa/admin/module/service/service/ServiceApplicationsService.java
  8. 4
      yun-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java
  9. 4
      yun-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/RequestEmployee.java
  10. 20
      yun-admin/src/main/resources/mapper/cost/FirmReportsMapper.xml
  11. 91
      yun-admin/src/main/resources/mapper/service/ServiceApplicationsMapper.xml

16
yun-admin/src/main/java/net/lab1024/sa/admin/module/cost/controller/FirmReportsController.java

@ -3,6 +3,7 @@ package net.lab1024.sa.admin.module.cost.controller;
import net.lab1024.sa.admin.module.cost.domain.form.FirmReportsAddForm;
import net.lab1024.sa.admin.module.cost.domain.form.FirmReportsQueryForm;
import net.lab1024.sa.admin.module.cost.domain.form.FirmReportsUpdateForm;
import net.lab1024.sa.admin.module.cost.domain.form.FirmReportsBatchCreateForm;
import net.lab1024.sa.admin.module.cost.domain.vo.FirmReportsCountVO;
import net.lab1024.sa.admin.module.cost.domain.vo.FirmReportsVO;
import net.lab1024.sa.admin.module.cost.service.FirmReportsService;
@ -19,6 +20,7 @@ import javax.annotation.Resource;
import javax.validation.Valid;
import java.time.LocalDate;
import java.time.Month;
import java.util.Map;
/**
* 律师事务所年度经营报表 Controller
@ -89,6 +91,20 @@ public class FirmReportsController {
return firmReportsService.commit(idList);
}
//提交前预检查
@Operation(summary = "提交前预检查 @author wzh")
@PostMapping("/firmReports/preCommitCheck")
public ResponseDTO<Map<String, Object>> preCommitCheck(@RequestBody ValidateList<Integer> idList) {
return firmReportsService.preCommitCheck(idList);
}
//批量创建缺失季度记录
@Operation(summary = "批量创建缺失季度记录 @author wzh")
@PostMapping("/firmReports/batchCreateMissing")
public ResponseDTO<String> batchCreateMissing(@RequestBody @Valid FirmReportsBatchCreateForm form) {
return firmReportsService.batchCreateMissing(form.getFirmId(), form.getYear(), form.getQuarters());
}
//驳回
@Operation(summary = "驳回 @author wzh")
@PostMapping("/firmReports/reject")

11
yun-admin/src/main/java/net/lab1024/sa/admin/module/cost/dao/FirmReportsDao.java

@ -81,4 +81,15 @@ public interface FirmReportsDao extends BaseMapper<FirmReportsEntity> {
List<FirmReportsEntity> selectByFirmIdYearAndQuarter(@Param("firmId") Integer firmId,
@Param("year") Integer year,
@Param("quarter") String quarter);
/**
* 查询当前季度之前尚未提交的季度列表支持跨年
* @param firmId 律所ID
* @param year 年份
* @param currentQuarter 当前季度
* @return 未提交的季度描述列表["2025年第1季度", "2025年第2季度"]
*/
List<String> findUnsubmittedEarlierQuarters(@Param("firmId") Integer firmId,
@Param("year") Integer year,
@Param("currentQuarter") Integer currentQuarter);
}

116
yun-admin/src/main/java/net/lab1024/sa/admin/module/cost/service/FirmReportsService.java

@ -1,7 +1,11 @@
package net.lab1024.sa.admin.module.cost.service;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.lab1024.sa.admin.common.enums.ReviewEnum;
import net.lab1024.sa.admin.module.cost.dao.FirmReportsDao;
@ -18,6 +22,7 @@ import net.lab1024.sa.admin.module.system.role.service.RoleEmployeeService;
import net.lab1024.sa.admin.util.AdminRequestUtil;
import net.lab1024.sa.admin.util.DateTimeUtil;
import net.lab1024.sa.base.common.code.UnexpectedErrorCode;
import net.lab1024.sa.base.common.code.UserErrorCode;
import net.lab1024.sa.base.common.domain.ValidateList;
import net.lab1024.sa.base.common.enumeration.UserTypeEnum;
import net.lab1024.sa.base.common.util.SmartBeanUtil;
@ -57,12 +62,14 @@ public class FirmReportsService {
Page<?> page = SmartPageUtil.convert2PageQuery(queryForm);
RequestEmployee requestUser = AdminRequestUtil.getRequestUser();
if (!hasCostPermission(requestUser)) {
return SmartPageUtil.convert2PageResult(page, Collections.emptyList());
}
List<RoleVO> roleIdList = roleEmployeeService.getRoleIdList(requestUser.getEmployeeId());
String roleCode = AdminRequestUtil.getRoleCode(roleIdList);
if (!UserTypeEnum.Admin.getDesc().equals(roleCode)) {
if (AdminRequestUtil.isAssociationRole(roleIdList)) {
queryForm.setUserId(requestUser.getEmployeeId());
queryForm.setIncludeSubmitted(true);
} else if (AdminRequestUtil.isFirmRole(roleIdList)) {
queryForm.setFirmId(Math.toIntExact(requestUser.getDepartmentId()));
@ -94,6 +101,9 @@ public class FirmReportsService {
* 添加
*/
public ResponseDTO<String> add(FirmReportsAddForm addForm) {
if (!hasCostPermission(AdminRequestUtil.getRequestUser())) {
return ResponseDTO.error(UserErrorCode.NO_PERMISSION);
}
// 使用季度检查重复数据
FirmReportsEntity existing = firmReportsDao.selectList(addForm.getDeclareQuarter(), addForm.getDeclareYear(), addForm.getFirmId());
if (existing != null ) {
@ -114,6 +124,9 @@ public class FirmReportsService {
*
*/
public ResponseDTO<String> update(FirmReportsUpdateForm updateForm) {
if (!hasCostPermission(AdminRequestUtil.getRequestUser())) {
return ResponseDTO.error(UserErrorCode.NO_PERMISSION);
}
// 检查记录是否存在
FirmReportsEntity currentEntity = firmReportsDao.selectById(updateForm.getId());
if (currentEntity == null) {
@ -140,6 +153,9 @@ public class FirmReportsService {
* 批量删除
*/
public ResponseDTO<String> batchDelete(List<Integer> idList) {
if (!hasCostPermission(AdminRequestUtil.getRequestUser())) {
return ResponseDTO.error(UserErrorCode.NO_PERMISSION);
}
if (CollectionUtils.isEmpty(idList)){
return ResponseDTO.ok();
}
@ -160,6 +176,9 @@ public class FirmReportsService {
* 单个删除
*/
public ResponseDTO<String> delete(Integer id) {
if (!hasCostPermission(AdminRequestUtil.getRequestUser())) {
return ResponseDTO.error(UserErrorCode.NO_PERMISSION);
}
if (null == id){
return ResponseDTO.ok();
}
@ -175,6 +194,9 @@ public class FirmReportsService {
}
public ResponseDTO<String> commit(ValidateList<Integer> idList) {
if (!hasCostPermission(AdminRequestUtil.getRequestUser())) {
return ResponseDTO.error(UserErrorCode.NO_PERMISSION);
}
if (CollectionUtils.isEmpty(idList)) {
return ResponseDTO.ok();
}
@ -189,16 +211,92 @@ public class FirmReportsService {
if (entity.getApprovalStatus() != null && (entity.getApprovalStatus() == 3 || entity.getApprovalStatus() == 4)) {
return ResponseDTO.userErrorParam("记录已审批,不能重复提交");
}
// 校验:提交当前季度前,必须已提交前面所有季度的数据(支持跨年)
Integer firmId = entity.getFirmId();
Integer year = entity.getDeclareYear();
Integer currentQuarter = Integer.valueOf(entity.getDeclareQuarter());
List<String> unsubmittedQuarters = firmReportsDao.findUnsubmittedEarlierQuarters(firmId, year, currentQuarter);
if (unsubmittedQuarters != null && !unsubmittedQuarters.isEmpty()) {
String quarterNames = String.join("、", unsubmittedQuarters);
return ResponseDTO.userErrorParam(
"请先提交" + quarterNames + "的成本报表后,再提交" + year + "年第" + currentQuarter + "季度");
}
}
firmReportsDao.commit(idList);
return ResponseDTO.ok();
}
/**
* 提交前预检查返回缺失的前置季度列表
*/
public ResponseDTO<Map<String, Object>> preCommitCheck(ValidateList<Integer> idList) {
if (CollectionUtils.isEmpty(idList)) {
return ResponseDTO.ok(Map.of("hasMissing", false));
}
for (Integer id : idList) {
FirmReportsEntity entity = firmReportsDao.selectById(id);
if (entity == null) {
continue;
}
Integer firmId = entity.getFirmId();
Integer year = entity.getDeclareYear();
Integer currentQuarter = Integer.valueOf(entity.getDeclareQuarter());
List<String> unsubmittedQuarters = firmReportsDao.findUnsubmittedEarlierQuarters(firmId, year, currentQuarter);
if (unsubmittedQuarters != null && !unsubmittedQuarters.isEmpty()) {
Map<String, Object> result = new HashMap<>();
result.put("hasMissing", true);
result.put("missingQuarters", unsubmittedQuarters);
result.put("firmId", firmId);
result.put("year", year);
result.put("currentQuarter", currentQuarter);
return ResponseDTO.ok(result);
}
}
return ResponseDTO.ok(Map.of("hasMissing", false));
}
/**
* 批量创建缺失季度记录空白报表
*/
public ResponseDTO<String> batchCreateMissing(Integer firmId, Integer year, List<Integer> quarters) {
if (firmId == null || year == null || quarters == null || quarters.isEmpty()) {
return ResponseDTO.userErrorParam("参数不能为空");
}
RequestEmployee requestUser = AdminRequestUtil.getRequestUser();
for (Integer quarter : quarters) {
FirmReportsEntity entity = new FirmReportsEntity();
entity.setFirmId(firmId);
entity.setDeclareYear(year);
entity.setDeclareQuarter(String.valueOf(quarter));
entity.setUserId(requestUser.getEmployeeId());
entity.setApprovalStatus(0);
entity.setDelFlag(0);
entity.setRevenue(BigDecimal.ZERO);
entity.setTotalCost(BigDecimal.ZERO);
entity.setPublicWelfareCost(BigDecimal.ZERO);
entity.setCostIncomeRatio(BigDecimal.ZERO);
entity.setActualPublicWelfareCost(BigDecimal.ZERO);
entity.setActualCostIncomeRatio(BigDecimal.ZERO);
firmReportsDao.insert(entity);
}
return ResponseDTO.ok();
}
/**
* 驳回将已提交的数据驳回为未提交状态
*/
public ResponseDTO<String> reject(ValidateList<Integer> idList) {
if (!hasCostPermission(AdminRequestUtil.getRequestUser())) {
return ResponseDTO.error(UserErrorCode.NO_PERMISSION);
}
if (CollectionUtils.isEmpty(idList)) {
return ResponseDTO.ok();
}
@ -224,6 +322,9 @@ public class FirmReportsService {
*/
public ResponseDTO<Boolean> query(Integer quarter, Integer Year) {
RequestEmployee requestUser = AdminRequestUtil.getRequestUser();
if (!hasCostPermission(requestUser)) {
return ResponseDTO.ok(false);
}
List<RoleVO> roleIdList = roleEmployeeService.getRoleIdList(requestUser.getEmployeeId());
// 只有律所主任或行政可以填报
@ -237,6 +338,12 @@ public class FirmReportsService {
public FirmReportsCountVO income(Integer year) {
// 获取当前用户
RequestEmployee requestUser = AdminRequestUtil.getRequestUser();
if (!hasCostPermission(requestUser)) {
FirmReportsCountVO empty = new FirmReportsCountVO();
empty.setRevenue(BigDecimal.ZERO);
empty.setTotalCost(BigDecimal.ZERO);
return empty;
}
if (year == null) {
year = DateTimeUtil.getCurrentYear();
}
@ -246,9 +353,16 @@ public class FirmReportsService {
public Long firmReportsCost(Integer year) {
// 获取当前用户
RequestEmployee requestUser = AdminRequestUtil.getRequestUser();
if (!hasCostPermission(requestUser)) {
return 0L;
}
if (year == null) {
year = DateTimeUtil.getCurrentYear();
}
return firmReportsDao.firmReportsCost(requestUser.getDepartmentId(), year);
}
private boolean hasCostPermission(RequestEmployee requestUser) {
return requestUser != null && Boolean.TRUE.equals(requestUser.getCostVisibleFlag());
}
}

11
yun-admin/src/main/java/net/lab1024/sa/admin/module/service/dao/ServiceApplicationsDao.java

@ -42,6 +42,11 @@ public interface ServiceApplicationsDao extends BaseMapper<ServiceApplicationsEn
void batchSubmit(@Param("idList")List<Long> idList, @Param("deletedFlag")Integer b);
/**
* 标记为律师已提交首次提交补提交时间后续提交不覆盖第一次提交时间
*/
void markSubmitted(@Param("applicationId")Long applicationId, @Param("firmAuditStatus")Integer firmAuditStatus);
/**
* 批量提交律所审核
*/
@ -214,6 +219,12 @@ public interface ServiceApplicationsDao extends BaseMapper<ServiceApplicationsEn
*/
Long queryNoReviewWithCostFilter();
/**
* 查询无成本查看权限律所的未审核数据数量
* @return 未审核数据数量
*/
Long queryNoReviewWithoutCostFilter();
/**
* 判断律所是否有成本查看权限
*/

8
yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/ServiceApplicationsQueryForm.java

@ -99,6 +99,8 @@ public class ServiceApplicationsQueryForm extends PageParam {
* 律所审核时间
*/
private LocalDateTime firmAuditTime;
private String firmAuditTimeStart;
private String firmAuditTimeEnd;
/**
* 协会审核状态0-待审核1-通过2-退回
@ -119,6 +121,8 @@ public class ServiceApplicationsQueryForm extends PageParam {
* 协会审核时间
*/
private LocalDateTime associationAuditTime;
private String associationAuditTimeStart;
private String associationAuditTimeEnd;
/**
* 备案编号
@ -191,7 +195,7 @@ public class ServiceApplicationsQueryForm extends PageParam {
private String endTime;
/**
* 是否只查询成本填报律所的数据
* 审批数据查看范围null/0=不限制1=只查看有成本权限的律所数据2=只查看无成本权限的律所数据
*/
private Boolean costReportViewOnly;
private Integer costReportViewOnly;
}

3
yun-admin/src/main/java/net/lab1024/sa/admin/module/service/domain/form/ServiceLawyerImportForm.java

@ -20,6 +20,9 @@ public class ServiceLawyerImportForm {
@ExcelIgnore
private Long userId;
@ExcelProperty("律所名称")
private String firmName;
@ExcelProperty("执业律师")
private String lawyerName;

197
yun-admin/src/main/java/net/lab1024/sa/admin/module/service/service/ServiceApplicationsService.java

@ -11,6 +11,7 @@ import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
@ -197,10 +198,11 @@ public class ServiceApplicationsService {
// 协会用户(CEO):可以看到所有律所提交的数据,但只显示associationAuditStatus为待审核(1)、通过(3)和拒绝(4)的数据和自己创建的数据
// CEO作为最高权限用户,不需要限制在特定部门范围内,直接设置includeAssociationReviewed即可
queryForm.setIncludeAssociationReviewed(true);
// 检查是否只能查看成本填报律所的数据
// 检查审批数据查看范围(1=只看有成本的律所,2=只看无成本的律所)
RequestEmployee requestEmployee = (RequestEmployee) requestUser;
if (Boolean.TRUE.equals(requestEmployee.getCostReportViewOnly())) {
queryForm.setCostReportViewOnly(true);
Integer costReportViewOnly = requestEmployee.getCostReportViewOnly();
if (costReportViewOnly != null && (costReportViewOnly == 1 || costReportViewOnly == 2)) {
queryForm.setCostReportViewOnly(costReportViewOnly);
}
} else if (isFirmRole) {
// 律所主任或行政:能看到自己部门范围内的数据,但只显示firmAuditStatus为待审核、通过和拒绝的数据和自己创建的数据
@ -242,6 +244,8 @@ public class ServiceApplicationsService {
queryForm.setEmployeeIdList(longs);
// 普通用户不需要审核状态过滤,可以看到自己所有状态的数据
queryForm.setNoStatusFilter(true);
// 普通用户只看自己的数据
queryForm.setUserId(requestUser.getUserId());
}
queryForm.setCurrentUserId(requestUser.getUserId()); // 传递当前用户ID用于SQL中的特殊过滤
}
@ -278,64 +282,17 @@ public class ServiceApplicationsService {
public PageResult<ServiceApplicationsVO> queryPageReport(@Valid ServiceApplicationsQueryForm queryForm) {
List<Long> longs = new ArrayList<>();
Page<?> page = SmartPageUtil.convert2PageQuery(queryForm);
//根据用户角色的查询数据范围来查询数据
RequestEmployee requestUser = AdminRequestUtil.getRequestUser();
List<RoleVO> roleIdList = roleEmployeeService.getRoleIdList(requestUser.getUserId());
String roleCode = AdminRequestUtil.getRoleCode(roleIdList);
// 检查角色类型
boolean isAssociationRole = AdminRequestUtil.isAssociationRole(roleIdList);
boolean isFirmRole = AdminRequestUtil.isFirmRole(roleIdList); // 律所主任或行政
// 服务申报页:非超管仅查看本人创建的数据(含草稿);审批范围逻辑见 queryPage
if (!UserTypeEnum.Admin.getDesc().equals(roleCode)) {
if (isAssociationRole) {
// 协会用户(CEO):可以看到所有律所提交的数据,但只显示associationAuditStatus为待审核(1)、通过(3)和拒绝(4)的数据和自己创建的数据
queryForm.setIncludeAssociationReviewed(true);
} else if (isFirmRole) {
// 律所主任或行政:能看到自己部门范围内的数据,但只显示firmAuditStatus为待审核、通过和拒绝的数据和自己创建的数据
Integer oneByRoleId = dataScopeViewService.getOneByRoleId(roleIdList.get(0).getRoleId());
// 获取自己部门范围内的数据
List<Long> departmentEmployees = new ArrayList<>();
if (DataScopeViewTypeEnum.ME.getValue().equals(oneByRoleId)) {
departmentEmployees = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.ME, requestUser.getUserId());
} else if (DataScopeViewTypeEnum.DEPARTMENT.getValue().equals(oneByRoleId)) {
departmentEmployees = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.DEPARTMENT, requestUser.getUserId());
}
// 确保包含当前用户ID,以便能看到自己创建的数据
if (departmentEmployees == null) {
departmentEmployees = new ArrayList<>();
}
if (!departmentEmployees.contains(requestUser.getUserId())) {
departmentEmployees.add(requestUser.getUserId());
}
queryForm.setEmployeeIdList(departmentEmployees);
// 律所主任或行政可以查看部门内所有已审核数据以及自己创建的有效数据(明确排除未提交的草稿)
queryForm.setIncludeFirmReviewed(true);
} else {
// 律所普通用户:只能看到自己提交的数据,包括所有firmAuditStatus状态
Integer oneByRoleId = dataScopeViewService.getOneByRoleId(roleIdList.get(0).getRoleId());
if (DataScopeViewTypeEnum.ME.getValue().equals(oneByRoleId)) {
longs = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.ME, requestUser.getUserId());
} else if (DataScopeViewTypeEnum.DEPARTMENT.getValue().equals(oneByRoleId)) {
longs = dataScopeViewService.getCanViewEmployeeId(DataScopeViewTypeEnum.DEPARTMENT, requestUser.getUserId());
}
// 确保普通用户至少能看到自己的数据
if (longs == null) {
longs = new ArrayList<>();
}
if (!longs.contains(requestUser.getUserId())) {
longs.add(requestUser.getUserId());
}
queryForm.setEmployeeIdList(longs);
// 普通用户不需要审核状态过滤,可以看到自己所有状态的数据
queryForm.setUserId(requestUser.getUserId());
queryForm.setNoStatusFilter(true);
}
queryForm.setCurrentUserId(requestUser.getUserId());
}
queryForm.setUserId(requestUser.getUserId());
List<ServiceApplicationsVO> list = serviceApplicationsDao.queryPage(page, queryForm);
if (!CollectionUtils.isEmpty(list)) {
//翻译单位名称和用户名称
@ -480,7 +437,7 @@ public class ServiceApplicationsService {
}
} else {
// 律所审核完成:发给律师(个人)
title = "你的服务申报「" + serviceBrief + "」律所通过";
title = "你的服务申报「" + serviceBrief + "」律所" + statusText;
}
net.lab1024.sa.base.module.support.message.domain.MessageSendForm sendForm = new net.lab1024.sa.base.module.support.message.domain.MessageSendForm();
@ -579,13 +536,18 @@ public class ServiceApplicationsService {
serviceApplications.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue());
serviceApplications.setReportTime(LocalDateTime.now());
serviceApplicationsDao.insert(serviceApplications);
serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), ReviewEnum.APPROVAL.getValue());
}else {
// 编辑提交(二次提交/驳回后重新提交)
ServiceApplicationsEntity serviceApplications = serviceApplicationsDao.selectById(addForm.getApplicationId());
SmartBeanUtil.copyProperties(addForm, serviceApplications);
serviceApplications.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue());
// 二次提交时保持原有的提交时间不变,不修改 reportTime
// 首次从草稿/已有记录提交时补提交时间;二次提交保持原有提交时间不变。
if (serviceApplications.getReportTime() == null) {
serviceApplications.setReportTime(LocalDateTime.now());
}
serviceApplicationsDao.updateById(serviceApplications);
serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), ReviewEnum.APPROVAL.getValue());
}
return ResponseDTO.ok();
}
@ -818,13 +780,22 @@ public class ServiceApplicationsService {
return ResponseDTO.error(UserErrorCode.NO_PERMISSION);
}
Long targetFirmId = null;
LocalDateTime firstReportTime = null;
// 查询这些记录的详细信息,进行权限和状态校验
for (Long id : idList) {
ServiceApplicationsVO record = serviceApplicationsDao.queryById(id);
ServiceApplicationsEntity record = serviceApplicationsDao.selectById(id);
if (record == null) {
return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST, "记录ID:" + id + "不存在");
}
// 记录律所ID和上报时间(用于后续成本校验)
if (targetFirmId == null) {
targetFirmId = record.getFirmId();
firstReportTime = record.getReportTime();
}
// 校验1:只能上报本所的数据
if (!record.getFirmId().equals(requestUser.getDepartmentId())) {
return ResponseDTO.error(UserErrorCode.NO_PERMISSION, "只能上报本所的数据");
@ -843,6 +814,20 @@ public class ServiceApplicationsService {
}
}
// 校验4:仅对有成本查看权限的用户(参与成本核算的律所)检查前置季度成本是否已提交
if (Boolean.TRUE.equals(requestUser.getCostVisibleFlag()) && targetFirmId != null && firstReportTime != null) {
int reportYear = firstReportTime.getYear();
int reportMonth = firstReportTime.getMonthValue();
int reportQuarter = (reportMonth - 1) / 3 + 1;
List<String> unsubmittedQuarters = firmReportsDao.findUnsubmittedEarlierQuarters(targetFirmId.intValue(), reportYear, reportQuarter);
if (unsubmittedQuarters != null && !unsubmittedQuarters.isEmpty()) {
String quarterNames = String.join("、", unsubmittedQuarters);
return ResponseDTO.userErrorParam(
"请先提交" + quarterNames + "的成本报表后,再批量上报服务数据");
}
}
serviceApplicationsDao.batchSubmitAsAssociation(idList, ReviewEnum.APPROVAL.getValue());
return ResponseDTO.ok();
@ -883,6 +868,7 @@ public class ServiceApplicationsService {
serviceApplications.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue());
serviceApplications.setReportTime(LocalDateTime.now());
serviceApplicationsDao.insert(serviceApplications);
serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), ReviewEnum.APPROVAL.getValue());
}else {
//判断活动类型查询案号有没有存在
if("TIME".equals(addForm.getServiceType())) {
@ -903,8 +889,11 @@ public class ServiceApplicationsService {
ServiceApplicationsEntity serviceApplications = serviceApplicationsDao.selectById(addForm.getApplicationId());
SmartBeanUtil.copyProperties(addForm, serviceApplications);
serviceApplications.setFirmAuditStatus(ReviewEnum.APPROVAL.getValue());
if (serviceApplications.getReportTime() == null) {
serviceApplications.setReportTime(LocalDateTime.now());
}
serviceApplicationsDao.updateById(serviceApplications);
serviceApplicationsDao.markSubmitted(serviceApplications.getApplicationId(), ReviewEnum.APPROVAL.getValue());
}
return ResponseDTO.ok();
@ -1038,29 +1027,11 @@ public class ServiceApplicationsService {
}
// ============================================================
// 根据上报时间确定成本归属的年份和季度
// 根据上报时间确定成本归属的年份和季度(直接对应自然账期)
// ============================================================
int reportMonth = reportTime.getMonthValue();
int costYear;
int costQuarter;
if (reportMonth >= 1 && reportMonth <= 3) {
// 1-3月上报 → 上年 Q4
costYear = reportTime.getYear() - 1;
costQuarter = 4;
} else if (reportMonth >= 4 && reportMonth <= 6) {
// 4-6月上报 → 当年 Q1
costYear = reportTime.getYear();
costQuarter = 1;
} else if (reportMonth >= 7 && reportMonth <= 9) {
// 7-9月上报 → 当年 Q2
costYear = reportTime.getYear();
costQuarter = 2;
} else {
// 10-12月上报 → 当年 Q3
costYear = reportTime.getYear();
costQuarter = 3;
}
int costYear = reportTime.getYear();
int costQuarter = (reportMonth - 1) / 3 + 1;
log.info("更新成本:firmId={}, reportTime={}, reportMonth={}, 成本归属年份={}, 成本归属季度=Q{}",
firmId, reportTime, reportMonth, costYear, costQuarter);
@ -1876,8 +1847,8 @@ public class ServiceApplicationsService {
try {
ServiceApplicationsEntity entity = serviceApplicationsDao.selectById(Long.valueOf(applicationId));
if (entity != null) {
// 律协审核通过时,更新成本管理表中的实际公益成本和比例
if (isAssociationReview && ReviewEnum.PASS.getValue().equals(auditResult)) {
// 律协批量通过/拒绝都要重算,保证驳回后实际成本能扣回。
if (isAssociationReview && isCostAffectingAssociationAudit(auditResult)) {
updateActualCostInFirmReports(entity);
}
// 发送通知
@ -1908,6 +1879,20 @@ public class ServiceApplicationsService {
* @return 成本万元
*/
public BigDecimal getServiceApplicationsCost(ServiceLawyerQueryForm queryForm) {
if (queryForm == null) {
return BigDecimal.ZERO;
}
RequestEmployee requestUser = AdminRequestUtil.getRequestUser();
if (requestUser == null || !Boolean.TRUE.equals(requestUser.getCostVisibleFlag())) {
return BigDecimal.ZERO;
}
List<RoleVO> roles = roleEmployeeService.getRoleIdList(requestUser.getEmployeeId());
boolean isAssociationOrAdmin = AdminRequestUtil.isAssociationRole(roles)
|| UserTypeEnum.Admin.getDesc().equals(AdminRequestUtil.getRoleCode(roles));
if (!isAssociationOrAdmin) {
queryForm.setFirmId(requestUser.getDepartmentId());
}
Long firmId = queryForm.getFirmId();
int year = queryForm.getYear();
Integer quarter = queryForm.getQuarter();
@ -2003,32 +1988,68 @@ public class ServiceApplicationsService {
* 按部门批量审核仅律协角色可用
* 前端统一传递 auditResult 字段3=通过4=拒绝
*/
@Transactional
public ResponseDTO<String> batchReviewByDepartmentId(@Valid ServiceApplicationsUpdateForm updateForm) {
RequestEmployee requestUser = AdminRequestUtil.getRequestUser();
// 统一从 auditResult 获取审核结果
Integer auditResult = updateForm.getAuditResult();
if (auditResult == null) {
auditResult = updateForm.getAssociationAuditStatus();
}
if (auditResult == null) {
return ResponseDTO.userErrorParam("审核结果不能为空");
}
if (updateForm.getFirmId() == null) {
return ResponseDTO.userErrorParam("律所不能为空");
}
List<ServiceApplicationsEntity> affectedApplications = serviceApplicationsDao.selectList(
new LambdaQueryWrapper<ServiceApplicationsEntity>()
.eq(ServiceApplicationsEntity::getFirmId, updateForm.getFirmId())
.eq(ServiceApplicationsEntity::getAssociationAuditStatus, ReviewEnum.APPROVAL.getValue())
.eq(ServiceApplicationsEntity::getDeletedFlag, 0)
);
String auditOpinion = updateForm.getAuditRemark();
if (auditOpinion == null) {
auditOpinion = updateForm.getAssociationAuditOpinion();
}
updateForm.setAssociationAuditStatus(auditResult);
updateForm.setAssociationAuditUser(requestUser.getEmployeeId());
updateForm.setAssociationAuditTime(LocalDateTime.now());
updateForm.setAssociationAuditOpinion(auditOpinion);
serviceApplicationsDao.batchReviewByDepartmentId(updateForm);
for (ServiceApplicationsEntity entity : affectedApplications) {
if (isCostAffectingAssociationAudit(auditResult)) {
updateActualCostInFirmReports(entity);
}
entity.setAssociationAuditStatus(auditResult);
entity.setAssociationAuditOpinion(auditOpinion);
sendAuditNotification(entity, auditResult, auditOpinion, true);
}
return ResponseDTO.ok();
}
private boolean isCostAffectingAssociationAudit(Integer auditResult) {
return ReviewEnum.PASS.getValue().equals(auditResult) || ReviewEnum.REFUSE.getValue().equals(auditResult);
}
public Long queryNoReview() {
//查询上个月是否有未审核的数据,注意跨年情况
RequestEmployee requestUser = AdminRequestUtil.getRequestUser();
Long departmentId = requestUser.getDepartmentId();
// 检查是否只能查看成本填报律所的数据
Boolean costReportViewOnly = requestUser.getCostReportViewOnly();
if (Boolean.TRUE.equals(costReportViewOnly)) {
// 只统计律所主任或行政有成本查看权限的律所的未审核数据
// 检查审批数据查看范围(1=只看有成本的律所,2=只看无成本的律所)
Integer costReportViewOnly = requestUser.getCostReportViewOnly();
if (costReportViewOnly != null && costReportViewOnly == 1) {
return serviceApplicationsDao.queryNoReviewWithCostFilter();
}
if (costReportViewOnly != null && costReportViewOnly == 2) {
return serviceApplicationsDao.queryNoReviewWithoutCostFilter();
}
return serviceApplicationsDao.queryNoReview(departmentId);
}
@ -2948,10 +2969,11 @@ public class ServiceApplicationsService {
public PageResult<ServiceReportStatisticsVO> getServiceReportStatistics(ServiceApplicationsQueryForm queryForm) {
Page<?> page = SmartPageUtil.convert2PageQuery(queryForm);
// 添加权限控制:检查是否只能查看成本填报律所的数据
// 添加权限控制:检查审批数据查看范围(1=只看有成本的律所,2=只看无成本的律所)
RequestEmployee requestUser = AdminRequestUtil.getRequestUser();
if (Boolean.TRUE.equals(requestUser.getCostReportViewOnly())) {
queryForm.setCostReportViewOnly(true);
Integer costReportViewOnly = requestUser.getCostReportViewOnly();
if (costReportViewOnly != null && (costReportViewOnly == 1 || costReportViewOnly == 2)) {
queryForm.setCostReportViewOnly(costReportViewOnly);
}
// 如果没有指定季度,则使用年度范围,否则使用季度范围
@ -3226,6 +3248,7 @@ public class ServiceApplicationsService {
// 固定列(合并两行)
head.add(Arrays.asList("序号", " "));
head.add(Arrays.asList("律所名称", " "));
head.add(Arrays.asList("律师名称", " "));
// 构建分类表头 - 记录每列的元数据信息(合计列在每个分类的前面)
@ -3261,6 +3284,7 @@ public class ServiceApplicationsService {
for (LawyerActivityCountVO lawyer : lawyerMap.values()) {
List<Object> row = new ArrayList<>();
row.add(++rowIndex); // 序号
row.add(lawyer.getFirmName() != null ? lawyer.getFirmName() : ""); // 律所名称
row.add(lawyer.getLawyerName());
// 按列元数据顺序填充数据
@ -3302,6 +3326,7 @@ public class ServiceApplicationsService {
// 添加合计行
List<Object> totalRow = new ArrayList<>();
totalRow.add("-");
totalRow.add("-");
totalRow.add("合计");
int grandTotal = 0;
@ -3360,7 +3385,7 @@ public class ServiceApplicationsService {
.head(head)
.registerWriteHandler(styleStrategy)
.registerWriteHandler(new SimpleColumnWidthStyleStrategy(12))
.registerWriteHandler(new SubtotalMergeHandler(columnMetaList, 2))
.registerWriteHandler(new SubtotalMergeHandler(columnMetaList, 3))
.registerWriteHandler(new CustomRowHeightHandler((short) 500))
.build();
excelWriter.write(data, writeSheet);

4
yun-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java

@ -106,7 +106,7 @@ public class EmployeeEntity {
private Boolean penaltyFlag;
/**
* 审批数据是否只能查看成本填报律所
* 审批数据查看范围null/0=不限制1=只查看有成本权限的律所数据2=只查看无成本权限的律所数据
*/
private Boolean costReportViewOnly;
private Integer costReportViewOnly;
}

4
yun-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/RequestEmployee.java

@ -73,9 +73,9 @@ public class RequestEmployee implements RequestUser, Serializable {
private Boolean penaltyFlag;
/**
* 审批数据是否只能查看成本填报律所
* 审批数据查看范围null/0=不限制1=只查看有成本权限的律所数据2=只查看无成本权限的律所数据
*/
private Boolean costReportViewOnly;
private Integer costReportViewOnly;
@Override
public Long getUserId() {

20
yun-admin/src/main/resources/mapper/cost/FirmReportsMapper.xml

@ -128,4 +128,24 @@
AND declare_quarter = #{quarter}
</select>
<!-- 查询当前季度之前尚未提交的季度列表 -->
<!-- 规则:Q1不检查;Q2查Q1;Q3查Q1,Q2;Q4查Q1,Q2,Q3 -->
<select id="findUnsubmittedEarlierQuarters" resultType="java.lang.String">
SELECT CONCAT(q.year_val, '年第', q.quarter_num, '季度') AS period_name
FROM (
SELECT #{year} AS year_val, 1 AS quarter_num WHERE #{currentQuarter} &gt; 1
UNION ALL SELECT #{year}, 2 WHERE #{currentQuarter} &gt; 2
UNION ALL SELECT #{year}, 3 WHERE #{currentQuarter} &gt; 3
) q
WHERE NOT EXISTS (
SELECT 1
FROM t_firm_reports fr
WHERE fr.del_flag = 0
AND fr.firm_id = #{firmId}
AND fr.declare_year = q.year_val
AND CAST(fr.declare_quarter AS UNSIGNED) = q.quarter_num
AND fr.approval_status = 3
)
ORDER BY q.year_val, q.quarter_num
</select>
</mapper>

91
yun-admin/src/main/resources/mapper/service/ServiceApplicationsMapper.xml

@ -98,6 +98,18 @@
</otherwise>
</choose>
</if>
<if test="queryForm.firmAuditTimeStart != null and queryForm.firmAuditTimeStart != ''">
and firm_audit_time &gt;= #{queryForm.firmAuditTimeStart}
</if>
<if test="queryForm.firmAuditTimeEnd != null and queryForm.firmAuditTimeEnd != ''">
and firm_audit_time &lt;= #{queryForm.firmAuditTimeEnd}
</if>
<if test="queryForm.associationAuditTimeStart != null and queryForm.associationAuditTimeStart != ''">
and association_audit_time &gt;= #{queryForm.associationAuditTimeStart}
</if>
<if test="queryForm.associationAuditTimeEnd != null and queryForm.associationAuditTimeEnd != ''">
and association_audit_time &lt;= #{queryForm.associationAuditTimeEnd}
</if>
<if test="queryForm.activityNameId != null and queryForm.activityNameId != ''">
and activity_name_id = #{queryForm.activityNameId}
</if>
@ -130,7 +142,7 @@
<!-- 普通律所用户:不过滤firm_audit_status,可以看到所有状态的数据 -->
</if>
<!-- 服务申报律所过滤:只查看律所主任或行政有成本查看权限的律所的数据 -->
<if test="queryForm.costReportViewOnly != null and queryForm.costReportViewOnly">
<if test="queryForm.costReportViewOnly != null and queryForm.costReportViewOnly == 1">
AND t_service_applications.firm_id IN (
SELECT DISTINCT e.department_id
FROM t_employee e
@ -141,6 +153,17 @@
AND e.cost_visible_flag = 1
)
</if>
<if test="queryForm.costReportViewOnly != null and queryForm.costReportViewOnly == 2">
AND t_service_applications.firm_id NOT IN (
SELECT DISTINCT e.department_id
FROM t_employee e
INNER JOIN t_role_employee re ON e.employee_id = re.employee_id
INNER JOIN t_role r ON re.role_id = r.role_id
WHERE (e.deleted_flag = 0 OR e.deleted_flag IS NULL)
AND (r.role_code = 'cto' OR r.role_code = 'staff')
AND e.cost_visible_flag = 1
)
</if>
<!-- 律所管理员过滤条件:查看部门内已审核数据以及自己创建的所有数据(不包括未提交的草稿) -->
<if test="queryForm.includeFirmReviewed != null and queryForm.includeFirmReviewed and (queryForm.firmAuditStatus == null or queryForm.firmAuditStatus == '') and (queryForm.associationAuditStatus == null or queryForm.associationAuditStatus == '')">
AND (
@ -190,19 +213,26 @@
</update>
<update id="batchSubmit">
update t_service_applications set firm_audit_status = #{deletedFlag}, report_time = NOW()
update t_service_applications set firm_audit_status = #{deletedFlag}, report_time = IFNULL(report_time, NOW())
where application_id in
<foreach collection="idList" open="(" close=")" separator="," item="item">
#{item}
</foreach>
</update>
<update id="markSubmitted">
update t_service_applications
set firm_audit_status = #{firmAuditStatus},
report_time = IFNULL(report_time, NOW())
where application_id = #{applicationId}
</update>
<update id="batchSubmitAsFirm">
update t_service_applications set
firm_audit_status = #{firmAuditStatus},
firm_audit_user = #{userId},
firm_audit_time = #{submitTime},
report_time = NOW()
report_time = IFNULL(report_time, NOW())
where application_id in
<foreach collection="idList" open="(" close=")" separator="," item="item">
#{item}
@ -256,7 +286,8 @@
update t_service_applications set
association_audit_status = #{queryForm.associationAuditStatus},
association_audit_user = #{queryForm.associationAuditUser},
association_audit_time = #{queryForm.associationAuditTime}
association_audit_time = #{queryForm.associationAuditTime},
association_audit_opinion = #{queryForm.associationAuditOpinion}
where association_audit_status = 1 and firm_id = #{queryForm.firmId}
</update>
@ -283,6 +314,7 @@
SELECT
e.actual_name AS lawyerName,
e.employee_id as userId,
MAX(d.department_name) AS firmName,
tsa.certificate_number AS certificateNumber,
COALESCE(SUM(tsa.service_duration), 0) AS annualServiceDuration
FROM t_service_applications tsa
@ -542,7 +574,7 @@
LEFT JOIN t_employee e ON e.department_id = d.department_id AND e.deleted_flag = 0
LEFT JOIN t_service_applications tsa ON tsa.user_id = e.employee_id
AND tsa.deleted_flag = 0
AND tsa.association_audit_status IN (1, 2, 3)
AND tsa.association_audit_status IN (1, 2, 3, 4)
<if test="queryForm.firmId != null">
AND tsa.firm_id = #{queryForm.firmId}
</if>
@ -558,7 +590,7 @@
AND d.department_id = #{queryForm.firmId}
</if>
<!-- 成本填报律所过滤:只查看律所主任或行政有成本查看权限的律所的数据 -->
<if test="queryForm.costReportViewOnly != null and queryForm.costReportViewOnly">
<if test="queryForm.costReportViewOnly != null and queryForm.costReportViewOnly == 1">
AND d.department_id IN (
SELECT DISTINCT e2.department_id
FROM t_employee e2
@ -569,6 +601,18 @@
AND e2.cost_visible_flag = 1
)
</if>
<!-- 无成本填报律所过滤:只查看律所主任或行政没有成本查看权限的律所的数据 -->
<if test="queryForm.costReportViewOnly != null and queryForm.costReportViewOnly == 2">
AND d.department_id NOT IN (
SELECT DISTINCT e2.department_id
FROM t_employee e2
INNER JOIN t_role_employee re ON e2.employee_id = re.employee_id
INNER JOIN t_role r ON re.role_id = r.role_id
WHERE (e2.deleted_flag = 0 OR e2.deleted_flag IS NULL)
AND (r.role_code = 'cto' OR r.role_code = 'staff')
AND e2.cost_visible_flag = 1
)
</if>
GROUP BY
d.department_id,
d.department_name
@ -779,6 +823,29 @@
)
</select>
<!-- 查询无成本查看权限律所的未审核数据数量 -->
<select id="queryNoReviewWithoutCostFilter" resultType="java.lang.Long">
SELECT COUNT(*)
FROM t_service_applications tsa
WHERE tsa.deleted_flag = 0
AND tsa.firm_audit_status = 1
AND tsa.firm_id NOT IN (
SELECT DISTINCT e.department_id
FROM t_employee e
INNER JOIN t_role_employee re ON e.employee_id = re.employee_id
INNER JOIN t_role r ON re.role_id = r.role_id
WHERE (e.deleted_flag = 0 OR e.deleted_flag IS NULL)
AND (r.role_code = 'cto' OR r.role_code = 'staff')
AND e.cost_visible_flag = 1
)
AND (
(YEAR(tsa.create_time) = YEAR(DATE_SUB(NOW(), INTERVAL 1 MONTH))
AND MONTH(tsa.create_time) = MONTH(DATE_SUB(NOW(), INTERVAL 1 MONTH)))
OR
(YEAR(tsa.create_time) = YEAR(NOW()) AND MONTH(tsa.create_time) = MONTH(NOW()))
)
</select>
<!-- 查询有成本查看权限律所的未审核数据数量 -->
<select id="queryNoReviewWithCostFilter" resultType="java.lang.Long">
SELECT COUNT(*)
@ -1156,6 +1223,18 @@
<if test="queryForm.firmAuditStatus != null and queryForm.firmAuditStatus != ''">
AND tsa.firm_audit_status = #{queryForm.firmAuditStatus}
</if>
<if test="queryForm.firmAuditTimeStart != null and queryForm.firmAuditTimeStart != ''">
AND tsa.firm_audit_time &gt;= #{queryForm.firmAuditTimeStart}
</if>
<if test="queryForm.firmAuditTimeEnd != null and queryForm.firmAuditTimeEnd != ''">
AND tsa.firm_audit_time &lt;= #{queryForm.firmAuditTimeEnd}
</if>
<if test="queryForm.associationAuditTimeStart != null and queryForm.associationAuditTimeStart != ''">
AND tsa.association_audit_time &gt;= #{queryForm.associationAuditTimeStart}
</if>
<if test="queryForm.associationAuditTimeEnd != null and queryForm.associationAuditTimeEnd != ''">
AND tsa.association_audit_time &lt;= #{queryForm.associationAuditTimeEnd}
</if>
<if test="queryForm.activityNameId != null and queryForm.activityNameId != ''">
AND tsa.activity_name_id = #{queryForm.activityNameId}
</if>

Loading…
Cancel
Save