From 43aab58c9ecb1203770ba382efbdbae299ca87ec Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期一, 26 十月 2026 15:12:31 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_business' into dev_business

---
 yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/energy/EnergyRecordServiceTest.java |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 178 insertions(+), 0 deletions(-)

diff --git a/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/energy/EnergyRecordServiceTest.java b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/energy/EnergyRecordServiceTest.java
new file mode 100644
index 0000000..be2d69c
--- /dev/null
+++ b/yudao-module-mes/src/test/java/cn/iocoder/yudao/module/mes/service/energy/EnergyRecordServiceTest.java
@@ -0,0 +1,178 @@
+package cn.iocoder.yudao.module.mes.service.energy;
+
+import cn.iocoder.yudao.module.mes.controller.admin.energy.vo.*;
+import cn.iocoder.yudao.module.mes.dal.dataobject.energy.EnergyRecordDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.energy.EnergyRecordMapper;
+import jakarta.validation.Validation;
+import org.apache.ibatis.session.Configuration;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.List;
+import java.util.Map;
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+class EnergyRecordServiceTest {
+    @Mock private org.springframework.context.ApplicationEventPublisher applicationEventPublisher;
+    @Mock
+    private EnergyRecordMapper mapper;
+    @InjectMocks
+    private EnergyRecordService service;
+
+    @Test
+    void changedDateChecksBothDaysWithOriginalTenant() {
+        var req = request(); req.setId(77L);
+        var old = new EnergyRecordDO(); old.setId(77L); old.setRecordDate(req.getRecordDate().minusDays(1));
+        when(mapper.selectById(77L)).thenReturn(old);
+        when(mapper.updateById(any(EnergyRecordDO.class))).thenReturn(1);
+        var previousTenant = cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder.getTenantId();
+        try {
+            cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder.setTenantId(42L);
+            service.update(req);
+            var event = org.mockito.ArgumentCaptor.forClass(EnergyRecordChangedEvent.class);
+            verify(applicationEventPublisher).publishEvent(event.capture());
+            assertEquals(42L, event.getValue().tenantId());
+            assertEquals(java.util.Set.of(old.getRecordDate(), req.getRecordDate()), event.getValue().dates());
+        } finally { cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder.setTenantId(previousTenant); }
+    }
+
+    @Test
+    void calculatesMoneyWithDecimalRoundingAndClearsRemark() {
+        EnergyRecordSaveReqVO req = request();
+        req.setQuantity(new BigDecimal("12.345"));
+        req.setUnitPrice(new BigDecimal("0.6789"));
+        EnergyRecordDO record = EnergyRecordService.toRecord(req);
+        assertEquals(new BigDecimal("8.38"), record.getAmount());
+        assertEquals("鐕曠獫鐢熶骇鍖�", record.getUsageArea());
+        assertEquals("", record.getRemark());
+        req.setUnitPrice(BigDecimal.ZERO);
+        assertEquals(new BigDecimal("0.00"), EnergyRecordService.toRecord(req).getAmount());
+    }
+
+    @Test
+    void createIgnoresClientIdAndUpdateRequiresExistingRecord() {
+        EnergyRecordSaveReqVO req = request();
+        req.setId(77L);
+        doAnswer(invocation -> {
+            EnergyRecordDO record = invocation.getArgument(0);
+            assertNull(record.getId());
+            record.setId(9L);
+            return 1;
+        }).when(mapper).insert(any(EnergyRecordDO.class));
+        assertEquals(9L, service.create(req));
+        assertThrows(RuntimeException.class, () -> service.update(req));
+        verify(mapper, never()).updateById(any(EnergyRecordDO.class));
+        req.setId(null);
+        assertThrows(RuntimeException.class, () -> service.update(req));
+    }
+
+    @Test
+    void deleteMissingRecordDoesNotExecuteDelete() {
+        assertThrows(RuntimeException.class, () -> service.delete(8L));
+        verify(mapper, never()).deleteById(any(Long.class));
+    }
+
+    @Test
+    void aggregatesSeparateUnitsAndMergesDatesAreasAndCosts() {
+        EnergyAnalysisRespVO result = EnergyRecordService.aggregate(List.of(
+                row("WATER", "2026-09-01", "鐕曠獫鐢熶骇鍖�", "10", "30", 1),
+                row("WATER", "2026-09-01", "鍘熸祮鐢熶骇鍖�", "5", "15", 2),
+                row("ELECTRICITY", "2026-09-01", "鐕曠獫鐢熶骇鍖�", "100", "80", 1),
+                row("WATER", "2026-09-02", "鐕曠獫鐢熶骇鍖�", "2", "0", 1)));
+        assertEquals(new BigDecimal("125"), result.getTotalAmount());
+        assertEquals(5, result.getRecordCount());
+        assertEquals(new BigDecimal("17"), result.getSummary().get(0).getQuantity());
+        assertEquals(new BigDecimal("100"), result.getSummary().get(1).getQuantity());
+        assertEquals(BigDecimal.ZERO, result.getSummary().get(2).getQuantity());
+        assertEquals(3, result.getTrend().size());
+        assertEquals(new BigDecimal("15"), result.getTrend().get(0).getQuantity());
+        assertEquals(3, result.getAreas().size());
+        assertEquals(new BigDecimal("12"), result.getAreas().get(0).getQuantity());
+    }
+
+    @Test
+    void emptyAnalysisReturnsZeroTotalsAndAllThreeEnergies() {
+        EnergyAnalysisRespVO result = EnergyRecordService.aggregate(List.of());
+        assertEquals(3, result.getSummary().size());
+        assertEquals(BigDecimal.ZERO, result.getTotalAmount());
+        assertTrue(result.getTrend().isEmpty());
+        assertTrue(result.getAreas().isEmpty());
+    }
+
+    @Test
+    void rejectsInvalidTypeNegativePriceZeroQuantityFutureDateAndExcessPrecision() {
+        try (var factory = Validation.buildDefaultValidatorFactory()) {
+            var validator = factory.getValidator();
+            assertTrue(validator.validate(request()).isEmpty());
+            EnergyRecordSaveReqVO req = request();
+            req.setEnergyType("GAS");
+            req.setUnitPrice(new BigDecimal("-1"));
+            req.setQuantity(BigDecimal.ZERO);
+            req.setRecordDate(LocalDate.now().plusDays(1));
+            assertTrue(validator.validate(req).size() >= 4);
+            req = request();
+            req.setQuantity(new BigDecimal("1.0001"));
+            assertFalse(validator.validate(req).isEmpty());
+            EnergyAnalysisReqVO analysis = new EnergyAnalysisReqVO();
+            analysis.setStartDate(LocalDate.of(2026, 1, 1));
+            analysis.setEndDate(LocalDate.of(2025, 1, 1));
+            assertFalse(validator.validate(analysis).isEmpty());
+            analysis.setEndDate(LocalDate.of(2029, 1, 1));
+            assertFalse(validator.validate(analysis).isEmpty());
+        }
+    }
+
+    @Test
+    void analysisSqlBindsFiltersAndSelectsDayOrMonthSafely() {
+        Configuration config = new Configuration();
+        config.addMapper(EnergyRecordMapper.class);
+        var statement = config.getMappedStatement(EnergyRecordMapper.class.getName() + ".selectAnalysis");
+        EnergyAnalysisReqVO req = new EnergyAnalysisReqVO();
+        req.setStartDate(LocalDate.of(2026, 1, 1));
+        req.setEndDate(LocalDate.of(2026, 1, 31));
+        String daily = statement.getBoundSql(Map.of("req", req)).getSql();
+        assertTrue(daily.contains("'%Y-%m-%d'"));
+        assertTrue(daily.contains("deleted = 0"));
+        req.setGroupBy("MONTH");
+        req.setEnergyType("STEAM");
+        req.setUsageArea("' OR 1=1 --");
+        req.setProductCategory("鐕曠獫");
+        String monthly = statement.getBoundSql(Map.of("req", req)).getSql();
+        assertTrue(monthly.contains("'%Y-%m'"));
+        assertTrue(monthly.contains("energy_type = ?"));
+        assertTrue(monthly.contains("product_category = ?"));
+        assertFalse(monthly.contains(req.getUsageArea()));
+    }
+
+    private static EnergyRecordSaveReqVO request() {
+        EnergyRecordSaveReqVO req = new EnergyRecordSaveReqVO();
+        req.setRecordDate(LocalDate.now());
+        req.setEnergyType("WATER");
+        req.setUsageArea(" 鐕曠獫鐢熶骇鍖� ");
+        req.setProductCategory("鐕曠獫");
+        req.setUsagePurpose("璁惧娓呮礂");
+        req.setQuantity(BigDecimal.ONE);
+        req.setUnitPrice(BigDecimal.ONE);
+        req.setRecorder("寮犱笁");
+        return req;
+    }
+
+    private static EnergyRecordMapper.Aggregate row(String type, String period, String area,
+                                                    String quantity, String amount, long count) {
+        EnergyRecordMapper.Aggregate row = new EnergyRecordMapper.Aggregate();
+        row.setEnergyType(type);
+        row.setPeriod(period);
+        row.setUsageArea(area);
+        row.setQuantity(new BigDecimal(quantity));
+        row.setAmount(new BigDecimal(amount));
+        row.setRecordCount(count);
+        return row;
+    }
+}

--
Gitblit v1.9.3