diff --git a/src/com/engine/salary/entity/salaryacct/param/SalaryAcctResultQueryParam.java b/src/com/engine/salary/entity/salaryacct/param/SalaryAcctResultQueryParam.java index 5f5749ac7..ef2eb6719 100644 --- a/src/com/engine/salary/entity/salaryacct/param/SalaryAcctResultQueryParam.java +++ b/src/com/engine/salary/entity/salaryacct/param/SalaryAcctResultQueryParam.java @@ -73,6 +73,9 @@ public class SalaryAcctResultQueryParam extends BaseQueryParam { //其他条件 private List otherConditions; + // 年度 + private String year; + @Data @NoArgsConstructor diff --git a/src/com/engine/salary/service/SalaryAcctResultService.java b/src/com/engine/salary/service/SalaryAcctResultService.java index ea6c2fe30..ee6150f5a 100644 --- a/src/com/engine/salary/service/SalaryAcctResultService.java +++ b/src/com/engine/salary/service/SalaryAcctResultService.java @@ -7,6 +7,7 @@ import com.engine.salary.entity.salaryacct.dto.SalaryAcctResultListColumnDTO; import com.engine.salary.entity.salaryacct.param.*; import com.engine.salary.entity.salaryacct.po.SalaryAcctResultPO; import com.engine.salary.util.page.PageInfo; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.util.Collection; import java.util.List; @@ -217,4 +218,13 @@ public interface SalaryAcctResultService { * @param param */ void batchUpdate(SalaryAcctResultBatchUpdateParam param); + + /** + * 月度薪资环比统计报表(本月、上月维度比较) + * @param year + * @return + */ + Map ydxzhbReportList(String year); + + XSSFWorkbook exportYdxzhbReport(String year); } diff --git a/src/com/engine/salary/service/impl/SalaryAcctResultServiceImpl.java b/src/com/engine/salary/service/impl/SalaryAcctResultServiceImpl.java index 67e873658..60186d028 100644 --- a/src/com/engine/salary/service/impl/SalaryAcctResultServiceImpl.java +++ b/src/com/engine/salary/service/impl/SalaryAcctResultServiceImpl.java @@ -1,5 +1,6 @@ package com.engine.salary.service.impl; +import com.cloudstore.eccom.pc.table.WeaTableColumn; import com.engine.common.util.ServiceUtil; import com.engine.core.impl.Service; import com.engine.hrmelog.entity.dto.LoggerContext; @@ -51,6 +52,7 @@ 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.excel.ExcelUtilPlus; import com.engine.salary.util.page.PageInfo; import com.engine.salary.util.page.SalaryPageUtil; import com.engine.salary.util.valid.ValidUtil; @@ -64,12 +66,15 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.util.StopWatch; import weaver.general.BaseBean; import weaver.hrm.User; +import java.io.UnsupportedEncodingException; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.*; import java.util.concurrent.BlockingDeque; import java.util.concurrent.CountDownLatch; @@ -1245,4 +1250,108 @@ public class SalaryAcctResultServiceImpl extends Service implements SalaryAcctRe } } + + @Override + public Map ydxzhbReportList(String year) { + if (!NumberUtils.isCreatable(year)) { + throw new SalaryRunTimeException("请输入年份"); + } + Map resultMap = new HashMap<>(); + // 获取能够管理的义务人 + Collection taxAgentPOS = getTaxAgentService(user).listAllTaxAgentsAsAdmin(Long.valueOf(user.getUID())); + List canManageTaxAgentIds = taxAgentPOS.stream().map(TaxAgentPO::getId).collect(Collectors.toList()); + List salarySobPOS = getSalarySobService(user).listByTaxAgentIds(canManageTaxAgentIds); + List salarySobIds = salarySobPOS.stream().map(SalarySobPO::getId).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(salarySobIds)) { + return resultMap; + } + // 获取已归档的核算记录 + LocalDateRange dateRange = LocalDateRange.builder().fromDate(SalaryDateUtil.stringToDate(year + "-01-01")).endDate(SalaryDateUtil.stringToDate(year + "-12-01")).build(); + List salaryAcctRecordPOS = getSalaryAcctRecordService(user).listBySalarySobIdsAndSalaryMonth(salarySobIds, dateRange); + salaryAcctRecordPOS = salaryAcctRecordPOS.stream().filter(record -> record.getStatus() > SalaryAcctRecordStatusEnum.NOT_ARCHIVED.getValue()).collect(Collectors.toList()); + List salaryAcctRecordIds = salaryAcctRecordPOS.stream().map(SalaryAcctRecordPO::getId).collect(Collectors.toList()); + + // 获取需要统计哪些薪资项目 + List salaryItemList = getSalaryItemService(user).listAll(); + Map salaryItemMap = SalaryEntityUtil.convert2Map(salaryItemList, SalaryItemPO::getName); + BaseBean baseBean = new BaseBean(); + String itemStr = baseBean.getPropValue("omlSalaryReport", "ydxzhbtj_item"); + List itemList = new ArrayList<>(); + try { + itemList = Arrays.stream(new String(itemStr.getBytes("ISO-8859-1"), "utf-8").split(",")) + .map(itemName -> salaryItemMap.get(itemName)) + .filter(item -> item != null) + .collect(Collectors.toList()); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + // 查询薪资核算结果 + List itemIdList = itemList.stream().map(SalaryItemPO::getId).collect(Collectors.toList()); + List resultPOList = getSalaryAcctResultService(user).listBySalaryAcctRecordIdsAndSalaryItemIds(salaryAcctRecordIds, itemIdList); + Map> resultGroupByAcctItemId = SalaryEntityUtil.group2Map(resultPOList, SalaryAcctResultPO::getSalaryItemId); + // 核算记录id根据薪资所属月份分组 + Map> salaryAcctRecordMapByMonth = SalaryEntityUtil.group2Map(salaryAcctRecordPOS, record -> SalaryDateUtil.getFormatYearMonth(record.getSalaryMonth()), SalaryAcctRecordPO::getId); + List sortedDateList = salaryAcctRecordMapByMonth.keySet().stream().sorted((k1, k2) -> k1.compareTo(k2)).collect(Collectors.toList()); + + // 构建表头 + List columns = new ArrayList<>(); + columns.add(new WeaTableColumn("150px", "项目(单位-万元)", "salaryItemName")); + for (String dateStr : sortedDateList) { + columns.add(new WeaTableColumn("150px", dateStr.substring(5) + "月", dateStr)); + } + columns.add(new WeaTableColumn("150px", "上月对比", "compareWithLastMonth")); + resultMap.put("columns", columns); + + List> dataList = new ArrayList<>(); + Map rjfhjMap = new HashMap<>(); + rjfhjMap.put("salaryItemName", "人件费合计"); + for (String salaryMonthStr : sortedDateList) { + rjfhjMap.put(salaryMonthStr, ""); + } + dataList.add(rjfhjMap); + for (SalaryItemPO item : itemList) { + List resultList = resultGroupByAcctItemId.getOrDefault(item.getId(), Collections.emptyList()); + Map monthResult = new HashMap<>(); + for (String salaryMonthStr : sortedDateList) { + // 获取该月份下有哪些核算记录id + Set recordIds = salaryAcctRecordMapByMonth.getOrDefault(salaryMonthStr, Collections.emptySet()); + BigDecimal resultValue = resultList.stream().filter(result -> recordIds.contains(result.getSalaryAcctRecordId())) + .map(resultPO -> SalaryEntityUtil.empty2Zero(resultPO.getResultValue())) + .reduce(new BigDecimal("0"), BigDecimal::add); + // 存储该薪资项目每个月的合计值 + monthResult.put(salaryMonthStr, resultValue); + } + // 计算上月对比 + if (CollectionUtils.isNotEmpty(sortedDateList) && sortedDateList.size() > 2) { + BigDecimal thisMonthValue = (BigDecimal) monthResult.get(sortedDateList.get(sortedDateList.size() - 1)); + BigDecimal lastMonthValue = (BigDecimal) monthResult.get(sortedDateList.get(sortedDateList.size() - 2)); + BigDecimal compareValue = (thisMonthValue.subtract(lastMonthValue)).divide(lastMonthValue, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, BigDecimal.ROUND_HALF_UP); + monthResult.put("compareWithLastMonth", compareValue.toString() + "%"); + } + monthResult.put("salaryItemName", item.getName()); + dataList.add(monthResult); + } + + resultMap.put("data", dataList); + return resultMap; + } + + @Override + public XSSFWorkbook exportYdxzhbReport(String year) { + Map resultMap = ydxzhbReportList(year); + List> dataList = (List>) resultMap.get("data"); + List columns = (List) resultMap.get("columns"); + + List> list = new ArrayList<>(); + // 表头 + list.add(columns.stream().map(WeaTableColumn::getText).collect(Collectors.toList())); + for (Map dataMap : dataList) { + List row = new ArrayList<>(); + for (WeaTableColumn column : columns) { + row.add(dataMap.getOrDefault(column.getColumn(), "")); + } + list.add(row); + } + return ExcelUtilPlus.genWorkbookV24oml(list, year + "年月度薪资环比统计报表"); + } } \ No newline at end of file diff --git a/src/com/engine/salary/util/excel/ExcelUtilPlus.java b/src/com/engine/salary/util/excel/ExcelUtilPlus.java index 9da402ce7..8a534a7a7 100644 --- a/src/com/engine/salary/util/excel/ExcelUtilPlus.java +++ b/src/com/engine/salary/util/excel/ExcelUtilPlus.java @@ -304,6 +304,92 @@ public class ExcelUtilPlus { } return workbook; } + public static XSSFWorkbook genWorkbookV24oml(List> rowList, String sheetName) { + XSSFWorkbook workbook = new XSSFWorkbook(); + + // 设置title样式 + XSSFCellStyle titleCellStyle = workbook.createCellStyle(); + XSSFFont titleFont = workbook.createFont(); + titleFont.setBold(true); + titleFont.setFontName("仿宋"); + titleFont.setFontHeightInPoints((short) 15); + titleCellStyle.setFont(titleFont); + titleCellStyle.setAlignment(HorizontalAlignment.CENTER); + titleCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());//背景色 + titleCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); + titleCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); + titleCellStyle.setBorderLeft(BorderStyle.THIN); + titleCellStyle.setBorderRight(BorderStyle.THIN); + titleCellStyle.setBorderTop(BorderStyle.THIN); + titleCellStyle.setBorderBottom(BorderStyle.THIN); + + + // 设置主体样式 + XSSFCellStyle cellStyle = workbook.createCellStyle(); + XSSFFont font = workbook.createFont(); + font.setFontName("宋体"); + font.setFontHeightInPoints((short) 10);// 设置字体大小 + cellStyle.setFont(font);// 选择需要用到的字体格式 + cellStyle.setWrapText(true); + cellStyle.setBorderLeft(BorderStyle.THIN); + cellStyle.setBorderRight(BorderStyle.THIN); + cellStyle.setBorderTop(BorderStyle.THIN); + cellStyle.setBorderBottom(BorderStyle.THIN); + + XSSFSheet sheet = workbook.createSheet(sheetName); + //自适应宽度 + sheet.autoSizeColumn(0, true); + //默认列宽 + sheet.setDefaultColumnWidth(20); + //默认行高 + sheet.setDefaultRowHeightInPoints(18); + //遍历设置列宽 + List header = rowList.get(0); + for (int i = 0; i < header.size(); i++) { + sheet.setColumnWidth(i, Math.min(255, Math.max(12, header.get(i).toString().length() * 4)) * 256); + } + for (int rowIndex = 0; rowIndex < rowList.size(); rowIndex++) { + List infoList = rowList.get(rowIndex); + XSSFRow row = sheet.createRow(rowIndex); + float height = 18; + float finalHeight = 18; + + for (int cellIndex = 0; cellIndex < infoList.size(); cellIndex++) { + XSSFCell cell = row.createCell(cellIndex); + if (rowIndex == 0) { + cell.setCellStyle(titleCellStyle); + } else { + cell.setCellStyle(cellStyle); + } + Object o = infoList.get(cellIndex); + if (o instanceof String) { + cell.setCellType(CellType.STRING); + cell.setCellValue(String.valueOf(o)); + } else if (o instanceof BigDecimal) { + cell.setCellType(CellType.NUMERIC); + cell.setCellValue(o == null ? 0 : ((BigDecimal) o).doubleValue()); + } else if (o instanceof Boolean) { + cell.setCellType(CellType.BOOLEAN); + cell.setCellValue(String.valueOf(o)); + } else if (o instanceof Date) { + cell.setCellType(CellType.STRING); + cell.setCellValue(SalaryDateUtil.getFormatLocalDate((Date) o)); + } else { + cell.setCellType(CellType.STRING); + cell.setCellValue(o == null ? "" : o.toString()); + } + + //判断是否要调整高度 + int width = sheet.getColumnWidth(cellIndex) / 256; + finalHeight = getFinalHeight(o, width, finalHeight, height); + } + if (rowIndex == 1) { + sheet.addMergedRegion(new CellRangeAddress(1, 1, 1, header.size()-1)); + } + row.setHeightInPoints(finalHeight); + } + return workbook; + } public static XSSFWorkbook genWorkbookV2(List> rowList, String sheetName, List comments) { diff --git a/src/com/engine/salary/web/SalaryAcctController.java b/src/com/engine/salary/web/SalaryAcctController.java index a196d53ef..fc15d1d2c 100644 --- a/src/com/engine/salary/web/SalaryAcctController.java +++ b/src/com/engine/salary/web/SalaryAcctController.java @@ -36,6 +36,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM; + /** * 薪资核算 *

Copyright: Copyright (c) 2022

@@ -270,7 +272,7 @@ public class SalaryAcctController { */ @GET @Path("/acctemployee/export") - @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Produces(APPLICATION_OCTET_STREAM) public Response exportSalaryAcctEmployee(@Context HttpServletRequest request, @Context HttpServletResponse response) { try { SalaryAcctEmployeeQueryParam param = buildSalaryAcctEmployeeQueryParam(request); @@ -340,7 +342,7 @@ public class SalaryAcctController { */ @GET @Path("/reducedemployee/export") - @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Produces(APPLICATION_OCTET_STREAM) public Response exportReducedEmployee(@Context HttpServletRequest request, @Context HttpServletResponse response) { try { SalaryAcctEmployeeQueryParam param = buildSalaryAcctEmployeeQueryParam(request); @@ -371,7 +373,7 @@ public class SalaryAcctController { */ @GET @Path("/addedemployee/export") - @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Produces(APPLICATION_OCTET_STREAM) public Response exportAddedEmployee(@Context HttpServletRequest request, @Context HttpServletResponse response) { try { SalaryAcctEmployeeQueryParam param = buildSalaryAcctEmployeeQueryParam(request); @@ -510,7 +512,7 @@ public class SalaryAcctController { //导出核算结果 @GET @Path("/acctresult/export") - @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Produces(APPLICATION_OCTET_STREAM) public Response exportSalaryAcctResult(@Context HttpServletRequest request, @Context HttpServletResponse response) { try { SalaryAcctResultQueryParam param = new SalaryAcctResultQueryParam(); @@ -538,7 +540,7 @@ public class SalaryAcctController { //导出核算结果(自定义导出字段) @GET @Path("/acctresult/exportWithCustomFields") - @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Produces(APPLICATION_OCTET_STREAM) public Response exportSalaryAcctResultWithCustomFields(@Context HttpServletRequest request, @Context HttpServletResponse response) { try { SalaryAcctResultQueryParam param = new SalaryAcctResultQueryParam(); @@ -645,7 +647,7 @@ public class SalaryAcctController { //导出导入模板 @GET @Path("/acctresult/importtemplate/export") - @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Produces(APPLICATION_OCTET_STREAM) public Response exportImportTemplate(@Context HttpServletRequest request, @Context HttpServletResponse response) { try { SalaryAcctImportTemplateParam param = new SalaryAcctImportTemplateParam(); @@ -790,7 +792,7 @@ public class SalaryAcctController { //导出线上线下对比结果 @GET @Path("/comparisonresult/export") - @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Produces(APPLICATION_OCTET_STREAM) public Response exportComparisonResult(@Context HttpServletRequest request, @Context HttpServletResponse response) { try { SalaryComparisonResultQueryParam param = new SalaryComparisonResultQueryParam(); @@ -879,7 +881,7 @@ public class SalaryAcctController { //线下对比结果导入模板导出 @GET @Path("/comparisonresult/importtemplate/export") - @Produces(MediaType.APPLICATION_OCTET_STREAM) + @Produces(APPLICATION_OCTET_STREAM) public Response exportComparisonResultTemplate(@Context HttpServletRequest request, @Context HttpServletResponse response) { try { @@ -928,4 +930,45 @@ public class SalaryAcctController { } /**********************************线下对比 end*********************************/ -} + + /**********************************欧姆龙月度薪资环比统计报表 start ********/ + // 欧姆龙月度薪资环比统计报表 + @POST + @Path("/oml/ydxzhbReportList") + @Produces(MediaType.APPLICATION_JSON) + public String ydxzhbReportList(@Context HttpServletRequest request, @Context HttpServletResponse response, @RequestBody SalaryAcctResultQueryParam param) { + User user = HrmUserVarify.getUser(request, response); + return new ResponseResult>(user).run(getSalaryAcctResultWrapper(user)::ydxzhbReportList, param.getYear()); + } + + // 导出欧姆龙月度薪资环比统计报表 + @GET + @Path("/oml/exportYdxzhbReport") + @Produces(APPLICATION_OCTET_STREAM) + public Response exportYdxzhbReport(@Context HttpServletRequest request, @Context HttpServletResponse response) { + try { + String year = request.getParameter("year"); + User user = HrmUserVarify.getUser(request, response); + XSSFWorkbook workbook = getSalaryAcctResultWrapper(user).exportYdxzhbReport(year); + String time = LocalDate.now().toString(); + String fileName = year + "年度月度薪资环比统计报表" + time; + try { + fileName = URLEncoder.encode(fileName + ".xlsx", "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + StreamingOutput output = outputStream -> { + workbook.write(outputStream); + outputStream.flush(); + }; + response.setContentType("application/octet-stream"); + return Response.ok(output).header("Content-disposition", "attachment;filename=" + fileName).header("Cache-Control", "no-cache").build(); + } catch (Exception e) { + log.error("欧姆龙月度薪资环比统计报表导出异常", e); + throw e; + } + } + + /**********************************欧姆龙月度薪资环比统计报表 end ********/ + +} \ No newline at end of file diff --git a/src/com/engine/salary/wrapper/SalaryAcctResultWrapper.java b/src/com/engine/salary/wrapper/SalaryAcctResultWrapper.java index 5bd00b417..f5dc00b60 100644 --- a/src/com/engine/salary/wrapper/SalaryAcctResultWrapper.java +++ b/src/com/engine/salary/wrapper/SalaryAcctResultWrapper.java @@ -23,6 +23,7 @@ import com.engine.salary.wrapper.proxy.SalaryAcctResultWrapperProxy; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.math.NumberUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import weaver.hrm.User; import java.math.BigDecimal; @@ -278,6 +279,19 @@ public class SalaryAcctResultWrapper extends Service implements SalaryAcctResult getSalaryAcctResultService(user).batchUpdate(param); } + /** + * 月度薪资环比统计报表(本月、上月维度比较) + * @param year + * @return + */ + public Map ydxzhbReportList(String year) { + return getSalaryAcctResultService(user).ydxzhbReportList(year); + } + + public XSSFWorkbook exportYdxzhbReport(String year) { + return getSalaryAcctResultService(user).exportYdxzhbReport(year); + } + /** * 薪资核算-校验 *