refactor: aggregate storage dashboard data in java
| | |
| | | int upsertDaily(@Param("stationId") Long stationId, @Param("rows") List<EmindIncomeHistoryDto> rows, |
| | | @Param("syncedAt") LocalDateTime syncedAt); |
| | | List<Map<String, Object>> selectStations(); |
| | | Map<String, Object> selectOverview(@Param("stationId") Long stationId, @Param("day") LocalDate day); |
| | | List<Map<String, Object>> selectHistory(@Param("stationId") Long stationId, @Param("period") String period, |
| | | @Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate); |
| | | List<Map<String, Object>> selectCurve(@Param("stationId") Long stationId); |
| | | List<Map<String, Object>> selectSnapshotRows(@Param("stationId") Long stationId); |
| | | List<Map<String, Object>> selectDailyRows(@Param("stationId") Long stationId, |
| | | @Param("startDate") LocalDate startDate, |
| | | @Param("endDate") LocalDate endDate); |
| | | List<Map<String, Object>> selectCurveRows(@Param("stationId") Long stationId); |
| | | List<Map<String, Object>> selectEnergyBlockRows(@Param("stationId") Long stationId); |
| | | } |
| | |
| | | import com.ruoyi.other.emind.dto.EmindDashboardQuery; |
| | | import com.ruoyi.other.emind.mapper.EmindStorageDashboardMapper; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDate; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | |
| | | @Service |
| | | public class EmindStorageDashboardService { |
| | | private final EmindStorageDashboardMapper mapper; |
| | | public EmindStorageDashboardService(EmindStorageDashboardMapper mapper) { this.mapper=mapper; } |
| | | public List<Map<String,Object>> stations() { return mapper.selectStations(); } |
| | | public Map<String,Object> overview(EmindDashboardQuery query) { |
| | | LocalDate end=query.getEndDate()==null?LocalDate.now():query.getEndDate(); |
| | | String period=query.getPeriod()==null?"DAY":query.getPeriod().toUpperCase(); |
| | | LocalDate start=query.getStartDate(); |
| | | if (start==null) start="YEAR".equals(period)?end.withDayOfYear(1):("MONTH".equals(period)?end.withDayOfMonth(1):end.minusDays(6)); |
| | | Map<String,Object> result=new LinkedHashMap<>(); |
| | | result.put("summary", mapper.selectOverview(query.getStationId(), LocalDate.now().minusDays(1))); |
| | | result.put("history", completeHistory(mapper.selectHistory(query.getStationId(), period, start, end), period, start, end)); |
| | | result.put("curve", mapper.selectCurve(query.getStationId())); |
| | | |
| | | public EmindStorageDashboardService(EmindStorageDashboardMapper mapper) { this.mapper = mapper; } |
| | | |
| | | public List<Map<String, Object>> stations() { return mapper.selectStations(); } |
| | | |
| | | public Map<String, Object> overview(EmindDashboardQuery query) { |
| | | LocalDate end = query.getEndDate() == null ? LocalDate.now() : query.getEndDate(); |
| | | String period = query.getPeriod() == null ? "DAY" : query.getPeriod().toUpperCase(); |
| | | LocalDate start = query.getStartDate(); |
| | | if (start == null) start = "YEAR".equals(period) ? end.withDayOfYear(1) |
| | | : ("MONTH".equals(period) ? end.withDayOfMonth(1) : end.minusDays(6)); |
| | | List<Map<String, Object>> dailyRows = mapper.selectDailyRows(query.getStationId(), start, end); |
| | | LocalDate yesterday = LocalDate.now().minusDays(1); |
| | | List<Map<String, Object>> yesterdayRows = start.equals(yesterday) && end.equals(yesterday) |
| | | ? dailyRows : mapper.selectDailyRows(query.getStationId(), yesterday, yesterday); |
| | | Map<String, Object> result = new LinkedHashMap<>(); |
| | | result.put("summary", summarize(mapper.selectSnapshotRows(query.getStationId()), yesterdayRows, yesterday, |
| | | mapper.selectEnergyBlockRows(query.getStationId()))); |
| | | result.put("history", completeHistory(dailyRows, period, start, end)); |
| | | result.put("curve", summarizeCurve(mapper.selectCurveRows(query.getStationId()))); |
| | | return result; |
| | | } |
| | | |
| | | private List<Map<String, Object>> completeHistory(List<Map<String, Object>> history, String period, |
| | | LocalDate start, LocalDate end) { |
| | | private Map<String, Object> summarize(List<Map<String, Object>> snapshots, List<Map<String, Object>> dailyRows, |
| | | LocalDate yesterday, List<Map<String, Object>> blocks) { |
| | | BigDecimal incomeSum = BigDecimal.ZERO; |
| | | BigDecimal chargedEnergySum = BigDecimal.ZERO; |
| | | BigDecimal dischargedEnergySum = BigDecimal.ZERO; |
| | | BigDecimal realTimePower = BigDecimal.ZERO; |
| | | BigDecimal surplusEnergy = BigDecimal.ZERO; |
| | | BigDecimal capacity = BigDecimal.ZERO; |
| | | BigDecimal totalSoc = BigDecimal.ZERO; |
| | | BigDecimal elinkTotal = BigDecimal.ZERO; |
| | | BigDecimal elinkOnline = BigDecimal.ZERO; |
| | | Object syncedAt = null; |
| | | for (Map<String, Object> row : snapshots) { |
| | | incomeSum = incomeSum.add(decimal(row.get("incomeSum"))); |
| | | chargedEnergySum = chargedEnergySum.add(decimal(row.get("chargedEnergySum"))); |
| | | dischargedEnergySum = dischargedEnergySum.add(decimal(row.get("dischargedEnergySum"))); |
| | | realTimePower = realTimePower.add(decimal(row.get("realTimePower"))); |
| | | surplusEnergy = surplusEnergy.add(decimal(row.get("surplusEnergy"))); |
| | | capacity = capacity.add(decimal(row.get("capacity"))); |
| | | totalSoc = totalSoc.add(decimal(row.get("soc"))); |
| | | elinkTotal = elinkTotal.add(decimal(row.get("elinkTotal"))); |
| | | elinkOnline = elinkOnline.add(decimal(row.get("elinkOnline"))); |
| | | if (row.get("syncedAt") != null) syncedAt = row.get("syncedAt"); |
| | | } |
| | | Map<String, Object> summary = new LinkedHashMap<>(); |
| | | summary.put("incomeSum", incomeSum); |
| | | summary.put("chargedEnergySum", chargedEnergySum); |
| | | summary.put("dischargedEnergySum", dischargedEnergySum); |
| | | summary.put("realTimePower", realTimePower); |
| | | summary.put("surplusEnergy", surplusEnergy); |
| | | summary.put("capacity", capacity); |
| | | summary.put("soc", capacity.signum() > 0 ? surplusEnergy.multiply(BigDecimal.valueOf(100)).divide(capacity, 2, RoundingMode.HALF_UP) |
| | | : (snapshots.isEmpty() ? BigDecimal.ZERO : totalSoc.divide(BigDecimal.valueOf(snapshots.size()), 2, RoundingMode.HALF_UP))); |
| | | summary.put("elinkTotal", elinkTotal); |
| | | summary.put("elinkOnline", elinkOnline); |
| | | summary.put("eblockTotal", blocks.size()); |
| | | summary.put("eblockOnline", blocks.stream().filter(this::isOnlineBlock).count()); |
| | | summary.put("incomeYesterday", sumDaily(dailyRows, yesterday, "income")); |
| | | summary.put("chargedEnergyYesterday", sumDaily(dailyRows, yesterday, "chargedEnergy")); |
| | | summary.put("dischargedEnergyYesterday", sumDaily(dailyRows, yesterday, "dischargedEnergy")); |
| | | summary.put("syncedAt", syncedAt); |
| | | return summary; |
| | | } |
| | | |
| | | private boolean isOnlineBlock(Map<String, Object> row) { |
| | | int status = decimal(row.get("runStatus")).intValue(); |
| | | return status >= 1 && status <= 4 && row.get("recordTime") != null && !String.valueOf(row.get("recordTime")).isEmpty(); |
| | | } |
| | | |
| | | private BigDecimal sumDaily(List<Map<String, Object>> rows, LocalDate day, String field) { |
| | | return rows.stream().filter(row -> day.equals(asDate(row.get("statDate")))) |
| | | .map(row -> decimal(row.get(field))).reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | } |
| | | |
| | | private List<Map<String, Object>> completeHistory(List<Map<String, Object>> dailyRows, String period, |
| | | LocalDate start, LocalDate end) { |
| | | DateTimeFormatter formatter = "YEAR".equals(period) ? DateTimeFormatter.ofPattern("yyyy-MM") : DateTimeFormatter.ISO_LOCAL_DATE; |
| | | Map<String, Map<String, Object>> historyByLabel = new HashMap<>(); |
| | | if (history != null) { |
| | | for (Map<String, Object> row : history) { |
| | | if (row != null && row.get("label") != null) { |
| | | historyByLabel.put(String.valueOf(row.get("label")), row); |
| | | } |
| | | } |
| | | for (Map<String, Object> row : dailyRows) { |
| | | LocalDate statDate = asDate(row.get("statDate")); |
| | | if (statDate == null) continue; |
| | | String label = statDate.format(formatter); |
| | | Map<String, Object> total = historyByLabel.computeIfAbsent(label, ignored -> zeroHistory(label)); |
| | | total.put("income", decimal(total.get("income")).add(decimal(row.get("income")))); |
| | | total.put("chargedEnergy", decimal(total.get("chargedEnergy")).add(decimal(row.get("chargedEnergy")))); |
| | | total.put("dischargedEnergy", decimal(total.get("dischargedEnergy")).add(decimal(row.get("dischargedEnergy")))); |
| | | } |
| | | List<Map<String, Object>> completed = new ArrayList<>(); |
| | | DateTimeFormatter formatter = "YEAR".equals(period) |
| | | ? DateTimeFormatter.ofPattern("yyyy-MM") : DateTimeFormatter.ISO_LOCAL_DATE; |
| | | LocalDate cursor = "YEAR".equals(period) ? start.withDayOfMonth(1) : start; |
| | | LocalDate last = "YEAR".equals(period) ? end.withDayOfMonth(1) : end; |
| | | while (!cursor.isAfter(last)) { |
| | | String label = cursor.format(formatter); |
| | | Map<String, Object> row = historyByLabel.get(label); |
| | | if (row == null) { |
| | | row = new LinkedHashMap<>(); |
| | | row.put("label", label); |
| | | row.put("income", BigDecimal.ZERO); |
| | | row.put("chargedEnergy", BigDecimal.ZERO); |
| | | row.put("dischargedEnergy", BigDecimal.ZERO); |
| | | } |
| | | completed.add(row); |
| | | completed.add(historyByLabel.getOrDefault(label, zeroHistory(label))); |
| | | cursor = "YEAR".equals(period) ? cursor.plusMonths(1) : cursor.plusDays(1); |
| | | } |
| | | return completed; |
| | | } |
| | | |
| | | private List<Map<String, Object>> summarizeCurve(List<Map<String, Object>> rows) { |
| | | Map<String, Map<String, Object>> totals = new LinkedHashMap<>(); |
| | | for (Map<String, Object> row : rows) { |
| | | String label = String.valueOf(row.get("recordTime")); |
| | | Map<String, Object> total = totals.computeIfAbsent(label, ignored -> new LinkedHashMap<>()); |
| | | total.put("label", label); |
| | | total.put("power", decimal(total.get("power")).add(decimal(row.get("power")))); |
| | | total.put("socSum", decimal(total.get("socSum")).add(decimal(row.get("soc")))); |
| | | total.put("count", decimal(total.get("count")).add(BigDecimal.ONE)); |
| | | } |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | for (Map<String, Object> total : totals.values()) { |
| | | BigDecimal count = decimal(total.remove("count")); |
| | | BigDecimal soc = decimal(total.remove("socSum")); |
| | | total.put("soc", count.signum() == 0 ? BigDecimal.ZERO : soc.divide(count, 2, RoundingMode.HALF_UP)); |
| | | result.add(total); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | private Map<String, Object> zeroHistory(String label) { |
| | | Map<String, Object> row = new LinkedHashMap<>(); |
| | | row.put("label", label); |
| | | row.put("income", BigDecimal.ZERO); |
| | | row.put("chargedEnergy", BigDecimal.ZERO); |
| | | row.put("dischargedEnergy", BigDecimal.ZERO); |
| | | return row; |
| | | } |
| | | |
| | | private LocalDate asDate(Object value) { |
| | | if (value instanceof LocalDate) return (LocalDate) value; |
| | | return value == null ? null : LocalDate.parse(String.valueOf(value)); |
| | | } |
| | | |
| | | private BigDecimal decimal(Object value) { |
| | | if (value == null) return BigDecimal.ZERO; |
| | | if (value instanceof BigDecimal) return (BigDecimal) value; |
| | | return new BigDecimal(String.valueOf(value)); |
| | | } |
| | | } |
| | |
| | | SELECT station_id stationId, station_name stationName, platform_name platformName |
| | | FROM t_emind_dashboard_snapshot ORDER BY station_name |
| | | </select> |
| | | <select id="selectOverview" resultType="map"> |
| | | SELECT COALESCE(SUM(income_sum),0) incomeSum, COALESCE(SUM(charged_energy_sum),0) chargedEnergySum, |
| | | COALESCE(SUM(discharged_energy_sum),0) dischargedEnergySum, |
| | | COALESCE((SELECT SUM(daily.charged_energy) FROM t_emind_dashboard_daily daily |
| | | WHERE daily.stat_date=#{day} |
| | | <if test="stationId != null">AND daily.station_id=#{stationId}</if>),0) chargedEnergyYesterday, |
| | | COALESCE((SELECT SUM(daily.discharged_energy) FROM t_emind_dashboard_daily daily |
| | | WHERE daily.stat_date=#{day} |
| | | <if test="stationId != null">AND daily.station_id=#{stationId}</if>),0) dischargedEnergyYesterday, |
| | | COALESCE(SUM(real_time_power),0) realTimePower, COALESCE(SUM(surplus_energy),0) surplusEnergy, |
| | | COALESCE(SUM(capacity),0) capacity, |
| | | CASE WHEN SUM(capacity)>0 THEN ROUND(SUM(surplus_energy)/SUM(capacity)*100,2) ELSE COALESCE(AVG(soc),0) END soc, |
| | | COALESCE(SUM(elink_total),0) elinkTotal, COALESCE(SUM(elink_online),0) elinkOnline, |
| | | COALESCE((SELECT COUNT(*) FROM t_emind_energy_block block WHERE block.del_flag=0 |
| | | <if test="stationId != null">AND block.station_id=#{stationId}</if>),0) eblockTotal, |
| | | COALESCE((SELECT COUNT(*) FROM t_emind_energy_block block WHERE block.del_flag=0 |
| | | AND block.run_status BETWEEN 1 AND 4 |
| | | AND block.record_time IS NOT NULL AND block.record_time!='' |
| | | <if test="stationId != null">AND block.station_id=#{stationId}</if>),0) eblockOnline, |
| | | COALESCE((SELECT SUM(daily.income) FROM t_emind_dashboard_daily daily |
| | | WHERE daily.stat_date=#{day} |
| | | <if test="stationId != null">AND daily.station_id=#{stationId}</if>),0) incomeYesterday, |
| | | MAX(synced_at) syncedAt |
| | | FROM t_emind_dashboard_snapshot WHERE 1=1 <if test="stationId != null">AND station_id=#{stationId}</if> |
| | | <select id="selectSnapshotRows" resultType="map"> |
| | | SELECT income_sum incomeSum, charged_energy_sum chargedEnergySum, |
| | | discharged_energy_sum dischargedEnergySum, real_time_power realTimePower, |
| | | surplus_energy surplusEnergy, soc, capacity, elink_total elinkTotal, |
| | | elink_online elinkOnline, synced_at syncedAt |
| | | FROM t_emind_dashboard_snapshot WHERE 1=1 |
| | | <if test="stationId != null">AND station_id=#{stationId}</if> |
| | | </select> |
| | | <select id="selectHistory" resultType="map"> |
| | | SELECT <choose><when test="period == 'YEAR'">DATE_FORMAT(stat_date,'%Y-%m')</when><otherwise>DATE_FORMAT(stat_date,'%Y-%m-%d')</otherwise></choose> label, |
| | | SUM(income) income, SUM(charged_energy) chargedEnergy, SUM(discharged_energy) dischargedEnergy |
| | | <select id="selectDailyRows" resultType="map"> |
| | | SELECT stat_date statDate, income, charged_energy chargedEnergy, discharged_energy dischargedEnergy |
| | | FROM t_emind_dashboard_daily WHERE stat_date BETWEEN #{startDate} AND #{endDate} |
| | | <if test="stationId != null">AND station_id=#{stationId}</if> |
| | | GROUP BY label ORDER BY label |
| | | ORDER BY stat_date |
| | | </select> |
| | | <select id="selectCurve" resultType="map"> |
| | | SELECT record_time label, SUM(power) power, AVG(soc) soc FROM t_emind_dashboard_curve WHERE 1=1 |
| | | <select id="selectCurveRows" resultType="map"> |
| | | SELECT record_time recordTime, power, soc FROM t_emind_dashboard_curve WHERE 1=1 |
| | | <if test="stationId != null">AND station_id=#{stationId}</if> |
| | | GROUP BY record_time ORDER BY record_time |
| | | ORDER BY record_time |
| | | </select> |
| | | <select id="selectEnergyBlockRows" resultType="map"> |
| | | SELECT run_status runStatus, record_time recordTime FROM t_emind_energy_block WHERE del_flag=0 |
| | | <if test="stationId != null">AND station_id=#{stationId}</if> |
| | | </select> |
| | | </mapper> |
| | |
| | | import com.ruoyi.other.emind.dto.EmindDashboardQuery; |
| | | import com.ruoyi.other.emind.mapper.EmindStorageDashboardMapper; |
| | | import org.junit.jupiter.api.Test; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.mockito.ArgumentMatchers.*; |
| | | import static org.mockito.Mockito.*; |
| | | |
| | | class EmindStorageDashboardServiceTest { |
| | | @Test |
| | | void overviewUsesOnlyLocalMapperAndDefaultsToRecentDays() { |
| | | EmindStorageDashboardMapper mapper=mock(EmindStorageDashboardMapper.class); |
| | | when(mapper.selectOverview(isNull(), any())).thenReturn(Collections.emptyMap()); |
| | | when(mapper.selectHistory(isNull(), eq("DAY"), any(), any())).thenReturn(Collections.emptyList()); |
| | | when(mapper.selectCurve(isNull())).thenReturn(Collections.emptyList()); |
| | | EmindDashboardQuery query=new EmindDashboardQuery(); |
| | | assertEquals(3, new EmindStorageDashboardService(mapper).overview(query).size()); |
| | | verify(mapper).selectOverview(isNull(), eq(LocalDate.now().minusDays(1))); |
| | | verify(mapper).selectHistory(isNull(), eq("DAY"), eq(LocalDate.now().minusDays(6)), eq(LocalDate.now())); |
| | | void overviewReadsRowsAndAggregatesThemInJava() { |
| | | EmindStorageDashboardMapper mapper = mock(EmindStorageDashboardMapper.class); |
| | | LocalDate yesterday = LocalDate.now().minusDays(1); |
| | | when(mapper.selectSnapshotRows(isNull())).thenReturn(Arrays.asList( |
| | | row("incomeSum", "10", "capacity", "100", "surplusEnergy", "40", "elinkTotal", 2, "elinkOnline", 1), |
| | | row("incomeSum", "20", "capacity", "100", "surplusEnergy", "60", "elinkTotal", 3, "elinkOnline", 2))); |
| | | when(mapper.selectDailyRows(isNull(), any(), any())).thenReturn(Collections.emptyList()); |
| | | when(mapper.selectDailyRows(isNull(), eq(yesterday), eq(yesterday))).thenReturn(Arrays.asList( |
| | | row("statDate", yesterday, "income", "12.5", "chargedEnergy", "5", "dischargedEnergy", "3"), |
| | | row("statDate", yesterday, "income", "7.5", "chargedEnergy", "2", "dischargedEnergy", "1"))); |
| | | when(mapper.selectCurveRows(isNull())).thenReturn(Collections.emptyList()); |
| | | when(mapper.selectEnergyBlockRows(isNull())).thenReturn(Arrays.asList( |
| | | row("runStatus", 1, "recordTime", "10:00"), row("runStatus", 5, "recordTime", "10:00"))); |
| | | |
| | | Map<String, Object> summary = (Map<String, Object>) new EmindStorageDashboardService(mapper) |
| | | .overview(new EmindDashboardQuery()).get("summary"); |
| | | |
| | | assertEquals(new BigDecimal("30"), summary.get("incomeSum")); |
| | | assertEquals(new BigDecimal("50"), summary.get("soc")); |
| | | assertEquals(2, summary.get("eblockTotal")); |
| | | assertEquals(1L, summary.get("eblockOnline")); |
| | | assertEquals(new BigDecimal("20.0"), summary.get("incomeYesterday")); |
| | | assertEquals(new BigDecimal("7"), summary.get("chargedEnergyYesterday")); |
| | | verify(mapper).selectDailyRows(isNull(), eq(yesterday), eq(yesterday)); |
| | | } |
| | | |
| | | @Test |
| | | void overviewFillsMissingDailyHistoryWithZeroValues() { |
| | | void overviewGroupsDailyRowsByMonthInJava() { |
| | | EmindStorageDashboardMapper mapper = mock(EmindStorageDashboardMapper.class); |
| | | LocalDate start = LocalDate.of(2026, 7, 20); |
| | | LocalDate end = LocalDate.of(2026, 7, 22); |
| | | Map<String, Object> recordedDay = new HashMap<>(); |
| | | recordedDay.put("label", "2026-07-21"); |
| | | recordedDay.put("income", 12); |
| | | recordedDay.put("chargedEnergy", 5); |
| | | recordedDay.put("dischargedEnergy", 3); |
| | | when(mapper.selectOverview(isNull(), any())).thenReturn(Collections.emptyMap()); |
| | | when(mapper.selectHistory(isNull(), eq("DAY"), eq(start), eq(end))).thenReturn(Collections.singletonList(recordedDay)); |
| | | when(mapper.selectCurve(isNull())).thenReturn(Collections.emptyList()); |
| | | LocalDate start = LocalDate.of(2026, 7, 1); |
| | | LocalDate end = LocalDate.of(2026, 8, 31); |
| | | when(mapper.selectSnapshotRows(isNull())).thenReturn(Collections.emptyList()); |
| | | when(mapper.selectDailyRows(isNull(), any(), any())).thenReturn(Collections.emptyList()); |
| | | when(mapper.selectDailyRows(isNull(), eq(start), eq(end))).thenReturn(Arrays.asList( |
| | | row("statDate", LocalDate.of(2026, 7, 1), "income", "2"), |
| | | row("statDate", LocalDate.of(2026, 7, 2), "income", "3"))); |
| | | when(mapper.selectCurveRows(isNull())).thenReturn(Collections.emptyList()); |
| | | when(mapper.selectEnergyBlockRows(isNull())).thenReturn(Collections.emptyList()); |
| | | EmindDashboardQuery query = new EmindDashboardQuery(); |
| | | query.setPeriod("DAY"); |
| | | query.setStartDate(start); |
| | | query.setEndDate(end); |
| | | query.setPeriod("YEAR"); query.setStartDate(start); query.setEndDate(end); |
| | | |
| | | Map<String, Object> result = new EmindStorageDashboardService(mapper).overview(query); |
| | | List<Map<String, Object>> history = (List<Map<String, Object>>) result.get("history"); |
| | | List<Map<String, Object>> history = (List<Map<String, Object>>) new EmindStorageDashboardService(mapper) |
| | | .overview(query).get("history"); |
| | | |
| | | List<Object> labels = new ArrayList<>(); |
| | | for (Map<String, Object> row : history) labels.add(row.get("label")); |
| | | assertEquals(Arrays.asList("2026-07-20", "2026-07-21", "2026-07-22"), labels); |
| | | assertEquals(BigDecimal.ZERO, history.get(0).get("income")); |
| | | assertEquals(12, history.get(1).get("income")); |
| | | assertEquals(BigDecimal.ZERO, history.get(2).get("chargedEnergy")); |
| | | assertEquals("2026-07", history.get(0).get("label")); |
| | | assertEquals(new BigDecimal("5"), history.get(0).get("income")); |
| | | assertEquals("2026-08", history.get(1).get("label")); |
| | | } |
| | | |
| | | private Map<String, Object> row(Object... values) { |
| | | Map<String, Object> row = new java.util.HashMap<>(); |
| | | for (int i = 0; i < values.length; i += 2) row.put((String) values[i], values[i + 1]); |
| | | return row; |
| | | } |
| | | } |