package com.engine.salary.service.impl; import com.api.formmode.mybatis.util.SqlProxyHandle; import com.cloudstore.eccom.pc.table.WeaTableColumn; import com.engine.common.util.ServiceUtil; import com.engine.core.impl.Service; import com.engine.salary.config.SalaryElogConfig; import com.engine.salary.elog.entity.dto.LoggerContext; import com.engine.salary.entity.taxagent.po.TaxAgentPO; import com.engine.salary.entity.taxdeclaration.dto.TaxDeclarationAnnualListDTO; import com.engine.salary.entity.taxdeclaration.dto.TaxDeclarationLaborListDTO; import com.engine.salary.entity.taxdeclaration.dto.TaxDeclarationWageListDTO; import com.engine.salary.entity.taxdeclaration.param.TaxDeclarationDetailListQueryParam; import com.engine.salary.entity.taxdeclaration.po.TaxDeclarationPO; import com.engine.salary.enums.OperateTypeEnum; import com.engine.salary.constant.SalaryDefaultTenantConstant; import com.engine.salary.entity.datacollection.DataCollectionEmployee; import com.engine.salary.entity.taxdeclaration.dto.AbnormalEmployeeListDTO; import com.engine.salary.entity.taxdeclaration.dto.FailEmployeeListDTO; import com.engine.salary.entity.taxdeclaration.dto.TaxDeclarationValueListDTO; import com.engine.salary.entity.taxdeclaration.param.AbnormalEmployeeListQueryParam; import com.engine.salary.entity.taxdeclaration.param.DownloadTemplateParam; import com.engine.salary.entity.taxdeclaration.param.TaxDeclarationValueListQueryParam; import com.engine.salary.entity.taxdeclaration.po.*; import com.engine.salary.enums.UserStatusEnum; import com.engine.salary.enums.salaryaccounting.EmployeeTypeEnum; import com.engine.salary.enums.salaryitem.SalaryDataTypeEnum; import com.engine.salary.enums.salarysob.IncomeCategoryEnum; import com.engine.salary.enums.sicategory.DeleteTypeEnum; import com.engine.salary.enums.taxdeclaration.SourceEnum; import com.engine.salary.mapper.sys.SalarySysConfMapper; import com.engine.salary.service.*; import com.engine.salary.sys.entity.po.SalarySysConfPO; import com.engine.salary.mapper.taxdeclaration.TaxDeclarationDetailMapper; import com.engine.salary.service.TaxAgentService; import com.engine.salary.service.TaxDeclarationDetailService; import com.engine.salary.service.TaxDeclarationExcelService; import com.engine.salary.service.TaxDeclarationService; import com.engine.salary.util.JsonUtil; import com.engine.salary.util.SalaryDateUtil; import com.engine.salary.util.SalaryEntityUtil; import com.engine.salary.util.SalaryI18nUtil; import com.engine.salary.util.excel.ExcelParseHelper; import com.engine.salary.util.excel.ExcelSheetData; import com.engine.salary.util.excel.ExcelSupport; import com.engine.salary.util.excel.ExcelUtil; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.engine.salary.util.db.IdGenerator; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import weaver.file.ImageFileManager; import weaver.general.Util; import weaver.hrm.User; import java.io.InputStream; import java.util.*; import java.util.stream.Collectors; import static com.engine.salary.util.excel.ExcelSupport.EXCEL_TYPE_XLSX; /** * 个税申报表导出 *

Copyright: Copyright (c) 2022

*

Company: 泛微软件

* * @author qiantao * @version 1.0 **/ @Slf4j public class TaxDeclarationExcelServiceImpl extends Service implements TaxDeclarationExcelService { private TaxDeclarationService getTaxDeclarationService(User user) { return ServiceUtil.getService(TaxDeclarationServiceImpl.class, user); } private TaxDeclarationValueService getTaxDeclarationValueService(User user) { return ServiceUtil.getService(TaxDeclarationValueServiceImpl.class, user); } private TaxDeclareRecordService getTaxDeclareRecordService(User user) { return ServiceUtil.getService(TaxDeclareRecordServiceImpl.class, user); } private TaxDeclareEmployeeService getTaxDeclareEmployeeService(User user) { return ServiceUtil.getService(TaxDeclareEmployeeServiceImpl.class, user); } private TaxDeclareFailService getTaxDeclareFailService(User user) { return ServiceUtil.getService(TaxDeclareFailServiceImpl.class, user); } private TaxAgentService getTaxAgentService(User user) { return ServiceUtil.getService(TaxAgentServiceImpl.class, user); } private TaxReportColumnService getTaxReportColumnService(User user) { return ServiceUtil.getService(TaxReportColumnServiceImpl.class, user); } private SalarySysConfMapper getSalarySysConfMapper() { return SqlProxyHandle.getProxy(SalarySysConfMapper.class); } private SalaryEmployeeService getSalaryEmployeeService(User user) { return ServiceUtil.getService(SalaryEmployeeServiceImpl.class, user); } @Override public XSSFWorkbook exportTaxDeclarationValue(TaxDeclarationValueListQueryParam queryParam) { // 查询个税申报表 TaxDeclarationPO taxDeclarationPO = getTaxDeclarationService(user).getById(queryParam.getTaxDeclarationId()); // 查询个税申报表明细 List taxDeclarationValues = getTaxDeclarationValueService(user).listByTaxDeclarationIds(Collections.singleton(queryParam.getTaxDeclarationId())); // 转成个税申报表明细 TaxDeclarationValueListDTO taxDeclarationValueListDTO = getTaxDeclarationValueService(user).convert2List(taxDeclarationPO, taxDeclarationValues); // excel导出的数据 List> rows = Lists.newArrayList(); List headerList = Lists.newArrayList(); List dataIndexList = Lists.newArrayList(); // 解析表头 for (WeaTableColumn column : taxDeclarationValueListDTO.getColumns()) { headerList.add(column.getText()); dataIndexList.add(column.getColumn()); } rows.add(headerList); // 解析表中数据 for (Map datum : taxDeclarationValueListDTO.getData()) { List row = Lists.newArrayList(); for (String dataIndex : dataIndexList) { row.add(Util.null2String(datum.get(dataIndex))); } rows.add(row); } String sheetName = SalaryI18nUtil.getI18nLabel(100090, "个税申报表"); return ExcelUtil.genWorkbook(rows, sheetName); } @Override public XSSFWorkbook exportEmployee4NotDeclare(AbnormalEmployeeListQueryParam queryParam) { // 查询个税申报记录 TaxDeclareRecordPO taxDeclareRecord = getTaxDeclareRecordService(user).getById(queryParam.getTaxDeclareRecordId()); queryParam.setTaxAgentId(taxDeclareRecord.getTaxAgentId()); queryParam.setTaxCycle(taxDeclareRecord.getTaxCycle()); // 查询个税申报表明细中的人员 List taxDeclareEmployees = getTaxDeclareEmployeeService(user).list4NotDeclareByParam(queryParam); // 转换成列表dto List dtoList = getTaxDeclareEmployeeService(user).convert2AbnormalEmployeeList(taxDeclareRecord, taxDeclareEmployees); ExcelSheetData excelSheetData = getExcelSheetData(AbnormalEmployeeListDTO.class, dtoList); return ExcelUtil.genWorkbook(excelSheetData); } @Override public XSSFWorkbook exportEmployee4NoValue(AbnormalEmployeeListQueryParam queryParam) { // 查询个税申报记录 TaxDeclareRecordPO taxDeclareRecord = getTaxDeclareRecordService(user).getById(queryParam.getTaxDeclareRecordId()); queryParam.setTaxAgentId(taxDeclareRecord.getTaxAgentId()); queryParam.setTaxCycle(taxDeclareRecord.getTaxCycle()); // 查询个税申报表明细中的人员 List taxDeclareEmployees = getTaxDeclareEmployeeService(user).list4NoValueByParam(queryParam); // 转换成列表dto List dtoList = getTaxDeclareEmployeeService(user).convert2AbnormalEmployeeList(taxDeclareRecord, taxDeclareEmployees); ExcelSheetData excelSheetData = getExcelSheetData(AbnormalEmployeeListDTO.class, dtoList); return ExcelUtil.genWorkbook(excelSheetData); } @Override public XSSFWorkbook exportEmployee4Fail(AbnormalEmployeeListQueryParam queryParam) { // 查询个税申报记录 TaxDeclareRecordPO taxDeclareRecord = getTaxDeclareRecordService(user).getById(queryParam.getTaxDeclareRecordId()); queryParam.setTaxAgentId(taxDeclareRecord.getTaxAgentId()); queryParam.setTaxCycle(taxDeclareRecord.getTaxCycle()); // 查询个税申报表明细中的人员 List taxDeclareFails = getTaxDeclareFailService(user).listByTaxDeclareRecordIds(Collections.singleton(taxDeclareRecord.getId())); // 转换成列表dto List dtoList = getTaxDeclareFailService(user).convert2FailEmployeeList(taxDeclareRecord, taxDeclareFails); ExcelSheetData excelSheetData = getExcelSheetData(FailEmployeeListDTO.class, dtoList); return ExcelUtil.genWorkbook(excelSheetData); } private ExcelSheetData getExcelSheetData(Class clazz, List dtoList) { // 导出的表头 List headerList = Lists.newArrayList(); List dataIndexList = Lists.newArrayList(); ExcelUtil.parseHeader(clazz, headerList, dataIndexList); // 导出的数据 List> rows = Lists.newArrayListWithExpectedSize(dtoList.size()); dtoList.forEach(dto -> { Map map = JsonUtil.parseMap(dto, Object.class); List row = Lists.newArrayListWithExpectedSize(dataIndexList.size()); dataIndexList.forEach(dataIndex -> row.add(map.get(dataIndex))); rows.add(row); }); // 组装excel导出数据 ExcelSheetData excelSheetData = new ExcelSheetData(); excelSheetData.setSheetName(SalaryI18nUtil.getI18nLabel(156423, "个税申报表人员")); excelSheetData.setHeaders(headerList); excelSheetData.setRows(rows); return excelSheetData; } @Override public XSSFWorkbook downloadTemplate(DownloadTemplateParam param) { TaxDeclarationPO declarationPO = getTaxDeclarationService(user).getById(param.getTaxDeclarationId()); IncomeCategoryEnum incomeCategoryEnum = IncomeCategoryEnum.parseByValue(declarationPO.getIncomeCategory()); List taxReportColumnPOS = getTaxReportColumnService(user).listByIncomeCategory(incomeCategoryEnum,0); List heads = new ArrayList<>(); heads.add(SalaryI18nUtil.getI18nLabel(85429, "姓名")); heads.add(SalaryI18nUtil.getI18nLabel(86185, "部门")); heads.add(SalaryI18nUtil.getI18nLabel(86186, "手机号")); heads.add(SalaryI18nUtil.getI18nLabel(86317, "工号")); heads.addAll(SalaryEntityUtil.properties(taxReportColumnPOS, TaxReportColumnPO::getReportColumnName, Collectors.toList())); List> rowList = new ArrayList<>(); rowList.add(heads); XSSFWorkbook book = ExcelUtil.genWorkbookV2(rowList, incomeCategoryEnum.getDefaultLabel()); return book; } @Override public Map preview(DownloadTemplateParam importParam) { //excel文件id String imageId = Util.null2String(importParam.getImageId()); Validate.notBlank(imageId, "imageId为空"); InputStream fileInputStream = null; Map map = new HashMap<>(); try { fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(importParam.getImageId())); Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX); map.put("headers", ExcelSupport.getSheetHeader(sheet, 0)); map.put("list", ExcelParseHelper.parse2List(sheet, 1, 0)); return map; } finally { IOUtils.closeQuietly(fileInputStream); } // 查询个税扣缴义务人名称 String bar = "_"; TaxAgentPO taxAgentPO = getTaxAgentService(user).getById(taxDeclarationPO.getTaxAgentId()); String targetName = SalaryDateUtil.getFormatYearMonth(taxDeclarationPO.getSalaryMonth()) + bar + taxAgentPO.getName() + bar + IncomeCategoryEnum.parseByValue(taxDeclarationPO.getIncomeCategory()).getDefaultLabel(); // 记录日志 LoggerContext loggerContext = new LoggerContext<>(); loggerContext.setUser(user); loggerContext.setTargetId(taxDeclarationId.toString()); loggerContext.setTargetName(targetName); loggerContext.setOperateType(OperateTypeEnum.EXCEL_EXPORT.getValue()); loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel( 0, "导出个税申报表")); loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel( 0, "导出个税申报表")); SalaryElogConfig.taxDeclarationLoggerTemplate.write(loggerContext); return ExcelUtil.genWorkbookV2(rows, sheetName); } @Override public Map importData(DownloadTemplateParam param) { Map apidatas = new HashMap<>(); //查询对于人员信息导入筛选的全局配置 SalarySysConfPO salarySysConfPO = getSalarySysConfMapper().getOneByCode("matchEmployeeMode"); String confValue = (salarySysConfPO != null && salarySysConfPO.getConfValue() != null && !"".equals(salarySysConfPO.getConfValue())) ? salarySysConfPO.getConfValue() : "0"; // 租户下所有的人员 List salaryEmployees = getSalaryEmployeeService(user).listAllForReport(); TaxDeclarationPO declarationPO = getTaxDeclarationService(user).getById(param.getTaxDeclarationId()); IncomeCategoryEnum incomeCategoryEnum = IncomeCategoryEnum.parseByValue(declarationPO.getIncomeCategory()); List taxReportColumnPOS = getTaxReportColumnService(user).listByIncomeCategory(incomeCategoryEnum,0); List taxReportColumnNames = SalaryEntityUtil.properties(taxReportColumnPOS, TaxReportColumnPO::getReportColumnName, Collectors.toList()); List taxDeclarationValuePOS = getTaxDeclarationValueService(user).listByTaxDeclarationId(declarationPO.getId()); Map empDeclarationValueMap = SalaryEntityUtil.convert2Map(taxDeclarationValuePOS, TaxDeclarationValuePO::getEmployeeId); // 失败的数量 int errorCount = 0; // 成功的数量 int successCount = 0; Date now = new Date(); List addList = Lists.newArrayList(); List editList = Lists.newArrayList(); InputStream fileInputStream = null; try { fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(param.getImageId())); Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX); // 错误提示信息 List excelComments = Lists.newArrayList(); // 存在错误的那行数据 List> errorDatas = Lists.newArrayList(); // 表头 List headers = ExcelSupport.getSheetHeader(sheet, 0); List> data = ExcelParseHelper.parse2Map(sheet, 1, 0); if (CollectionUtils.isEmpty(headers)) { Map errorMessageMap = Maps.newHashMap(); errorMessageMap.put("message", "表头为空"); excelComments.add(errorMessageMap); apidatas.put("successCount", successCount); apidatas.put("errorCount", errorCount); apidatas.put("errorData", excelComments); return apidatas; } if (CollectionUtils.isEmpty(data)) { Map errorMessageMap = Maps.newHashMap(); errorMessageMap.put("message", "无数据"); excelComments.add(errorMessageMap); apidatas.put("successCount", successCount); apidatas.put("errorCount", errorCount); apidatas.put("errorData", excelComments); return apidatas; } Optional first = taxReportColumnNames.stream().filter(name -> !headers.contains(name)).findFirst(); if (first.isPresent()) { Map errorMessageMap = Maps.newHashMap(); errorMessageMap.put("message", "申报模板异常,缺失" + first.get() + "列,请检查是否为" + incomeCategoryEnum.getDefaultLabel() + "申报模板"); excelComments.add(errorMessageMap); apidatas.put("successCount", successCount); apidatas.put("errorCount", errorCount); apidatas.put("errorData", excelComments); return apidatas; } for (int i = 0; i < data.size(); i++) { String row = "第" + (i + 2) + "行"; boolean isError = false; Map map = data.get(i); Long employeeId = 0L; String username = (String) map.getOrDefault("姓名", ""); String deparmentName = (String) map.getOrDefault("部门", ""); String mobile = (String) map.getOrDefault("手机号", ""); String workcode = (String) map.getOrDefault("工号", ""); if (StringUtils.isEmpty(username) && "0".equals(confValue)) { isError = true; Map errorMessageMap = Maps.newHashMap(); errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(102838, "姓名不能为空")); excelComments.add(errorMessageMap); } else { //筛选导入人员信息可以在人力资源池中匹配到的人员信息 List employeeSameIds = getSalaryEmployeeService(user).matchImportEmployee(salaryEmployees, username, deparmentName, mobile, workcode, null); if (CollectionUtils.isEmpty(employeeSameIds)) { isError = true; Map errorMessageMap = Maps.newHashMap(); errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579, "姓名错误,系统内不存在该姓名")); excelComments.add(errorMessageMap); } else if (employeeSameIds.size() > 1) { //存在离职和在职状态取在职状态 employeeSameIds = employeeSameIds.stream() .filter(e -> UserStatusEnum.getNormalStatus().contains(e.getStatus())) .collect(Collectors.toList()); if (employeeSameIds.size() != 1) { isError = true; Map errorMessageMap = Maps.newHashMap(); errorMessageMap.put("message", row + "员工信息不存在或者存在多个员工"); excelComments.add(errorMessageMap); } else { employeeId = CollectionUtils.isNotEmpty(employeeSameIds) && employeeSameIds.size() == 1 ? employeeSameIds.get(0).getEmployeeId() : null; } } else { employeeId = employeeSameIds.get(0).getEmployeeId(); } } if (isError) { errorCount++; errorDatas.add(map); continue; } successCount++; Map valueMap = Maps.newHashMap(); for (TaxReportColumnPO taxReportColumn : taxReportColumnPOS) { String value = (String) map.getOrDefault(taxReportColumn.getReportColumnName(), ""); valueMap.put(taxReportColumn.getReportColumnDataIndex(), StringUtils.isNotBlank(value) ? value.toString() : Objects.equals(taxReportColumn.getDataType(), SalaryDataTypeEnum.NUMBER.getValue()) ? "0.00" : ""); } if (empDeclarationValueMap.containsKey(employeeId)) { TaxDeclarationValuePO taxDeclarationValue = empDeclarationValueMap.get(employeeId); taxDeclarationValue.setResultValue(valueMap); taxDeclarationValue.setResultValueJson(JsonUtil.toJsonString(valueMap)); taxDeclarationValue.setUpdateTime(new Date()); taxDeclarationValue.setSource(SourceEnum.IMP.getValue()); editList.add(taxDeclarationValue); } else { //新增 TaxDeclarationValuePO taxDeclarationValue = TaxDeclarationValuePO.builder() .id(IdGenerator.generate()) .taxDeclareRecordId(declarationPO.getTaxDeclareRecordId()) .taxDeclarationId(declarationPO.getId()) .employeeType(EmployeeTypeEnum.ORGANIZATION.getValue()) .employeeId(employeeId) .resultValue(valueMap) .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY) .creator(employeeId) .deleteType(DeleteTypeEnum.NOT_DELETED.getValue()) .createTime(now) .updateTime(now) .source(SourceEnum.IMP.getValue()) .build(); addList.add(taxDeclarationValue); } } getTaxDeclarationValueService(user).batchSave(addList); getTaxDeclarationValueService(user).batchEdit(editList); if (incomeCategoryEnum == IncomeCategoryEnum.ONETIME_ANNUAL_BONUS) { TaxDeclareRecordPO declareRecordPO = getTaxDeclareRecordService(user).getById(declarationPO.getTaxDeclareRecordId()); getTaxDeclarationValueService(user).autoAddWagesDeclare(declareRecordPO); } apidatas.put("successCount", successCount); apidatas.put("errorCount", errorCount); apidatas.put("errorData", excelComments); } finally { IOUtils.closeQuietly(fileInputStream); } return apidatas; } }