puzhibing
2026-09-02 54b8d039c03b2a94b7e6dcd74b8bd18ee979f55d
fix: complete order VIN display and summary query
2个文件已添加
6个文件已修改
329 ■■■■■ 已修改文件
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/vo/ChargingOrderInfoVO.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TCardChargingOrderMapper.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TCardChargingOrderServiceImpl.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TVinChargingOrderServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TCardChargingOrderMapper.xml 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/mapper/CardChargingOrderSummaryMapperTest.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/TCardChargingOrderSummaryTest.java 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-api/ruoyi-api-order/src/main/java/com/ruoyi/order/api/vo/ChargingOrderInfoVO.java
@@ -22,6 +22,8 @@
    private String totalPower;
    @ApiModelProperty(value = "车牌号")
    private String licensePlate;
    @ApiModelProperty(value = "VIN码")
    private String vin;
    @ApiModelProperty(value = "车辆品牌")
    private String vehicleBrand;
    @ApiModelProperty(value = "车辆类型")
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/controller/TChargingOrderController.java
@@ -1484,6 +1484,7 @@
        chargingOrderInfoVO.setCdVoltage(byId.getVoltage()!=null?byId.getVoltage().setScale(2, BigDecimal.ROUND_HALF_DOWN)+"":"");
        chargingOrderInfoVO.setSurplus(byId.getTotalElectricity()!=null?byId.getTotalElectricity().setScale(2, BigDecimal.ROUND_HALF_DOWN)+"":"");
        chargingOrderInfoVO.setTotalPower(byId.getPower()!=null?byId.getPower().setScale(2, BigDecimal.ROUND_HALF_DOWN)+"":"");
        chargingOrderInfoVO.setVin(byId.getVin());
        if (byId.getAppUserCarId()!=null){
            TAppUserCar data = appUserCarClient.getCarById(byId.getAppUserCarId()+"").getData();
            if (data!=null){
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/mapper/TCardChargingOrderMapper.java
@@ -33,6 +33,14 @@
                                @Param("endTime1") String endTime1,
                                @Param("endTime2") String endTime2);
    List<Long> summaryOrderIds(@Param("query") CardChargingOrderQuery query,
                               @Param("startTime1") String startTime1,
                               @Param("startTime2") String startTime2,
                               @Param("endTime1") String endTime1,
                               @Param("endTime2") String endTime2);
    Map<String, Object> accountingSummaryByOrderIds(@Param("orderIds") List<Long> orderIds);
    List<Map<String, Object>> balanceIncomeDetail(@Param("query") CardChargingOrderQuery query);
    List<Map<String, Object>> accountingStrategyList(@Param("chargingOrderId") Long chargingOrderId);
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TCardChargingOrderServiceImpl.java
@@ -24,6 +24,7 @@
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
@@ -76,11 +77,70 @@
        if (result == null) {
            result = new HashMap<>();
        }
        result.putIfAbsent("platformIncome", BigDecimal.ZERO);
        result.putIfAbsent("partnerIncome", BigDecimal.ZERO);
        BigDecimal platformIncome = BigDecimal.ZERO;
        BigDecimal partnerIncome = BigDecimal.ZERO;
        Map<String, BigDecimal> accountingSummary = emptyAccountingSummary();
        List<Long> orderIds = baseMapper.summaryOrderIds(query, timeRange[0], timeRange[1], timeRange[2], timeRange[3]);
        if (orderIds != null && !orderIds.isEmpty()) {
            int batchSize = 500;
            for (int i = 0; i < orderIds.size(); i += batchSize) {
                List<Long> batchIds = orderIds.subList(i, Math.min(i + batchSize, orderIds.size()));
                Map<String, Object> shareSummary = baseMapper.shareIncomeSummaryByOrderIds(batchIds);
                platformIncome = platformIncome.add(summaryDecimal(shareSummary, "platformIncome"));
                partnerIncome = partnerIncome.add(summaryDecimal(shareSummary, "partnerIncome"));
                mergeAccountingSummary(accountingSummary, baseMapper.accountingSummaryByOrderIds(batchIds));
            }
        }
        result.put("platformIncome", platformIncome);
        result.put("partnerIncome", partnerIncome);
        result.put("platformIncomeTotal", platformIncome);
        result.put("partnerIncomeTotal", partnerIncome);
        result.put("capacityProportion", buildProportion(accountingSummary, "capacity"));
        result.put("serviceProportion", buildProportion(accountingSummary, "service"));
        result.put("electronicProportion", buildProportion(accountingSummary, "electric"));
        return result;
    }
    private Map<String, BigDecimal> emptyAccountingSummary() {
        Map<String, BigDecimal> summary = new HashMap<>();
        for (String prefix : new String[]{"capacity", "service", "electric"}) {
            summary.put(prefix + "Total", BigDecimal.ZERO);
            for (int type = 1; type <= 4; type++) {
                summary.put(prefix + type, BigDecimal.ZERO);
            }
        }
        return summary;
    }
    private void mergeAccountingSummary(Map<String, BigDecimal> total, Map<String, Object> batch) {
        if (batch == null) {
            return;
        }
        for (String key : total.keySet()) {
            total.put(key, total.get(key).add(summaryDecimal(batch, key)));
        }
    }
    private BigDecimal summaryDecimal(Map<String, Object> summary, String key) {
        if (summary == null || summary.get(key) == null) {
            return BigDecimal.ZERO;
        }
        Object value = summary.get(key);
        return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(value.toString());
    }
    private String buildProportion(Map<String, BigDecimal> summary, String prefix) {
        BigDecimal denominator = summary.get(prefix + "Total");
        List<String> proportions = new ArrayList<>(4);
        for (int type = 1; type <= 4; type++) {
            BigDecimal percentage = denominator.signum() == 0 ? BigDecimal.ZERO
                    : summary.get(prefix + type).multiply(new BigDecimal("100"))
                    .divide(denominator, 2, RoundingMode.HALF_UP).stripTrailingZeros();
            proportions.add(percentage.toPlainString() + "%");
        }
        return String.join("-", proportions);
    }
    @Override
    public List<ChargingOrderVO> exportList(CardChargingOrderQuery query) {
        String[] timeRange = parseTimeRange(query);
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TVinChargingOrderServiceImpl.java
@@ -134,6 +134,11 @@
                data.setPower(data.getOutput_voltage().multiply(data.getOutput_current()).divide(new BigDecimal(1000), 2, BigDecimal.ROUND_HALF_UP));
            }
        }
        UploadRealTimeMonitoringData latestMonitoring = monitoring.isEmpty() ? null : monitoring.get(monitoring.size() - 1);
        result.put("cdElectronic", latestMonitoring == null ? null : latestMonitoring.getOutput_current());
        result.put("cdVoltage", latestMonitoring == null ? null : latestMonitoring.getOutput_voltage());
        result.put("totalPower", latestMonitoring == null ? null : latestMonitoring.getPower());
        result.put("surplus", latestMonitoring == null ? null : latestMonitoring.getSoc());
        result.put("list", monitoring);
        result.put("list1", baseMapper.accountingStrategyList(order.getId()));
        return result;
ruoyi-service/ruoyi-order/src/main/resources/mapper/order/TCardChargingOrderMapper.xml
@@ -29,10 +29,10 @@
            <if test="query.gunId != null">
                AND o.charging_gun_id = #{query.gunId}
            </if>
            <if test="startTime1 != null and startTime1 != ''">
            <if test="startTime1 != null and startTime1 != '' and startTime2 != null and startTime2 != ''">
                AND o.pay_time BETWEEN #{startTime1} AND #{startTime2}
            </if>
            <if test="endTime1 != null and endTime1 != ''">
            <if test="endTime1 != null and endTime1 != '' and endTime2 != null and endTime2 != ''">
                AND o.end_time BETWEEN #{endTime1} AND #{endTime2}
            </if>
        </where>
@@ -77,55 +77,51 @@
               IFNULL(SUM(o.payment_amount), 0) AS paymentAmount,
               IFNULL(SUM(o.electrovalence), 0) AS electrovalence,
               IFNULL(SUM(o.service_charge), 0) AS serviceCharge,
               IFNULL(SUM(o.third_pay_amount), 0) AS thirdPayAmount,
               IFNULL(SUM(s.platform_income), 0) AS platformIncome,
               IFNULL(SUM(s.partner_income), 0) AS partnerIncome,
               IFNULL(SUM(s.platform_income), 0) AS platformIncomeTotal,
               IFNULL(SUM(s.partner_income), 0) AS partnerIncomeTotal,
               CONCAT(IFNULL(ROUND(SUM(a.capacity1) / NULLIF(SUM(a.capacity_total), 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(SUM(a.capacity2) / NULLIF(SUM(a.capacity_total), 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(SUM(a.capacity3) / NULLIF(SUM(a.capacity_total), 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(SUM(a.capacity4) / NULLIF(SUM(a.capacity_total), 0) * 100, 2), 0), '%') AS capacityProportion,
               CONCAT(IFNULL(ROUND(SUM(a.service1) / NULLIF(SUM(a.service_total), 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(SUM(a.service2) / NULLIF(SUM(a.service_total), 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(SUM(a.service3) / NULLIF(SUM(a.service_total), 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(SUM(a.service4) / NULLIF(SUM(a.service_total), 0) * 100, 2), 0), '%') AS serviceProportion,
               CONCAT(IFNULL(ROUND(SUM(a.electric1) / NULLIF(SUM(a.electric_total), 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(SUM(a.electric2) / NULLIF(SUM(a.electric_total), 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(SUM(a.electric3) / NULLIF(SUM(a.electric_total), 0) * 100, 2), 0), '%-',
                      IFNULL(ROUND(SUM(a.electric4) / NULLIF(SUM(a.electric_total), 0) * 100, 2), 0), '%') AS electronicProportion
               IFNULL(SUM(o.third_pay_amount), 0) AS thirdPayAmount
        FROM t_card_charging_order o
        LEFT JOIN (
            SELECT charging_order_id,
                   SUM(IFNULL(channel_electricity_amount, 0) + IFNULL(channel_service_amount, 0) - IFNULL(share_amount, 0)) AS platform_income,
                   SUM(IFNULL(share_amount, 0)) AS partner_income
            FROM t_card_charging_order_share_record
            WHERE del_flag = 0
            GROUP BY charging_order_id
        ) s ON s.charging_order_id = o.id
        LEFT JOIN (
            SELECT charging_order_id,
                   SUM(charging_capacity) AS capacity_total,
                   SUM(CASE WHEN type = 1 THEN charging_capacity ELSE 0 END) AS capacity1,
                   SUM(CASE WHEN type = 2 THEN charging_capacity ELSE 0 END) AS capacity2,
                   SUM(CASE WHEN type = 3 THEN charging_capacity ELSE 0 END) AS capacity3,
                   SUM(CASE WHEN type = 4 THEN charging_capacity ELSE 0 END) AS capacity4,
                   SUM(period_service_price) AS service_total,
                   SUM(CASE WHEN type = 1 THEN period_service_price ELSE 0 END) AS service1,
                   SUM(CASE WHEN type = 2 THEN period_service_price ELSE 0 END) AS service2,
                   SUM(CASE WHEN type = 3 THEN period_service_price ELSE 0 END) AS service3,
                   SUM(CASE WHEN type = 4 THEN period_service_price ELSE 0 END) AS service4,
                   SUM(period_electric_price) AS electric_total,
                   SUM(CASE WHEN type = 1 THEN period_electric_price ELSE 0 END) AS electric1,
                   SUM(CASE WHEN type = 2 THEN period_electric_price ELSE 0 END) AS electric2,
                   SUM(CASE WHEN type = 3 THEN period_electric_price ELSE 0 END) AS electric3,
                   SUM(CASE WHEN type = 4 THEN period_electric_price ELSE 0 END) AS electric4
            FROM t_card_charging_order_accounting_strategy
            GROUP BY charging_order_id
        ) a ON a.charging_order_id = o.id
        <include refid="queryCondition"/>
    </select>
    <select id="summaryOrderIds" resultType="java.lang.Long">
        SELECT o.id
        FROM t_card_charging_order o
        <include refid="queryCondition"/>
    </select>
    <select id="shareIncomeSummaryByOrderIds" resultType="java.util.LinkedHashMap">
        SELECT IFNULL(SUM(IFNULL(channel_electricity_amount, 0) + IFNULL(channel_service_amount, 0) - IFNULL(share_amount, 0)), 0) AS platformIncome,
               IFNULL(SUM(IFNULL(share_amount, 0)), 0) AS partnerIncome
        FROM t_card_charging_order_share_record
        WHERE del_flag = 0
          AND charging_order_id IN
        <foreach collection="orderIds" item="orderId" open="(" separator="," close=")">
            #{orderId}
        </foreach>
    </select>
    <select id="accountingSummaryByOrderIds" resultType="java.util.LinkedHashMap">
        SELECT IFNULL(SUM(charging_capacity), 0) AS capacityTotal,
               IFNULL(SUM(CASE WHEN type = 1 THEN charging_capacity ELSE 0 END), 0) AS capacity1,
               IFNULL(SUM(CASE WHEN type = 2 THEN charging_capacity ELSE 0 END), 0) AS capacity2,
               IFNULL(SUM(CASE WHEN type = 3 THEN charging_capacity ELSE 0 END), 0) AS capacity3,
               IFNULL(SUM(CASE WHEN type = 4 THEN charging_capacity ELSE 0 END), 0) AS capacity4,
               IFNULL(SUM(period_service_price), 0) AS serviceTotal,
               IFNULL(SUM(CASE WHEN type = 1 THEN period_service_price ELSE 0 END), 0) AS service1,
               IFNULL(SUM(CASE WHEN type = 2 THEN period_service_price ELSE 0 END), 0) AS service2,
               IFNULL(SUM(CASE WHEN type = 3 THEN period_service_price ELSE 0 END), 0) AS service3,
               IFNULL(SUM(CASE WHEN type = 4 THEN period_service_price ELSE 0 END), 0) AS service4,
               IFNULL(SUM(period_electric_price), 0) AS electricTotal,
               IFNULL(SUM(CASE WHEN type = 1 THEN period_electric_price ELSE 0 END), 0) AS electric1,
               IFNULL(SUM(CASE WHEN type = 2 THEN period_electric_price ELSE 0 END), 0) AS electric2,
               IFNULL(SUM(CASE WHEN type = 3 THEN period_electric_price ELSE 0 END), 0) AS electric3,
               IFNULL(SUM(CASE WHEN type = 4 THEN period_electric_price ELSE 0 END), 0) AS electric4
        FROM t_card_charging_order_accounting_strategy
        WHERE charging_order_id IN
        <foreach collection="orderIds" item="orderId" open="(" separator="," close=")">
            #{orderId}
        </foreach>
    </select>
    <select id="balanceIncomeDetail" resultType="java.util.LinkedHashMap">
        SELECT o.card_id AS cardId,
               o.card_no AS cardNo,
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/mapper/CardChargingOrderSummaryMapperTest.java
New file
@@ -0,0 +1,51 @@
package com.ruoyi.order.mapper;
import org.junit.jupiter.api.Test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class CardChargingOrderSummaryMapperTest {
    @Test
    void splitsSummaryQueriesForMyCatAndRequiresCompleteTimeRanges() throws IOException {
        String mapper = resource("mapper/order/TCardChargingOrderMapper.xml");
        String summary = select(mapper, "summary");
        String orderIds = select(mapper, "summaryOrderIds");
        String share = select(mapper, "shareIncomeSummaryByOrderIds");
        String accounting = select(mapper, "accountingSummaryByOrderIds");
        assertTrue(summary.contains("FROM t_card_charging_order o"));
        assertFalse(summary.contains(" JOIN "));
        assertFalse(summary.contains("t_card_charging_order_share_record"));
        assertFalse(summary.contains("t_card_charging_order_accounting_strategy"));
        assertTrue(orderIds.contains("<include refid=\"queryCondition\"/>"));
        assertTrue(share.contains("charging_order_id IN"));
        assertTrue(accounting.contains("charging_order_id IN"));
        assertTrue(mapper.contains("startTime1 != null and startTime1 != '' and startTime2 != null and startTime2 != ''"));
        assertTrue(mapper.contains("endTime1 != null and endTime1 != '' and endTime2 != null and endTime2 != ''"));
    }
    private String select(String mapper, String id) {
        int start = mapper.indexOf("<select id=\"" + id + "\"");
        int end = mapper.indexOf("</select>", start);
        assertTrue(start >= 0 && end > start);
        return mapper.substring(start, end);
    }
    private String resource(String path) throws IOException {
        InputStream input = getClass().getClassLoader().getResourceAsStream(path);
        assertNotNull(input);
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {
            return reader.lines().collect(Collectors.joining("\n"));
        }
    }
}
ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/TCardChargingOrderSummaryTest.java
New file
@@ -0,0 +1,108 @@
package com.ruoyi.order.service.impl;
import com.ruoyi.order.api.query.CardChargingOrderQuery;
import com.ruoyi.order.mapper.TCardChargingOrderMapper;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
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.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class TCardChargingOrderSummaryTest {
    @Test
    void mergesShareAndAccountingSummariesInBatches() {
        TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl();
        TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class);
        CardChargingOrderQuery query = new CardChargingOrderQuery();
        query.setSiteId(12);
        ReflectionTestUtils.setField(service, "baseMapper", mapper);
        Map<String, Object> baseSummary = new HashMap<>();
        baseSummary.put("orderCount", 501L);
        List<Long> orderIds = new ArrayList<>();
        for (long id = 1; id <= 501; id++) {
            orderIds.add(id);
        }
        when(mapper.summary(any(), isNull(), isNull(), isNull(), isNull())).thenReturn(baseSummary);
        when(mapper.summaryOrderIds(any(), isNull(), isNull(), isNull(), isNull())).thenReturn(orderIds);
        Map<String, Object> share = new HashMap<>();
        share.put("platformIncome", new BigDecimal("10.25"));
        share.put("partnerIncome", new BigDecimal("2.50"));
        when(mapper.shareIncomeSummaryByOrderIds(anyList())).thenReturn(share);
        Map<String, Object> accounting = new HashMap<>();
        accounting.put("capacityTotal", new BigDecimal("10"));
        accounting.put("capacity1", new BigDecimal("4"));
        accounting.put("capacity2", new BigDecimal("3"));
        accounting.put("capacity3", new BigDecimal("2"));
        accounting.put("capacity4", BigDecimal.ONE);
        when(mapper.accountingSummaryByOrderIds(anyList())).thenReturn(accounting);
        Map<String, Object> result = service.summary(query);
        assertEquals(new BigDecimal("20.50"), result.get("platformIncome"));
        assertEquals(new BigDecimal("5.00"), result.get("partnerIncomeTotal"));
        assertEquals("40%-30%-20%-10%", result.get("capacityProportion"));
        assertEquals("0%-0%-0%-0%", result.get("serviceProportion"));
        verify(mapper, times(2)).shareIncomeSummaryByOrderIds(anyList());
        verify(mapper, times(2)).accountingSummaryByOrderIds(anyList());
    }
    @Test
    void doesNotQueryDetailSummariesWhenNoOrdersMatch() {
        TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl();
        TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class);
        CardChargingOrderQuery query = new CardChargingOrderQuery();
        query.setSiteId(12);
        ReflectionTestUtils.setField(service, "baseMapper", mapper);
        when(mapper.summary(any(), isNull(), isNull(), isNull(), isNull())).thenReturn(new HashMap<>());
        when(mapper.summaryOrderIds(any(), isNull(), isNull(), isNull(), isNull())).thenReturn(Collections.emptyList());
        Map<String, Object> result = service.summary(query);
        assertEquals(BigDecimal.ZERO, result.get("platformIncome"));
        assertEquals("0%-0%-0%-0%", result.get("electronicProportion"));
        verify(mapper, times(0)).shareIncomeSummaryByOrderIds(anyList());
        verify(mapper, times(0)).accountingSummaryByOrderIds(anyList());
    }
    @Test
    void buildsFourPeriodProportionWithTwoDecimalRounding() {
        TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl();
        Map<String, BigDecimal> summary = new HashMap<>();
        summary.put("capacityTotal", new BigDecimal("3"));
        summary.put("capacity1", BigDecimal.ONE);
        summary.put("capacity2", BigDecimal.ONE);
        summary.put("capacity3", BigDecimal.ONE);
        summary.put("capacity4", BigDecimal.ZERO);
        String proportion = ReflectionTestUtils.invokeMethod(service, "buildProportion", summary, "capacity");
        assertEquals("33.33%-33.33%-33.33%-0%", proportion);
    }
    @Test
    void returnsZeroProportionWhenThereIsNoAccountingData() {
        TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl();
        Map<String, BigDecimal> summary = ReflectionTestUtils.invokeMethod(service, "emptyAccountingSummary");
        String proportion = ReflectionTestUtils.invokeMethod(service, "buildProportion", summary, "electric");
        assertEquals("0%-0%-0%-0%", proportion);
    }
}