package com.engine.salary.service.impl; import com.engine.common.util.ServiceUtil; import com.engine.core.impl.Service; import com.engine.salary.common.LocalDateRange; import com.engine.salary.entity.salaryacct.po.SalaryAcctRecordPO; import com.engine.salary.entity.salaryacct.po.SalaryAcctResultPO; import com.engine.salary.entity.salaryitem.po.SalaryItemPO; import com.engine.salary.entity.salarysob.po.SalarySobPO; import com.engine.salary.entity.taxagent.po.TaxAgentPO; import com.engine.salary.entity.taxdeclaration.bo.TaxDeclarationBO; import com.engine.salary.entity.taxdeclaration.param.TaxDeclarationListQueryParam; import com.engine.salary.entity.taxdeclaration.param.TaxDeclarationSaveParam; import com.engine.salary.entity.taxdeclaration.po.TaxDeclarationPO; import com.engine.salary.enums.salaryaccounting.SalaryAcctRecordStatusEnum; import com.engine.salary.exception.SalaryRunTimeException; import com.engine.salary.mapper.datacollection.AddUpSituationMapper; import com.engine.salary.mapper.salaryacct.SalaryAcctRecordMapper; import com.engine.salary.mapper.taxdeclaration.TaxDeclarationMapper; import com.engine.salary.service.*; import com.engine.salary.util.SalaryDateUtil; import com.engine.salary.util.SalaryEntityUtil; import com.engine.salary.util.SalaryI18nUtil; import com.engine.salary.util.db.MapperProxyFactory; import com.engine.salary.util.page.PageInfo; import com.engine.salary.util.page.SalaryPageUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import weaver.general.BaseBean; import weaver.hrm.User; import java.time.YearMonth; import java.util.*; import java.util.stream.Collectors; @Slf4j public class TaxDeclarationServiceImpl extends Service implements TaxDeclarationService { private final Boolean isLog = "true".equals(new BaseBean().getPropValue("hrmSalary", "log")); private TaxDeclarationMapper getTaxDeclarationMapper() { return MapperProxyFactory.getProxy(TaxDeclarationMapper.class); } private SalaryAcctRecordMapper getSalaryAcctRecordMapper() { return MapperProxyFactory.getProxy(SalaryAcctRecordMapper.class); } private AddUpSituationMapper getAddUpSituationMapper() { return MapperProxyFactory.getProxy(AddUpSituationMapper.class); } private TaxDeclarationDetailService getTaxDeclarationDetailService(User user) { return ServiceUtil.getService(TaxDeclarationDetailServiceImpl.class, user); } private AddUpSituationService getAddUpSituationService(User user) { return ServiceUtil.getService(AddUpSituationServiceImpl.class, user); } private TaxAgentService getTaxAgentService(User user) { return ServiceUtil.getService(TaxAgentServiceImpl.class, user); } private SalarySobService getSalarySobService(User user) { return ServiceUtil.getService(SalarySobServiceImpl.class, user); } private SalaryAcctResultService getSalaryAcctResultService(User user) { return ServiceUtil.getService(SalaryAcctResultServiceImpl.class, user); } private SalaryItemService getSalaryItemService(User user) { return ServiceUtil.getService(SalaryItemServiceImpl.class, user); } private SalaryAcctRecordService getSalaryAcctRecordService(User user) { return ServiceUtil.getService(SalaryAcctRecordServiceImpl.class, user); } private SalaryAcctEmployeeService getSalaryAcctEmployeeService(User user) { return ServiceUtil.getService(SalaryAcctEmployeeServiceImpl.class, user); } @Override public List listByTaxCycleAndTaxAgentIds(YearMonth taxCycle, Collection taxAgentIds) { if (Objects.isNull(taxCycle) || CollectionUtils.isEmpty(taxAgentIds)) { throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误")); } TaxDeclarationPO po = TaxDeclarationPO.builder().taxCycle(SalaryDateUtil.toDate(taxCycle, 1)).taxAgentIds(taxAgentIds).build(); List taxDeclarationPOS = getTaxDeclarationMapper().listSome(po); return taxDeclarationPOS; } @Override public PageInfo listPageByParam(TaxDeclarationListQueryParam queryParam) { long currentEmployeeId = user.getUID(); // 分页参数 TaxDeclarationPO po = TaxDeclarationPO.builder().build(); LocalDateRange localDateRange = new LocalDateRange(); if (Objects.nonNull(queryParam.getFromSalaryMonth())) { localDateRange.setFromDate(queryParam.getFromSalaryMonth()); } if (Objects.nonNull(queryParam.getEndSalaryMonth())) { localDateRange.setEndDate(SalaryDateUtil.localDateToDate(SalaryDateUtil.localDate2YearMonth(queryParam.getEndSalaryMonth()).atEndOfMonth())); } po.setSalaryMonths(localDateRange); // 分权 Boolean openDevolution = getTaxAgentService(user).isNeedAuth(currentEmployeeId); if (openDevolution) { // 查询负责管理的个税扣缴义务人 Collection taxAgentPOS = getTaxAgentService(user).listAllTaxAgents(currentEmployeeId); if (CollectionUtils.isEmpty(taxAgentPOS)) { return new PageInfo<>(new ArrayList<>()); } Set taxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId); po.setTaxAgentIds(taxAgentIds); } // 查询个税申报表 List taxDeclarationPOS = getTaxDeclarationMapper().listSome(po); return SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(), taxDeclarationPOS, TaxDeclarationPO.class); } //根据id查询taxAgents @Override public List countByTaxDeclarationId(Collection taxAgentIds) { if (CollectionUtils.isEmpty(taxAgentIds)) { return Collections.emptyList(); } return getTaxAgentService(user).listByIds(taxAgentIds); } //根据id获取TaxDeclaration @Override public TaxDeclarationPO getById(Long id) { return getTaxDeclarationMapper().getById(id); } @Override public void save(TaxDeclarationSaveParam saveParam) { long currentEmployeeId = user.getUID(); // 个税扣缴义务人id Set taxAgentIds; Long taxAgentId = saveParam.getTaxAgentId(); if (taxAgentId == null) { throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "请选择要申报的扣缴义务人!")); } if (taxAgentId != null) { taxAgentIds = Collections.singleton(taxAgentId); } else { //管理的扣缴义务人一次性申报逻辑 Boolean openDevolution = getTaxAgentService(user).isOpenDevolution(); if (BooleanUtils.isFalse(openDevolution)) { taxAgentIds = SalaryEntityUtil.properties(getTaxAgentService(user).listAll(), TaxAgentPO::getId); } else { taxAgentIds = SalaryEntityUtil.properties(getTaxAgentService(user).listAllTaxAgentsAsAdmin(currentEmployeeId), TaxAgentPO::getId); } } // 检查是否具有权限 if (CollectionUtils.isEmpty(taxAgentIds)) { throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "对不起,您不具备任何个税扣缴义务人的管理权限")); } // 查询个税扣缴义务人 List taxAgentPOS = getTaxAgentService(user).listByIds(taxAgentIds); Map taxAgentNameMap = SalaryEntityUtil.convert2Map(taxAgentPOS, TaxAgentPO::getId, TaxAgentPO::getName); // 薪资所属月的日期范围 LocalDateRange salaryMonthDateRange = SalaryDateUtil.localDate2Range(SalaryDateUtil.localDateToDate(saveParam.getSalaryMonth().atDay(1))); if (Objects.isNull(salaryMonthDateRange)) { throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "薪资所属月参数错误")); } // 查询薪资所属月个税扣缴义务人已经生成过的个税申报表 List taxDeclarationPOS = listBySalaryMonthTax(TaxDeclarationPO.builder().salaryMonths(salaryMonthDateRange).taxAgentIds(taxAgentNameMap.keySet()).build()); // 已经生成过个税申报表,不允许再次生成个税申报表 if (CollectionUtils.isNotEmpty(taxDeclarationPOS)) { throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(107986, "{0}在{1}已经生成过个税申报表,不允许再次生成") .replace("{0}", taxAgentNameMap.get(taxDeclarationPOS.get(0).getTaxAgentId())) .replace("{1}", saveParam.getSalaryMonth().toString())); } // 查询薪资所属月的薪资核算记录 List salaryAcctRecordPOS = listBySalaryMonth(SalaryAcctRecordPO.builder().salaryMonths(salaryMonthDateRange).build()); // 无薪资核算记录,不允许生成个税申报表 if (CollectionUtils.isEmpty(salaryAcctRecordPOS)) { throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98874, "{0}无申报数据").replace("{0}", saveParam.getSalaryMonth().toString())); } // 查询薪资核算结果 List salaryAcctResultPOS = getSalaryAcctResultService(user) .listBySalaryAcctRecordIdsAndTaxAgentIds(SalaryEntityUtil.properties(salaryAcctRecordPOS, SalaryAcctRecordPO::getId), taxAgentIds); // 无薪资核算结果,不允许生成个税申报表 if (CollectionUtils.isEmpty(salaryAcctResultPOS)) { throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(110093, "{0}无可申报数据") .replace("{0}", saveParam.getSalaryMonth().toString())); } Set salaryAcctRecordIds = SalaryEntityUtil.properties(salaryAcctResultPOS, SalaryAcctResultPO::getSalaryAcctRecordId); salaryAcctRecordPOS = salaryAcctRecordPOS.stream().filter(salaryAcctRecordPO -> salaryAcctRecordIds.contains(salaryAcctRecordPO.getId())).collect(Collectors.toList()); // 如果存在未归档的,也不允许生成个税申报表 boolean notArchived = salaryAcctRecordPOS.stream().anyMatch(salaryAcctRecordPO -> Objects.equals(salaryAcctRecordPO.getStatus(), SalaryAcctRecordStatusEnum.NOT_ARCHIVED.getValue())); if (notArchived) { throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98875, "{0}有未归档数据,请全部归档后再申报") .replace("{0}", saveParam.getSalaryMonth().toString())); } // 如果当前薪资所属月下存在不同的税款所属期,属于异常业务场景,不允许生成个税申报表 Date taxCycle = salaryAcctRecordPOS.get(0).getTaxCycle(); boolean differentTaxCycle = salaryAcctRecordPOS.stream().anyMatch(salaryAcctRecordPO -> salaryAcctRecordPO.getTaxCycle().compareTo(taxCycle) != 0); if (differentTaxCycle) { throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98876, "{0}存在不同的税款所属期,无法正常生成个税申报表,请调整账套设置,重新核算后再生成个税申报表") .replace("{0}", saveParam.getSalaryMonth().toString())); } // 查询薪资账套 Set salarySobIds = SalaryEntityUtil.properties(salaryAcctRecordPOS, SalaryAcctRecordPO::getSalarySobId); List salarySobPOS = getSalarySobService(user).listByIds(salarySobIds); // 查询所有薪资项目 List salaryItemPOS = getSalaryItemService(user).listAll(); // 处理要保存的数据 TaxDeclarationBO.Result result = TaxDeclarationBO.handle(saveParam, taxCycle, user, salaryItemPOS, salarySobPOS, salaryAcctResultPOS); // 保存个税申报表 if (CollectionUtils.isNotEmpty(result.getNeedInsertTaxDeclarations())) { if (isLog) { log.info("salary TaxDeclaration step1 save {}", result.getNeedInsertTaxDeclarations().size()); } getTaxDeclarationMapper().batchInsert(result.getNeedInsertTaxDeclarations()); } // 保存个税申报表明细 if (CollectionUtils.isNotEmpty(result.getNeedInsertTaxDeclarationDetails())) { if (isLog) { log.info("salary TaxDeclaration step2 detail save {}", result.getNeedInsertTaxDeclarationDetails().size()); } getTaxDeclarationDetailService(user).batchSave(result.getNeedInsertTaxDeclarationDetails()); } // 保存累计情况 if (CollectionUtils.isNotEmpty(result.getNeedInsertAddUpSituations())) { if (isLog) { log.info("salary TaxDeclaration step3 AddUpSituations save {}", result.getNeedInsertAddUpSituations().size()); } getAddUpSituationService(user).deleteByTaxYearMonthAndTaxAgentIds(SalaryDateUtil.localDate2YearMonth(taxCycle), taxAgentIds); getAddUpSituationService(user).batchSave((List) result.getNeedInsertAddUpSituations()); } // 更新薪资核算记录的状态 if (isLog) { log.info("salary TaxDeclaration step4 AcctRecordStatus save {}", salaryAcctRecordIds.size()); } getSalaryAcctRecordService(user).updateStatusByIds(salaryAcctRecordIds, SalaryAcctRecordStatusEnum.DECLARED); } @Override public void delete(SalaryAcctRecordPO salaryAcctRecordPO) { SalarySobPO sobPO = getSalarySobService(user).getById(salaryAcctRecordPO.getSalarySobId()); if (sobPO == null || sobPO.getTaxAgentId() == null) { throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "账套信息异常")); } // 薪资所属月的日期范围 LocalDateRange taxCycleDateRange = SalaryDateUtil.localDate2Range(salaryAcctRecordPO.getTaxCycle()); if (Objects.isNull(taxCycleDateRange)) { throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误")); } List taxDeclarationPOS = listByTaxCycleAndTaxAgentIds(SalaryDateUtil.localDate2YearMonth(salaryAcctRecordPO.getTaxCycle()), Collections.singleton(sobPO.getTaxAgentId())); Set taxDeclarationIds = SalaryEntityUtil.properties(taxDeclarationPOS, TaxDeclarationPO::getId); if (CollectionUtils.isNotEmpty(taxDeclarationIds)) { // 删除个税申报表 getTaxDeclarationMapper().deleteByIds(taxDeclarationIds); // 删除个税申报表详情 getTaxDeclarationDetailService(user).deleteByTaxDeclarationIds(taxDeclarationIds); } // 删除往期累计情况 getAddUpSituationService(user).deleteAddUpSituationList(salaryAcctRecordPO.getTaxCycle(), sobPO.getTaxAgentId()); } public List listBySalaryMonthTax(TaxDeclarationPO build) { return getTaxDeclarationMapper().listSome(build); } public List listBySalaryMonth(SalaryAcctRecordPO po) { return getSalaryAcctRecordMapper().listSome(po); } @Override public boolean checkByAuthority(TaxDeclarationPO taxDeclarationPO, Long employeeId) { // 判断是否开启了分权 Boolean openDevolution = getTaxAgentService(user).isOpenDevolution(); // 判断是否是总管理员 Boolean isChief = getTaxAgentService(user).isChief(employeeId); if (openDevolution && !isChief) { // 查询负责管理的个税扣缴义务人 Collection taxAgentPOS = getTaxAgentService(user).listAllTaxAgentsAsAdmin(employeeId); if (CollectionUtils.isEmpty(taxAgentPOS)) { return false; } Set taxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId); return taxAgentIds.contains(taxDeclarationPO.getTaxAgentId()); } // 查询个税申报表 return true; } @Override public void withDrawTaxDeclaration(Long taxDeclarationId) { TaxDeclarationPO po = getTaxDeclarationMapper().getById(taxDeclarationId); if (Objects.isNull(po)) { throw new SalaryRunTimeException("个税申报表不存在"); } // 获取当前个税扣缴义务人下的薪资账套 List salarySobPOS = getSalarySobService(user).listByTaxAgentId(po.getTaxAgentId()); List salarySobIds = salarySobPOS.stream().map(SalarySobPO::getId).collect(Collectors.toList()); // 获取记录 LocalDateRange dateRange = new LocalDateRange(po.getSalaryMonth(), po.getSalaryMonth()); List salaryAcctRecords = getSalaryAcctRecordService(user).listBySalarySobIdsAndSalaryMonth(salarySobIds, dateRange); List salaryAcctRecordIds = salaryAcctRecords.stream().map(SalaryAcctRecordPO::getId).collect(Collectors.toList()); // 删除个税申报表 getTaxDeclarationMapper().deleteByIdZj(po.getId()); // 修改薪资核算记录状态为已归档 if (CollectionUtils.isNotEmpty(salaryAcctRecordIds)) { getSalaryAcctRecordService(user).updateStatusByIds(salaryAcctRecordIds, SalaryAcctRecordStatusEnum.ARCHIVED); } } @Override public void deleteByTaxDeclareRecordIds(Collection taxDeclareRecordIds) { if (CollectionUtils.isEmpty(taxDeclareRecordIds)) { return; } getTaxDeclarationMapper().deleteByIds(taxDeclareRecordIds); // new LambdaUpdateChainWrapper<>(baseMapper) // .eq(TaxDeclarationPO::getTenantKey, tenantKey) // .eq(TaxDeclarationPO::getDeleteType, DeleteTypeEnum.NOT_DELETED.getValue()) // .in(TaxDeclarationPO::getTaxDeclareRecordId, taxDeclareRecordIds) // .set(TaxDeclarationPO::getDeleteType, DeleteTypeEnum.DELETED.getValue()) // .set(TaxDeclarationPO::getUpdateTime, LocalDateTime.now()) // .update(); } @Override public void saveBatch(List taxDeclarations) { if (CollectionUtils.isNotEmpty(taxDeclarations)) { getTaxDeclarationMapper().batchInsert(taxDeclarations); } } }