From ea01cf9278def6c71800a2a1dc8ab129e1b757cb Mon Sep 17 00:00:00 2001 From: xiezw Date: Sat, 14 Sep 2024 09:11:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8D=9F=E8=80=97=E5=88=86=E6=9E=90=E6=8A=A5?= =?UTF-8?q?=E8=A1=A8-20240914?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/core/utils/excel/ExcelUtils.java | 29 ++- .../controller/EnergyLossController.java | 43 +++ .../carbon/energyloss/dto/EnergyLossDTO.java | 35 +++ .../energyloss/dto/EnergyLossInfoDTO.java | 31 +++ .../energyloss/dto/EnergyLossReportParam.java | 37 +++ .../carbon/energyloss/dto/KeyAndCodeDTO.java | 21 ++ .../carbon/energyloss/dto/NameAndCodeDTO.java | 19 ++ .../energyloss/excel/EnergyLossExcel.java | 33 +++ .../energyloss/service/EnergyLossService.java | 15 ++ .../service/impl/EnergyLossServiceImpl.java | 245 ++++++++++++++++++ 10 files changed, 507 insertions(+), 1 deletion(-) create mode 100644 modules/report-analysis/src/main/java/com/thing/carbon/energyloss/controller/EnergyLossController.java create mode 100644 modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossDTO.java create mode 100644 modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossInfoDTO.java create mode 100644 modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossReportParam.java create mode 100644 modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/KeyAndCodeDTO.java create mode 100644 modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/NameAndCodeDTO.java create mode 100644 modules/report-analysis/src/main/java/com/thing/carbon/energyloss/excel/EnergyLossExcel.java create mode 100644 modules/report-analysis/src/main/java/com/thing/carbon/energyloss/service/EnergyLossService.java create mode 100644 modules/report-analysis/src/main/java/com/thing/carbon/energyloss/service/impl/EnergyLossServiceImpl.java diff --git a/common/core/src/main/java/com/thing/common/core/utils/excel/ExcelUtils.java b/common/core/src/main/java/com/thing/common/core/utils/excel/ExcelUtils.java index 70d57e5..9c917c5 100644 --- a/common/core/src/main/java/com/thing/common/core/utils/excel/ExcelUtils.java +++ b/common/core/src/main/java/com/thing/common/core/utils/excel/ExcelUtils.java @@ -16,7 +16,7 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.web.multipart.MultipartFile; @@ -48,6 +48,33 @@ public class ExcelUtils { public static void exportExcel(List list, String title, String sheetName, Class pojoClass, String fileName, HttpServletResponse response){ defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName)); } + public static void exportExcel1(List list, String title, String sheetName, Class pojoClass, String fileName, HttpServletResponse response){ + defaultExport1(list, pojoClass, fileName, response, new ExportParams(title, sheetName)); + } + private static void defaultExport1(List list, Class pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) { + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list); + if (workbook != null) { + // 设置第一列左对齐 + Sheet sheet = workbook.getSheetAt(0); + CellStyle style = workbook.createCellStyle(); + style.setAlignment(HorizontalAlignment.LEFT); + style.setVerticalAlignment(VerticalAlignment.CENTER); + + // 获取第一列列索引 + int firstColumnIndex = 0; + + // 遍历所有行 + for (Row row : sheet) { + Cell cell = row.getCell(firstColumnIndex); + if (cell != null) { + cell.setCellStyle(style); + } + } + + // 下载文件 + downLoadExcel(fileName, response, workbook); + } + } public static void exportExcel(List list, Class pojoClass, String title, String sheetName, String fileName, ExcelType excelType, HttpServletResponse response){ diff --git a/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/controller/EnergyLossController.java b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/controller/EnergyLossController.java new file mode 100644 index 0000000..da6774e --- /dev/null +++ b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/controller/EnergyLossController.java @@ -0,0 +1,43 @@ +package com.thing.carbon.energyloss.controller; + +import com.thing.carbon.energyloss.dto.EnergyLossDTO; +import com.thing.carbon.energyloss.dto.EnergyLossReportParam; +import com.thing.carbon.energyloss.excel.EnergyLossExcel; +import com.thing.carbon.energyloss.service.EnergyLossService; +import com.thing.common.core.utils.excel.ExcelUtils; +import com.thing.common.core.web.response.Result; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + + +@RestController +@RequestMapping("energy/loss") +@Tag(name="能源损耗") +@RequiredArgsConstructor +public class EnergyLossController { + @Autowired + private EnergyLossService energyLossService; + + @PostMapping("report") + @Operation(summary="能源损耗报表") + public Result> energyLossReport(@RequestBody EnergyLossReportParam param) { + List list = energyLossService.energyLossReport(param); + return new Result>().ok(list); + } + + @PostMapping("export") + @Operation(summary="能源损耗报表导出") + public void energyLossReport(@RequestBody EnergyLossReportParam param, HttpServletResponse response){ + List list = energyLossService.getEnergyLossList(param); + ExcelUtils.exportExcel1(list, null, "能源损耗报表", EnergyLossExcel.class, "能源损耗报表.xls", response); + } +} diff --git a/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossDTO.java b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossDTO.java new file mode 100644 index 0000000..ea15f11 --- /dev/null +++ b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossDTO.java @@ -0,0 +1,35 @@ +package com.thing.carbon.energyloss.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@Schema( name= "损耗报表数据") +public class EnergyLossDTO { + + @Schema(description = "能源节点") + private String thingName; + + @Schema(description = "能源code") + private String thingCode; + + @Schema(description = "当前支路能耗") + private BigDecimal currentValue; + + @Schema(description = "下级支路能耗合计") + private BigDecimal lastValue; + + @Schema(description = "差值") + private BigDecimal differenceValue; + + @Schema(description = "相差百分比") + private BigDecimal percentValue; + + @Schema(description = "子项") + private List childs; + + +} diff --git a/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossInfoDTO.java b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossInfoDTO.java new file mode 100644 index 0000000..48cafc2 --- /dev/null +++ b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossInfoDTO.java @@ -0,0 +1,31 @@ +package com.thing.carbon.energyloss.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@Schema( name= "损耗报表数据1") +public class EnergyLossInfoDTO { + + @Schema(description = "能源节点") + private String thingName; + + @Schema(description = "能源code") + private String thingCode; + + @Schema(description = "当前支路能耗") + private BigDecimal currentValue; + + @Schema(description = "下级支路能耗合计") + private BigDecimal lastValue; + + @Schema(description = "差值") + private BigDecimal differenceValue; + + @Schema(description = "相差百分比") + private BigDecimal percentValue; + +} diff --git a/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossReportParam.java b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossReportParam.java new file mode 100644 index 0000000..9c00b3a --- /dev/null +++ b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/EnergyLossReportParam.java @@ -0,0 +1,37 @@ +package com.thing.carbon.energyloss.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.groups.Default; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; + +@Data +@Schema( name= "能源损耗入参") +public class EnergyLossReportParam implements Serializable { + + @Serial + private static final long serialVersionUID = -8868412528182030308L; + + @Schema(description = "开始时间") + private String beginTime; + + @Schema(description = "结束时间") + private String endTime; + + @Schema(description = "标签组名称") + private String labelGroupName; + + @NotNull(message = "根主键不能为空", groups = Default.class) + @Schema(description = "根主键") + private Long rootId; + + @Schema(description = "物属性code类型(hh mm yy),分别对应日月年") + private String thingAttrCodeType; + + @Schema(description = "配置类型 例如:监控分析配置,用量分析配置") + private String configType; + +} diff --git a/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/KeyAndCodeDTO.java b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/KeyAndCodeDTO.java new file mode 100644 index 0000000..a25610d --- /dev/null +++ b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/KeyAndCodeDTO.java @@ -0,0 +1,21 @@ +package com.thing.carbon.energyloss.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +@Schema( name= "属性和物code") +public class KeyAndCodeDTO { + + @Schema(description = "属性key") + private String key; + + @Schema(description = "物code") + private String code; + + + +} diff --git a/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/NameAndCodeDTO.java b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/NameAndCodeDTO.java new file mode 100644 index 0000000..b847600 --- /dev/null +++ b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/dto/NameAndCodeDTO.java @@ -0,0 +1,19 @@ +package com.thing.carbon.energyloss.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema( name= "物名称和物code") +public class NameAndCodeDTO { + + @Schema(description = "物名称") + private String name; + + @Schema(description = "物code") + private String code; + + @Schema(description = "物id") + private Long thingId; + +} diff --git a/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/excel/EnergyLossExcel.java b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/excel/EnergyLossExcel.java new file mode 100644 index 0000000..b84813e --- /dev/null +++ b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/excel/EnergyLossExcel.java @@ -0,0 +1,33 @@ +package com.thing.carbon.energyloss.excel; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.annotation.write.style.HeadRowHeight; +import lombok.Data; + +import java.math.BigDecimal; + + +@Data +public class EnergyLossExcel { + + @Excel(name = "能源节点", orderNum = "1", width = 30) + private String thingName; + +// @Excel(name = "能源code", orderNum = "1") +// private String thingCode; + + @Excel(name = "当前支路能耗", orderNum = "2", width = 30) + private BigDecimal currentValue; + + @Excel(name = "下级支路能耗合计", orderNum = "3", width = 30) + private BigDecimal lastValue; + + @Excel(name = "差值", orderNum = "4", width = 30) + private BigDecimal differenceValue; + + @Excel(name = "相差百分比(%)", orderNum = "5", width = 30) + private BigDecimal percentValue; + +} diff --git a/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/service/EnergyLossService.java b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/service/EnergyLossService.java new file mode 100644 index 0000000..0bab309 --- /dev/null +++ b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/service/EnergyLossService.java @@ -0,0 +1,15 @@ +package com.thing.carbon.energyloss.service; + +import com.thing.carbon.energyloss.dto.EnergyLossDTO; +import com.thing.carbon.energyloss.dto.EnergyLossInfoDTO; +import com.thing.carbon.energyloss.dto.EnergyLossReportParam; +import com.thing.carbon.energyloss.excel.EnergyLossExcel; + +import java.util.List; + +public interface EnergyLossService { + + List energyLossReport(EnergyLossReportParam param); + + List getEnergyLossList(EnergyLossReportParam param); +} diff --git a/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/service/impl/EnergyLossServiceImpl.java b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/service/impl/EnergyLossServiceImpl.java new file mode 100644 index 0000000..fe4eea6 --- /dev/null +++ b/modules/report-analysis/src/main/java/com/thing/carbon/energyloss/service/impl/EnergyLossServiceImpl.java @@ -0,0 +1,245 @@ +package com.thing.carbon.energyloss.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import com.mybatisflex.core.query.QueryWrapper; +import com.thing.carbon.energyloss.dto.EnergyLossDTO; +import com.thing.carbon.energyloss.dto.EnergyLossReportParam; +import com.thing.carbon.energyloss.excel.EnergyLossExcel; +import com.thing.carbon.energyloss.service.EnergyLossService; +import com.thing.common.core.utils.DateTimeUtils; +import com.thing.common.data.tskv.TsKvDTO; +import com.thing.common.tskv.service.TsKvService; +import com.thing.device.source.entity.IotThingSourceEntity; +import com.thing.device.source.mapper.IotThingSourceMapper; +import com.thing.thing.context.service.ThingManageContextService; +import com.thing.thing.relation.detail.dto.IotThingRelationDetailDTO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +public class EnergyLossServiceImpl implements EnergyLossService { + + @Autowired + private ThingManageContextService thingManageContextService; + + @Autowired + private TsKvService tsKvService; + + @Resource + private IotThingSourceMapper iotThingSourceDao; + + @Override + public List energyLossReport(EnergyLossReportParam param) { + List result = new ArrayList<>(); + String beginTime = param.getBeginTime(); + String endTime = param.getEndTime(); + Long beginTs = DateTimeUtils.dateToStamp(beginTime); + Long endTs = DateTimeUtils.dateToStamp(endTime); + Long rootId = param.getRootId(); + String labelGroupName = param.getLabelGroupName(); + if (rootId==null){ + return result; + } + //根据rootId获取该结构下所有的物 + Optional> relationDetailDTOS = thingManageContextService.findRootDetailAllByRootId(rootId); + List relations = relationDetailDTOS.orElseGet(Collections::emptyList).stream().toList(); + if (CollectionUtil.isEmpty(relations)){ + return result; + } + List codes = relationDetailDTOS.orElseGet(Collections::emptyList).stream().map(IotThingRelationDetailDTO::getToCode).toList(); + Map> multiMap = new HashMap<>(); + //根据物code和标签组名称遍历查询对应配置的属性key + if (CollectionUtil.isNotEmpty(codes)){ + for (String code:codes){ + List iotThingSourceEntities = iotThingSourceDao.selectListExt(QueryWrapper.create() + .eq(IotThingSourceEntity::getThingCode, code) + .eq(IotThingSourceEntity::getRootId, rootId) + .eq(IotThingSourceEntity::getConfigType, param.getConfigType()) + .eq(IotThingSourceEntity::getThingAttrGroup,labelGroupName) + .eq(IotThingSourceEntity::getStartStatus,"0")); + String key=null; + if (CollectionUtil.isNotEmpty(iotThingSourceEntities)){ + key = iotThingSourceEntities.get(0).getThingAttrCode(); + } + List keys = new ArrayList<>(); + keys.add(key); + if (StringUtils.isNotBlank(key)){ + multiMap.put(code,keys); + } + } + } + + //获取物 对应时间的能耗值 + Map codeAndValueMap = new HashMap<>(); + List dataList = tsKvService.findTsKvByMultiMap(multiMap, beginTs, endTs, Boolean.FALSE); + if (CollectionUtil.isNotEmpty(dataList)){ + codeAndValueMap = dataList.stream() + .filter(dto -> dto.getVal() != null && !dto.getVal().isEmpty()) + .collect(Collectors.groupingBy( + TsKvDTO::getThingCode, + Collectors.mapping( + dto -> new BigDecimal(dto.getVal()), + Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)))); + } + + //处理结构,根据fromId分组,并排序 + Map> fromIdMap = relations.stream() + .collect(Collectors.groupingBy(IotThingRelationDetailDTO::getFromId)); + fromIdMap.forEach((fromId, list) -> + list.sort(Comparator.comparing(IotThingRelationDetailDTO::getSort)) + ); + + //组装数据并赋值 + result = buildEnergyLossDTOListRecursive(fromIdMap, rootId,codeAndValueMap); + return result; + } + + @Override + public List getEnergyLossList(EnergyLossReportParam param) { + List result = new ArrayList<>(); + List result1; + String beginTime = param.getBeginTime(); + String endTime = param.getEndTime(); + Long beginTs = DateTimeUtils.dateToStamp(beginTime); + Long endTs = DateTimeUtils.dateToStamp(endTime); + Long rootId = param.getRootId(); + String labelGroupName = param.getLabelGroupName(); + if (rootId==null){ + return result; + } + //根据rootId获取该结构下所有的物 + Optional> relationDetailDTOS = thingManageContextService.findRootDetailAllByRootId(rootId); + List relations = relationDetailDTOS.orElseGet(Collections::emptyList).stream().toList(); + if (CollectionUtil.isEmpty(relations)){ + return result; + } + List codes = relationDetailDTOS.orElseGet(Collections::emptyList).stream().map(IotThingRelationDetailDTO::getToCode).toList(); + Map> multiMap = new HashMap<>(); + //根据物code和标签组名称遍历查询对应配置的属性key + if (CollectionUtil.isNotEmpty(codes)){ + for (String code:codes){ + List iotThingSourceEntities = iotThingSourceDao.selectListExt(QueryWrapper.create() + .eq(IotThingSourceEntity::getThingCode, code) + .eq(IotThingSourceEntity::getRootId, rootId) + .eq(IotThingSourceEntity::getConfigType, param.getConfigType()) + .eq(IotThingSourceEntity::getThingAttrGroup,labelGroupName) + .eq(IotThingSourceEntity::getStartStatus,"0")); + String key=null; + if (CollectionUtil.isNotEmpty(iotThingSourceEntities)){ + key = iotThingSourceEntities.get(0).getThingAttrCode(); + } + List keys = new ArrayList<>(); + keys.add(key); + if (StringUtils.isNotBlank(key)){ + multiMap.put(code,keys); + } + } + } + + //获取物 对应时间的能耗值 + Map codeAndValueMap = new HashMap<>(); + List dataList = tsKvService.findTsKvByMultiMap(multiMap, beginTs, endTs, Boolean.FALSE); + if (CollectionUtil.isNotEmpty(dataList)){ + codeAndValueMap = dataList.stream() + .filter(dto -> dto.getVal() != null && !dto.getVal().isEmpty()) + .collect(Collectors.groupingBy( + TsKvDTO::getThingCode, + Collectors.mapping( + dto -> new BigDecimal(dto.getVal()), + Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)))); + } + + //处理结构,根据fromId分组,并排序 + Map> fromIdMap = relations.stream() + .collect(Collectors.groupingBy(IotThingRelationDetailDTO::getFromId)); + fromIdMap.forEach((fromId, list) -> + list.sort(Comparator.comparing(IotThingRelationDetailDTO::getSort)) + ); + + //组装数据并赋值 + result1 = buildEnergyLossDTOListRecursive(fromIdMap, rootId,codeAndValueMap); + int depth=0; + processWithHierarchy(result,result1,depth); + return result; + } + + private String getIndentedName(String name, int depth) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < depth; i++) { + sb.append(" "); // Four spaces for each level of indentation + } + sb.append(name); + return sb.toString(); + } + private EnergyLossExcel convertToEnergyLossInfoDTO(EnergyLossDTO energyLossDTO,int depth) { + if (energyLossDTO == null) { + return null; + } + + EnergyLossExcel energyLossInfoDTO = new EnergyLossExcel(); + energyLossInfoDTO.setThingName(getIndentedName(energyLossDTO.getThingName(),depth)); +// energyLossInfoDTO.setThingCode(energyLossDTO.getThingCode()); + energyLossInfoDTO.setCurrentValue(energyLossDTO.getCurrentValue()); + energyLossInfoDTO.setLastValue(energyLossDTO.getLastValue()); + energyLossInfoDTO.setDifferenceValue(energyLossDTO.getDifferenceValue()); + energyLossInfoDTO.setPercentValue(energyLossDTO.getPercentValue()); + + return energyLossInfoDTO; + } + + public List processWithHierarchy(List result,List energyLossDTOList,int depth) { + for (EnergyLossDTO dto : energyLossDTOList) { + EnergyLossExcel infoDTO = convertToEnergyLossInfoDTO(dto,depth); + result.add(infoDTO); + + // Recursively process child items + if (dto.getChilds() != null) { + processWithHierarchy(result,dto.getChilds(),depth + 1); + } + } + + return result; + } + + private List buildEnergyLossDTOListRecursive( + Map> fromIdMap, + Long rootId,Map codeAndValueMap) { + List childDataList = fromIdMap.getOrDefault(rootId, Collections.emptyList()); + + List dtos = new ArrayList<>(); + for (IotThingRelationDetailDTO data : childDataList) { + EnergyLossDTO dto = new EnergyLossDTO(); + dto.setThingName(data.getToName()); + dto.setThingCode(data.getToCode()); + + BigDecimal currentValue = codeAndValueMap.getOrDefault(data.getToCode(), BigDecimal.ZERO); + dto.setCurrentValue(currentValue); + + List children = buildEnergyLossDTOListRecursive(fromIdMap,data.getToId(),codeAndValueMap); + dto.setChilds(children); + + BigDecimal lastValue = children.stream() + .map(EnergyLossDTO::getCurrentValue) + .reduce(BigDecimal.ZERO, BigDecimal::add); + dto.setLastValue(lastValue); + BigDecimal differenceValue = currentValue.subtract(lastValue); + BigDecimal percentValue = currentValue.compareTo(BigDecimal.ZERO) == 0 + ? BigDecimal.ZERO + : differenceValue.divide(currentValue, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)); + dto.setDifferenceValue(differenceValue); + dto.setPercentValue(percentValue); + dtos.add(dto); + } + return dtos; + } +}