diff --git a/src/com/engine/salary/annotation/Auth.java b/src/com/engine/salary/annotation/Auth.java new file mode 100644 index 000000000..55677a320 --- /dev/null +++ b/src/com/engine/salary/annotation/Auth.java @@ -0,0 +1,28 @@ +package com.engine.salary.annotation; + +import com.engine.salary.enums.auth.AuthCheckTypeEnum; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 权限验证字段 + *

Copyright: Copyright (c) 2022

+ *

Company: 泛微软件

+ * + * @author qiantao + * @version 1.0 + **/ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface Auth { + String page(); + + AuthCheckTypeEnum checkType() default AuthCheckTypeEnum.TAX_EMP; + + String taxAgentIdField() default "taxAgentId"; + String employeeIdField() default "employeeId"; + String optsField() default "opts"; +} diff --git a/src/com/engine/salary/annotation/AuthField.java b/src/com/engine/salary/annotation/AuthField.java new file mode 100644 index 000000000..b51cd44f3 --- /dev/null +++ b/src/com/engine/salary/annotation/AuthField.java @@ -0,0 +1,22 @@ +package com.engine.salary.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 权限验证字段 + *

Copyright: Copyright (c) 2022

+ *

Company: 泛微软件

+ * + * @author qiantao + * @version 1.0 + **/ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface AuthField { + + String fieldType(); + +} diff --git a/src/com/engine/salary/annotation/AuthOpt.java b/src/com/engine/salary/annotation/AuthOpt.java new file mode 100644 index 000000000..e4ffcb499 --- /dev/null +++ b/src/com/engine/salary/annotation/AuthOpt.java @@ -0,0 +1,20 @@ +package com.engine.salary.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 权限验证字段 + *

Copyright: Copyright (c) 2022

+ *

Company: 泛微软件

+ * + * @author qiantao + * @version 1.0 + **/ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface AuthOpt { + +} diff --git a/src/com/engine/salary/entity/auth/dto/EmpOpt.java b/src/com/engine/salary/entity/auth/dto/EmpOpt.java index 1a2a59920..89ac9782c 100644 --- a/src/com/engine/salary/entity/auth/dto/EmpOpt.java +++ b/src/com/engine/salary/entity/auth/dto/EmpOpt.java @@ -5,7 +5,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.List; +import java.util.Set; @Data @Builder @@ -13,6 +13,6 @@ import java.util.List; @AllArgsConstructor public class EmpOpt { private Long employeeId; - private List opts; + private Set opts; } diff --git a/src/com/engine/salary/entity/auth/dto/Opt.java b/src/com/engine/salary/entity/auth/dto/Opt.java index 872139ddf..f9171e390 100644 --- a/src/com/engine/salary/entity/auth/dto/Opt.java +++ b/src/com/engine/salary/entity/auth/dto/Opt.java @@ -10,8 +10,6 @@ import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor public class Opt { -// private Long id; -// private String page; private String opt; } diff --git a/src/com/engine/salary/entity/salaryarchive/dto/SalaryArchiveListDTO.java b/src/com/engine/salary/entity/salaryarchive/dto/SalaryArchiveListDTO.java index 1083ca4dd..24958c2d2 100644 --- a/src/com/engine/salary/entity/salaryarchive/dto/SalaryArchiveListDTO.java +++ b/src/com/engine/salary/entity/salaryarchive/dto/SalaryArchiveListDTO.java @@ -1,10 +1,7 @@ package com.engine.salary.entity.salaryarchive.dto; import com.cloudstore.eccom.pc.table.WeaTableType; -import com.engine.salary.annotation.I18n; -import com.engine.salary.annotation.SalaryTable; -import com.engine.salary.annotation.SalaryTableOperate; -import com.engine.salary.annotation.TableTitle; +import com.engine.salary.annotation.*; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AllArgsConstructor; import lombok.Builder; @@ -12,6 +9,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; +import java.util.Set; /** * 薪资档案列表 @@ -29,12 +27,14 @@ import java.util.Date; @SalaryTableOperate(index = "0", text = "编辑"), @SalaryTableOperate(index = "1", text = "删除") }) +@Auth(page = "salaryArchive") public class SalaryArchiveListDTO { @TableTitle(title = "id", dataIndex = "id", key = "id") private Long id; @TableTitle(title = "人员信息表的主键id", dataIndex = "employeeId", key = "employeeId") + @AuthField(fieldType = "employeeId") private Long employeeId; private Integer employeeType; @@ -51,6 +51,7 @@ public class SalaryArchiveListDTO { */ @TableTitle(title = "个税扣缴义务人", dataIndex = "taxAgentName", key = "taxAgentName") private String taxAgentName; + @AuthField(fieldType = "taxAgentId") private Long taxAgentId; /** @@ -121,4 +122,6 @@ public class SalaryArchiveListDTO { */ private String archiveStatus; + private Set opts; + } diff --git a/src/com/engine/salary/entity/salaryarchive/po/SalaryArchivePO.java b/src/com/engine/salary/entity/salaryarchive/po/SalaryArchivePO.java index a1762c54b..f3fee2f08 100644 --- a/src/com/engine/salary/entity/salaryarchive/po/SalaryArchivePO.java +++ b/src/com/engine/salary/entity/salaryarchive/po/SalaryArchivePO.java @@ -1,6 +1,7 @@ package com.engine.salary.entity.salaryarchive.po; import com.engine.hrmelog.annotation.ElogTransform; +import com.engine.salary.annotation.Auth; import com.engine.salary.enums.datacollection.DataCollectionEmployeeTypeEnum; import com.engine.salary.enums.salaryarchive.SalaryArchiveStatusEnum; import com.engine.salary.enums.salaryarchive.SalaryArchiveAddTypeEnum; @@ -29,6 +30,7 @@ import java.util.List; @AllArgsConstructor //hrsa_salary_archive @ElogTransform(name = "薪资档案") +@Auth(page = "salaryArchive") public class SalaryArchivePO { /** diff --git a/src/com/engine/salary/enums/auth/AuthCheckTypeEnum.java b/src/com/engine/salary/enums/auth/AuthCheckTypeEnum.java new file mode 100644 index 000000000..f715fdbb3 --- /dev/null +++ b/src/com/engine/salary/enums/auth/AuthCheckTypeEnum.java @@ -0,0 +1,58 @@ +package com.engine.salary.enums.auth; + +import com.engine.salary.enums.BaseEnum; +import com.engine.salary.exception.SalaryRunTimeException; + +import java.util.Objects; + +/** + * 权限验证方式 + *

Copyright: Copyright (c) 2024

+ *

Company: 泛微软件

+ * + * @author qiantao + * @version 1.0 + **/ +public enum AuthCheckTypeEnum implements BaseEnum { + + + TAX_EMP("TAX_EMP", "扣缴义务人和人员混合验证", 87627), + EMP("EMP", "人员验证", 87626), + TAX("TAX", "扣缴义务人验证", 87626); + + + private String value; + private String defaultLabel; + private int labelId; + + AuthCheckTypeEnum(String value, String defaultLabel, int labelId) { + this.value = value; + this.defaultLabel = defaultLabel; + this.labelId = labelId; + } + + + @Override + public String getValue() { + return value; + } + + @Override + public String getDefaultLabel() { + return defaultLabel; + } + + @Override + public Integer getLabelId() { + return labelId; + } + + public static AuthCheckTypeEnum parseByValue(String value) { + for (AuthCheckTypeEnum typeEnum : AuthCheckTypeEnum.values()) { + if (Objects.equals(typeEnum.getValue(), value)) { + return typeEnum; + } + } + throw new SalaryRunTimeException("未找到对应的枚举"); + } +} diff --git a/src/com/engine/salary/service/TaxAgentAdminService.java b/src/com/engine/salary/service/TaxAgentAdminService.java index 274ba8c07..60ac4d451 100644 --- a/src/com/engine/salary/service/TaxAgentAdminService.java +++ b/src/com/engine/salary/service/TaxAgentAdminService.java @@ -53,4 +53,11 @@ public interface TaxAgentAdminService { * @return */ List listByEmployeeId(Long currentEmployeeId); + + /** + * 获取管理的扣缴义务人id + * @param currentEmployeeId + * @return + */ + List getAdminTaxAgentIds(Long currentEmployeeId); } diff --git a/src/com/engine/salary/service/TaxAgentService.java b/src/com/engine/salary/service/TaxAgentService.java index bab08d143..4f694f5f8 100644 --- a/src/com/engine/salary/service/TaxAgentService.java +++ b/src/com/engine/salary/service/TaxAgentService.java @@ -50,6 +50,13 @@ public interface TaxAgentService { */ Boolean isChief(Long currentEmployeeId); + /** + * 获取管理的扣缴义务人id + * @param currentEmployeeId + * @return + */ + List getAdminTaxAgentIds(Long currentEmployeeId); + /** * 默认权限是否开启 * diff --git a/src/com/engine/salary/service/auth/AuthService.java b/src/com/engine/salary/service/auth/AuthService.java index b15b3f4ee..b0166dbf4 100644 --- a/src/com/engine/salary/service/auth/AuthService.java +++ b/src/com/engine/salary/service/auth/AuthService.java @@ -13,5 +13,7 @@ import java.util.List; * @version 1.0 **/ public interface AuthService { + List auth(List list, Class clazz); + List auth(String page); } diff --git a/src/com/engine/salary/service/auth/AuthServiceImpl.java b/src/com/engine/salary/service/auth/AuthServiceImpl.java index 9103494af..147b66ae8 100644 --- a/src/com/engine/salary/service/auth/AuthServiceImpl.java +++ b/src/com/engine/salary/service/auth/AuthServiceImpl.java @@ -1,17 +1,162 @@ package com.engine.salary.service.auth; +import cn.hutool.core.collection.CollectionUtil; +import com.engine.common.util.ServiceUtil; import com.engine.core.impl.Service; +import com.engine.salary.annotation.Auth; import com.engine.salary.entity.auth.dto.AuthDTO; +import com.engine.salary.entity.auth.dto.EmpOpt; +import com.engine.salary.entity.auth.dto.Opt; +import com.engine.salary.enums.auth.AuthCheckTypeEnum; import com.engine.salary.mapper.auth.AuthMapper; +import com.engine.salary.service.TaxAgentService; +import com.engine.salary.service.impl.TaxAgentServiceImpl; +import com.engine.salary.util.SalaryEntityUtil; import com.engine.salary.util.db.MapperProxyFactory; +import weaver.hrm.User; -import java.util.List; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; +import java.util.stream.Collectors; public class AuthServiceImpl extends Service implements AuthService { + + private TaxAgentService getTaxAgentService(User user) { + return ServiceUtil.getService(TaxAgentServiceImpl.class, user); + } + private AuthMapper getAuthMapper() { return MapperProxyFactory.getProxy(AuthMapper.class); } + @Override + public List auth(List list, Class clazz) { + Boolean isOpenDevolution = getTaxAgentService(user).isOpenDevolution(); + boolean isAuth = clazz.isAnnotationPresent(Auth.class); + + if (!isOpenDevolution || !isAuth) { + return list; + } + + Auth auth = clazz.getAnnotation(Auth.class); + String taxAgentIdField = auth.taxAgentIdField(); + String taxAgentIdFieldGetter = "get" + taxAgentIdField.substring(0, 1).toUpperCase() + taxAgentIdField.substring(1); + String employeeIdField = auth.employeeIdField(); + String employeeIdFieldGetter = "get" + employeeIdField.substring(0, 1).toUpperCase() + employeeIdField.substring(1); + String optsField = auth.optsField(); + String optsFieldGetter = "get" + optsField.substring(0, 1).toUpperCase() + optsField.substring(1); + String optsFieldSetter = "set" + optsField.substring(0, 1).toUpperCase() + optsField.substring(1); + + //给总管理员赋值最大权限 + Boolean isChief = getTaxAgentService(user).isChief((long) user.getUID()); + if (isChief) { + list.forEach(t -> { + try { + Method taxAgentIdFieldGetterMethod = t.getClass().getMethod(taxAgentIdFieldGetter); + Long taxAgentId = (Long) taxAgentIdFieldGetterMethod.invoke(t); + + Method employeeIdFieldGetterMethod = t.getClass().getMethod(employeeIdFieldGetter); + Long employeeId = (Long) employeeIdFieldGetterMethod.invoke(t); + + Method optsFieldGetterMethod = t.getClass().getMethod(optsFieldGetter); + Set opts = (Set) optsFieldGetterMethod.invoke(t); + if (opts == null) { + opts = new HashSet<>(); + } + opts.add("query"); + opts.add("admin"); + + Method optsFieldSetterMethod = t.getClass().getMethod(optsFieldSetter, Set.class); + optsFieldSetterMethod.invoke(t, opts); + + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + }); + + return list; + } + + //给各管理员赋值对应的扣缴义务人权限 + List adminTaxAgentIds = getTaxAgentService(user).getAdminTaxAgentIds((long) user.getUID()); + if (CollectionUtil.isNotEmpty(adminTaxAgentIds)) { + Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + try { + T t = iterator.next(); + Method taxAgentIdFieldGetterMethod = t.getClass().getMethod(taxAgentIdFieldGetter); + Long taxAgentId = (Long) taxAgentIdFieldGetterMethod.invoke(t); + + if (adminTaxAgentIds.contains(taxAgentId)) { + Method optsFieldGetterMethod = t.getClass().getMethod(optsFieldGetter); + Set opts = (Set) optsFieldGetterMethod.invoke(t); + if (opts == null) { + opts = new HashSet<>(); + } + opts.add("query"); + opts.add("admin"); + + Method optsFieldSetterMethod = t.getClass().getMethod(optsFieldSetter, Set.class); + optsFieldSetterMethod.invoke(t, opts); + } else { + iterator.remove(); + } + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + + return list; + } + + //给各角色赋权 + String page = auth.page(); + AuthCheckTypeEnum checkType = auth.checkType(); + List authDTOS = getAuthMapper().getAuth((long) user.getUID(), page); + Map> authMap = SalaryEntityUtil.convert2Map(authDTOS, AuthDTO::getTaxAgentId, AuthDTO::getEmps); + Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + try { + T t = iterator.next(); + Method taxAgentIdFieldGetterMethod = t.getClass().getMethod(taxAgentIdFieldGetter); + Long taxAgentId = (Long) taxAgentIdFieldGetterMethod.invoke(t); + + Method employeeIdFieldGetterMethod = t.getClass().getMethod(employeeIdFieldGetter); + Long employeeId = (Long) employeeIdFieldGetterMethod.invoke(t); + + //混合验证 + if (authMap.containsKey(taxAgentId)) { + List orDefault = authMap.getOrDefault(taxAgentId, new ArrayList<>()); + Map> optsMap = SalaryEntityUtil.convert2Map(orDefault, EmpOpt::getEmployeeId, EmpOpt::getOpts); + if (optsMap.containsKey(employeeId)) { + Set optSets = optsMap.getOrDefault(employeeId, new HashSet<>()).stream().map(Opt::getOpt).collect(Collectors.toSet()); + Method optsFieldGetterMethod = t.getClass().getMethod(optsFieldGetter); + Set opts = (Set) optsFieldGetterMethod.invoke(t); + if (opts == null) { + opts = new HashSet<>(); + } + opts.addAll(optSets); + + Method optsFieldSetterMethod = t.getClass().getMethod(optsFieldSetter, Set.class); + optsFieldSetterMethod.invoke(t, opts); + } else { + iterator.remove(); + } + } else { + iterator.remove(); + } + + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + + return list; + } + @Override public List auth(String page) { return getAuthMapper().getAuth((long) user.getUID(), page); diff --git a/src/com/engine/salary/service/impl/SalaryArchiveServiceImpl.java b/src/com/engine/salary/service/impl/SalaryArchiveServiceImpl.java index 568b7719b..bd9eac70f 100644 --- a/src/com/engine/salary/service/impl/SalaryArchiveServiceImpl.java +++ b/src/com/engine/salary/service/impl/SalaryArchiveServiceImpl.java @@ -35,6 +35,8 @@ import com.engine.salary.exception.SalaryRunTimeException; import com.engine.salary.mapper.archive.SalaryArchiveItemMapper; import com.engine.salary.mapper.archive.SalaryArchiveMapper; import com.engine.salary.service.*; +import com.engine.salary.service.auth.AuthService; +import com.engine.salary.service.auth.AuthServiceImpl; import com.engine.salary.sys.constant.SalarySysConstant; import com.engine.salary.sys.entity.po.SalarySysConfPO; import com.engine.salary.sys.entity.vo.OrderRuleVO; @@ -132,6 +134,10 @@ public class SalaryArchiveServiceImpl extends Service implements SalaryArchiveSe return ServiceUtil.getService(SalarySobServiceImpl.class, user); } + public AuthService getAuthService(User user) { + return ServiceUtil.getService(AuthServiceImpl.class, user); + } + @Override public SalaryArchivePO getById(Long salaryArchiveId) { return salaryArchiveMapper.getById(salaryArchiveId); @@ -183,12 +189,6 @@ public class SalaryArchiveServiceImpl extends Service implements SalaryArchiveSe if (Objects.nonNull(queryParam.getPayEndDateEndDateStr())) { queryParam.setPayEndDateEndDate(SalaryDateUtil.stringToDate(queryParam.getPayEndDateEndDateStr())); } - - //能查看哪些档案 - - //能管理哪些档案 - - List list = getSalaryArchiveMapper().list(queryParam); return SalaryI18nUtil.i18nList(list); } @@ -233,18 +233,10 @@ public class SalaryArchiveServiceImpl extends Service implements SalaryArchiveSe }) .collect(Collectors.toList()); - if (needAuth) { - Boolean adminEnable = getTaxAgentService(user).isAdminEnable(currentEmployeeId); - //不是管理员看不到数据,返回空 - if (!adminEnable) { - PageInfo pageInfo = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(), SalaryArchiveListDTO.class); - return pageInfo; - } - // 获取作为管理员的所有个税扣缴义务人列表 - Collection taxAgentPOS = getTaxAgentService(user).listAllTaxAgentsAsAdmin(currentEmployeeId); - Set taxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId); - list = list.stream().filter(dto -> taxAgentIds.contains(dto.getTaxAgentId())).collect(Collectors.toList()); - } + //能查看哪些档案 + list = getAuthService(user).auth(list, SalaryArchiveListDTO.class); + + PageInfo pageInfo = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(), SalaryArchiveListDTO.class); pageInfo.setTotal(list.size()); pageInfo.setList(SalaryPageUtil.subList(queryParam.getCurrent(), queryParam.getPageSize(), list)); @@ -795,7 +787,7 @@ public class SalaryArchiveServiceImpl extends Service implements SalaryArchiveSe LoggerContext loggerContext = new LoggerContext(); loggerContext.setUser(user); loggerContext.setTargetId(String.valueOf(e.getId())); - loggerContext.setTargetName( Optional.ofNullable(taxAgentMap.get(e.getTaxAgentId())).orElse(StringUtils.EMPTY) + bar + Optional.ofNullable(empMap.get(e.getEmployeeId())).orElse(StringUtils.EMPTY) ); + loggerContext.setTargetName(Optional.ofNullable(taxAgentMap.get(e.getTaxAgentId())).orElse(StringUtils.EMPTY) + bar + Optional.ofNullable(empMap.get(e.getEmployeeId())).orElse(StringUtils.EMPTY)); loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue()); loggerContext.setOperateTypeName(operatedesc); loggerContext.setOperatedesc(operatedesc); @@ -1085,26 +1077,9 @@ public class SalaryArchiveServiceImpl extends Service implements SalaryArchiveSe //获取管理的人员范围 List taxAgentEmployeeDTOS = getTaxAgentService(user).listTaxAgentAndEmployeeTree(currentEmployeeId); Map> taxAgentEmployeesMap = SalaryEntityUtil.convert2Map(taxAgentEmployeeDTOS, TaxAgentManageRangeEmployeeDTO::getTaxAgentId, TaxAgentManageRangeEmployeeDTO::getEmployeeList); - List list = new ArrayList<>(); - if (needAuth) { - // 获取作为管理员的所有个税扣缴义务人列表 - Collection taxAgentPOS = getTaxAgentService(user).listAllTaxAgentsAsAdmin(currentEmployeeId); - Set taxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId); - - //获取所有薪资档案 - List archiveListDTOS = getSalaryArchiveMapper().listAll(); - list = archiveListDTOS.stream().filter(dto -> taxAgentIds.contains(dto.getTaxAgentId())).collect(Collectors.toList()); - - Boolean adminEnable = getTaxAgentService(user).isAdminEnable(currentEmployeeId); - //不是管理员看不到数据,返回空 - if (!adminEnable) { - list = new ArrayList<>(); - } - - } else { - list = getSalaryArchiveMapper().listAll(); - } + List list = getSalaryArchiveMapper().listAll(); + list = getAuthService(user).auth(list,SalaryArchivePO.class); long pendingTotal = 0L; long fixedTotal = 0L; diff --git a/src/com/engine/salary/service/impl/TaxAgentAdminServiceImpl.java b/src/com/engine/salary/service/impl/TaxAgentAdminServiceImpl.java index 72838fc10..171bd953a 100644 --- a/src/com/engine/salary/service/impl/TaxAgentAdminServiceImpl.java +++ b/src/com/engine/salary/service/impl/TaxAgentAdminServiceImpl.java @@ -13,6 +13,7 @@ import org.apache.commons.collections4.CollectionUtils; import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.stream.Collectors; /** * 个税扣缴义务人管理员 @@ -79,4 +80,9 @@ public class TaxAgentAdminServiceImpl extends Service implements TaxAgentAdminSe public List listByEmployeeId(Long currentEmployeeId) { return getTaxAgentAdminMapper().listSome(TaxAgentAdminPO.builder().employeeId(currentEmployeeId).build()); } + + @Override + public List getAdminTaxAgentIds(Long currentEmployeeId) { + return listByEmployeeId(currentEmployeeId).stream().map(TaxAgentAdminPO::getTaxAgentId).collect(Collectors.toList()); + } } diff --git a/src/com/engine/salary/service/impl/TaxAgentServiceImpl.java b/src/com/engine/salary/service/impl/TaxAgentServiceImpl.java index aa0890cb7..8f02b60d1 100644 --- a/src/com/engine/salary/service/impl/TaxAgentServiceImpl.java +++ b/src/com/engine/salary/service/impl/TaxAgentServiceImpl.java @@ -225,6 +225,11 @@ public class TaxAgentServiceImpl extends Service implements TaxAgentService { return hasRight; } + @Override + public List getAdminTaxAgentIds(Long currentEmployeeId) { + return getTaxAgentAdminService(user).getAdminTaxAgentIds(currentEmployeeId); + } + @Override public Boolean isDefaultOpen(Long currentEmployeeId) { return getTaxAgentBaseService(user).isOpenDevolution();