From 8ea02ca30907216aece38fda1ba918e5a5246abe Mon Sep 17 00:00:00 2001
From: puzhibing <393733352@qq.com>
Date: 星期三, 14 十月 2026 15:00:51 +0800
Subject: [PATCH] 修改bug

---
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java                |   29 +++++
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyVinChargingOrderList.java                            |    2 
 ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TCardChargingOrderServiceImpl.java            |   33 ++++++
 ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/TChargingOrderServiceImplVinFallbackTest.java |  101 ++++++++++++++++++++
 ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/CardVinSettlementTimeAlignmentTest.java       |  123 ++++++++++++++++++++++++
 5 files changed, 282 insertions(+), 6 deletions(-)

diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyVinChargingOrderList.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyVinChargingOrderList.java
index 85c1ef4..b64857e 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyVinChargingOrderList.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/dto/MyVinChargingOrderList.java
@@ -1,5 +1,6 @@
 package com.ruoyi.order.dto;
 
+import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
 import io.swagger.annotations.ApiModel;
@@ -39,6 +40,7 @@
     private BigDecimal payMoney;
 
     @ApiModelProperty("订单时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private LocalDateTime createTime;
 
     @ApiModelProperty("订单状态")
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TCardChargingOrderServiceImpl.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TCardChargingOrderServiceImpl.java
index ca6c00f..dac0a1c 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TCardChargingOrderServiceImpl.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TCardChargingOrderServiceImpl.java
@@ -316,8 +316,9 @@
         result.put("endMode", order.getEndMode());
         result.put("phone", order.getPhone());
         result.put("licensePlate", order.getPlateNum());
-        result.put("startSoc", "-");
-        result.put("endSoc", "-");
+        // SOC 展示口径:优先展示结算回填的开始/结束 SOC;历史订单未采集时保持占位符
+        result.put("startSoc", order.getStartSoc() == null ? "-" : order.getStartSoc().toPlainString());
+        result.put("endSoc", order.getEndSoc() == null ? "-" : order.getEndSoc().toPlainString());
         if (order.getStartTime() != null && order.getEndTime() != null) {
             result.put("chargingSecond", ChronoUnit.SECONDS.between(order.getStartTime(), order.getEndTime()));
         }
@@ -1418,6 +1419,9 @@
         final BigDecimal svcTotal = serviceChargeTotal;
         final BigDecimal discountElecTotal = discountElectricTotal;
         final BigDecimal discountSvcTotal = discountServiceTotal;
+        // SOC 回填(与 VIN 结算同口径):取订单最早/最新实时监控上报,读取失败不阻断结算
+        final BigDecimal startSoc = getMonitoringSocQuietly(code, "asc");
+        final BigDecimal endSoc = getMonitoringSocQuietly(code, "desc");
         // 剩余金额口径:可用金额基数(建单写入的 charge_amount) - 本单金额;
         // 改造前创建的老订单无基数时以本单金额兜底(剩余金额记 0),并顺带补齐 charge_amount
         final BigDecimal chargeBase = order.getChargeAmount() != null ? order.getChargeAmount() : orderAmount;
@@ -1455,6 +1459,13 @@
             update.setStatus(ORDER_STATUS_FINISHED);
             if (order.getEndMode() == null) {
                 update.setEndMode(1);
+            }
+            // SOC 回填:监控数据缺失/查询异常时不覆盖既有值,与 VIN 结算行为一致
+            if (startSoc != null) {
+                update.setStartSoc(startSoc);
+            }
+            if (endSoc != null) {
+                update.setEndSoc(endSoc);
             }
             if (preferentialBackfill) {
                 // 历史订单(快照为空)实时查询结果回填订单快照列,保证后续补偿重算口径一致
@@ -1498,6 +1509,24 @@
     }
 
     /**
+     * 容错读取订单最早/最新监控记录的 SOC(与 VIN 结算同口径):
+     * Mongo 数据缺失、SOC 未上报或查询异常返回 null,不阻断主结算流程。
+     */
+    private BigDecimal getMonitoringSocQuietly(String code, String sort) {
+        if (uploadRealTimeMonitoringDataService == null) {
+            return null;
+        }
+        try {
+            UploadRealTimeMonitoringData monitoringData = uploadRealTimeMonitoringDataService.getDataByOrderCode(code, sort);
+            return monitoringData == null || monitoringData.getSoc() == null
+                    ? null : BigDecimal.valueOf(monitoringData.getSoc().longValue());
+        } catch (Exception ex) {
+            log.error("[SD结算] 查询监控SOC失败 code={} sort={}", code, sort, ex);
+            return null;
+        }
+    }
+
+    /**
      * 结算刷卡账户资金(实扣冻结口径,与 VIN 链路同构):
      * 1) 分配模式:解锁卡片锁定额并按实际消费扣减(允许扣成负数),差额退回卡账户;
      * 2) 共享模式:解锁企业账户锁定额并按实际消费扣减,差额退回企业账户;
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
index eec9c0e..900dda3 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -2852,7 +2852,14 @@
                 .eq(TChargingOrder::getDelFlag, 0)
                 .orderByDesc(TChargingOrder::getCreateTime)
                 .last(" limit 0, 1"));
-        if (null == one || !one.getAppUserId().equals(userId)) {
+        if (null != one && !userId.equals(one.getAppUserId())) {
+            one = null;
+        }
+        // 普通订单在充电中(2=启动中/3=充电中/4=停止中)时直接返回,保持原快路径不变;
+        // 普通订单已结束(5)或不存在时才与 VIN 码订单比较:未结束订单优先,其次取创建时间更近的一笔。
+        // 避免同一把枪先有普通订单完成、随后 VIN 码充电时,充电页被历史完成订单抢占而误入
+        // 「充电完成」弹窗,导致用户无法停止充电。
+        if (null == one || !isActiveStatus(one.getStatus())) {
             // VIN 码充电订单兜底:VD 订单存于 t_vin_charging_order,且后付模式无支付动作,
             // 不按 rechargePaymentStatus 过滤;TVinChargingOrder 继承 TChargingOrder,后续组装原样复用
             // 状态同样包含已结束(5),保证 VIN 订单结束后前端仍能拿到完成态
@@ -2863,10 +2870,12 @@
                     .eq(TVinChargingOrder::getDelFlag, 0)
                     .orderByDesc(TVinChargingOrder::getCreateTime)
                     .last(" limit 0, 1"));
-            if (null == vinOrder) {
-                return null;
+            if (null != vinOrder && (isActiveStatus(vinOrder.getStatus()) || null == one || isNewerOrder(vinOrder, one))) {
+                one = vinOrder;
             }
-            one = vinOrder;
+        }
+        if (null == one) {
+            return null;
         }
         ChargingDetails chargingDetails = new ChargingDetails();
         chargingDetails.setId(one.getId().toString());
@@ -2911,6 +2920,18 @@
     }
 
 
+    /** 订单是否为未结束状态:2=启动中、3=充电中、4=停止中(5=已结束 不算未结束) */
+    private boolean isActiveStatus(Integer status) {
+        return null != status && status >= 2 && status <= 4;
+    }
+
+    /** candidate 订单创建时间是否晚于 current(createTime 缺失时按“不更晚”处理,保持普通订单优先的历史行为) */
+    private boolean isNewerOrder(TChargingOrder candidate, TChargingOrder current) {
+        return null != candidate.getCreateTime()
+                && (null == current.getCreateTime() || candidate.getCreateTime().isAfter(current.getCreateTime()));
+    }
+
+
     /**
      * 停止充电操作
      *
diff --git a/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/CardVinSettlementTimeAlignmentTest.java b/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/CardVinSettlementTimeAlignmentTest.java
index c89d9dc..6a07c95 100644
--- a/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/CardVinSettlementTimeAlignmentTest.java
+++ b/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/CardVinSettlementTimeAlignmentTest.java
@@ -503,6 +503,129 @@
         });
     }
 
+    // ===== SD:结算从监控数据回填开始/结束 SOC(与 VIN 链路同口径) =====
+
+    @Test
+    @SuppressWarnings("unchecked")
+    void cardSettlementBackfillsSocFromMonitoringData() throws InterruptedException {
+        TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl();
+        ReflectionTestUtils.setField(service, "chargeAccountSupport", newChargeAccountSupport());
+        TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class);
+        ChargingCardClient cardClient = mock(ChargingCardClient.class);
+        ChargingGunClient gunClient = mock(ChargingGunClient.class);
+        UploadRealTimeMonitoringDataService monitoringDataService = mock(UploadRealTimeMonitoringDataService.class);
+        TCardAccountingStrategyDetailOrderService detailOrderService = mock(TCardAccountingStrategyDetailOrderService.class);
+        TCardChargingOrderAccountingStrategyService strategyService = mock(TCardChargingOrderAccountingStrategyService.class);
+        TransactionTemplate txTemplate = mock(TransactionTemplate.class);
+        ReflectionTestUtils.setField(service, "baseMapper", mapper);
+        ReflectionTestUtils.setField(service, "chargingCardClient", cardClient);
+        ReflectionTestUtils.setField(service, "chargingGunClient", gunClient);
+        ReflectionTestUtils.setField(service, "uploadRealTimeMonitoringDataService", monitoringDataService);
+        ReflectionTestUtils.setField(service, "cardAccountingStrategyDetailOrderService", detailOrderService);
+        ReflectionTestUtils.setField(service, "cardChargingOrderAccountingStrategyService", strategyService);
+        ReflectionTestUtils.setField(service, "transactionTemplate", txTemplate);
+        ReflectionTestUtils.setField(service, "redissonClient", mockedRedisson(mockedLock(true)));
+
+        TCardChargingOrder charging = new TCardChargingOrder();
+        charging.setId(1L);
+        charging.setCode("SD1");
+        charging.setStatus(4);
+        charging.setCardId(5L);
+        charging.setChargingGunId(9);
+        charging.setChargeAmount(new BigDecimal("100.00"));
+        charging.setStartTime(LocalDateTime.of(2026, 9, 14, 7, 30, 0));
+        charging.setEndTime(LocalDateTime.of(2026, 9, 14, 21, 45, 0));
+        when(mapper.selectOne(any())).thenReturn(charging);
+        when(mapper.updateById(any())).thenReturn(1);
+
+        UploadRealTimeMonitoringData firstMonitoring = new UploadRealTimeMonitoringData();
+        firstMonitoring.setSoc(18);
+        UploadRealTimeMonitoringData lastMonitoring = new UploadRealTimeMonitoringData();
+        lastMonitoring.setSoc(87);
+        when(monitoringDataService.getDataByOrderCode("SD1", "asc")).thenReturn(firstMonitoring);
+        when(monitoringDataService.getDataByOrderCode("SD1", "desc")).thenReturn(lastMonitoring);
+
+        stubGunAndUpdate(gunClient, 9);
+        stubCardDeductAndUnlock(cardClient);
+        stubCardStrategyQuerySave(detailOrderService, strategyService, cardThreePeriodSnapshots());
+        stubTxExecute(txTemplate);
+
+        TransactionRecordMessageVO vo = new TransactionRecordMessageVO();
+        vo.setTransaction_serial_number("SD1");
+        vo.setSpike_charge1(new BigDecimal("3"));
+        vo.setFlat_charge2(new BigDecimal("5"));
+        vo.setValley_charge3(new BigDecimal("8"));
+
+        R result = service.cardEndChargeBillingCharge(vo);
+        assertEquals(R.SUCCESS, result.getCode());
+
+        ArgumentCaptor<TCardChargingOrder> orderCaptor = ArgumentCaptor.forClass(TCardChargingOrder.class);
+        verify(mapper).updateById(orderCaptor.capture());
+        assertEquals(0, new BigDecimal("18").compareTo(orderCaptor.getValue().getStartSoc()));
+        assertEquals(0, new BigDecimal("87").compareTo(orderCaptor.getValue().getEndSoc()));
+        verify(monitoringDataService).getDataByOrderCode("SD1", "asc");
+        verify(monitoringDataService).getDataByOrderCode("SD1", "desc");
+    }
+
+    // ===== SD:监控数据缺失时不覆盖订单 SOC(保持历史行为) =====
+
+    @Test
+    @SuppressWarnings("unchecked")
+    void cardSettlementKeepsSocWhenMonitoringMissing() throws InterruptedException {
+        TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl();
+        ReflectionTestUtils.setField(service, "chargeAccountSupport", newChargeAccountSupport());
+        TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class);
+        ChargingCardClient cardClient = mock(ChargingCardClient.class);
+        ChargingGunClient gunClient = mock(ChargingGunClient.class);
+        UploadRealTimeMonitoringDataService monitoringDataService = mock(UploadRealTimeMonitoringDataService.class);
+        TCardAccountingStrategyDetailOrderService detailOrderService = mock(TCardAccountingStrategyDetailOrderService.class);
+        TCardChargingOrderAccountingStrategyService strategyService = mock(TCardChargingOrderAccountingStrategyService.class);
+        TransactionTemplate txTemplate = mock(TransactionTemplate.class);
+        ReflectionTestUtils.setField(service, "baseMapper", mapper);
+        ReflectionTestUtils.setField(service, "chargingCardClient", cardClient);
+        ReflectionTestUtils.setField(service, "chargingGunClient", gunClient);
+        ReflectionTestUtils.setField(service, "uploadRealTimeMonitoringDataService", monitoringDataService);
+        ReflectionTestUtils.setField(service, "cardAccountingStrategyDetailOrderService", detailOrderService);
+        ReflectionTestUtils.setField(service, "cardChargingOrderAccountingStrategyService", strategyService);
+        ReflectionTestUtils.setField(service, "transactionTemplate", txTemplate);
+        ReflectionTestUtils.setField(service, "redissonClient", mockedRedisson(mockedLock(true)));
+
+        TCardChargingOrder charging = new TCardChargingOrder();
+        charging.setId(1L);
+        charging.setCode("SD1");
+        charging.setStatus(4);
+        charging.setCardId(5L);
+        charging.setChargingGunId(9);
+        charging.setChargeAmount(new BigDecimal("100.00"));
+        charging.setStartTime(LocalDateTime.of(2026, 9, 14, 7, 30, 0));
+        charging.setEndTime(LocalDateTime.of(2026, 9, 14, 21, 45, 0));
+        when(mapper.selectOne(any())).thenReturn(charging);
+        when(mapper.updateById(any())).thenReturn(1);
+
+        // 首末监控记录均缺失(设备未上报或数据已过期)
+        when(monitoringDataService.getDataByOrderCode("SD1", "asc")).thenReturn(null);
+        when(monitoringDataService.getDataByOrderCode("SD1", "desc")).thenReturn(null);
+
+        stubGunAndUpdate(gunClient, 9);
+        stubCardDeductAndUnlock(cardClient);
+        stubCardStrategyQuerySave(detailOrderService, strategyService, cardThreePeriodSnapshots());
+        stubTxExecute(txTemplate);
+
+        TransactionRecordMessageVO vo = new TransactionRecordMessageVO();
+        vo.setTransaction_serial_number("SD1");
+        vo.setSpike_charge1(new BigDecimal("3"));
+        vo.setFlat_charge2(new BigDecimal("5"));
+        vo.setValley_charge3(new BigDecimal("8"));
+
+        R result = service.cardEndChargeBillingCharge(vo);
+        assertEquals(R.SUCCESS, result.getCode());
+
+        ArgumentCaptor<TCardChargingOrder> orderCaptor = ArgumentCaptor.forClass(TCardChargingOrder.class);
+        verify(mapper).updateById(orderCaptor.capture());
+        assertNull(orderCaptor.getValue().getStartSoc());
+        assertNull(orderCaptor.getValue().getEndSoc());
+    }
+
     // ===== SD:订单 startTime/endTime 缺失时首末段保持快照兜底 =====
 
     @Test
diff --git a/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/TChargingOrderServiceImplVinFallbackTest.java b/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/TChargingOrderServiceImplVinFallbackTest.java
index 3b32ec4..c498df5 100644
--- a/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/TChargingOrderServiceImplVinFallbackTest.java
+++ b/ruoyi-service/ruoyi-order/src/test/java/com/ruoyi/order/service/impl/TChargingOrderServiceImplVinFallbackTest.java
@@ -47,6 +47,7 @@
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -303,6 +304,106 @@
         assertStatusFilterCoversFinished(captor.getValue());
     }
 
+    @Test
+    void getChargingDetailsPrefersActiveVinOrderOverFinishedNormalOrder() {
+        // 同一把枪:普通订单已完成(5),随后 VIN 码订单充电中(3)。
+        // 充电页必须拿到未结束的 VIN 订单,否则会误入「充电完成」弹窗、用户无法停止充电
+        LoginUserApplet loginUser = new LoginUserApplet();
+        loginUser.setUserId(88L);
+        when(tokenService.getLoginUserApplet()).thenReturn(loginUser);
+        TChargingOrder finishedNormalOrder = new TChargingOrder();
+        finishedNormalOrder.setId(3003L);
+        finishedNormalOrder.setAppUserId(88L);
+        finishedNormalOrder.setChargingGunId(5);
+        finishedNormalOrder.setStatus(5);
+        finishedNormalOrder.setCode("CH20261014001");
+        finishedNormalOrder.setResidualAmount(new BigDecimal("2.06"));
+        finishedNormalOrder.setCreateTime(LocalDateTime.of(2026, 10, 14, 14, 22, 49));
+        when(mapper.selectOne(any())).thenReturn(finishedNormalOrder);
+        TVinChargingOrder activeVinOrder = new TVinChargingOrder();
+        activeVinOrder.setId(2002L);
+        activeVinOrder.setAppUserId(88L);
+        activeVinOrder.setChargingGunId(5);
+        activeVinOrder.setStatus(3);
+        activeVinOrder.setCode("VD20261014002");
+        activeVinOrder.setResidualAmount(new BigDecimal("3.44"));
+        activeVinOrder.setCreateTime(LocalDateTime.of(2026, 10, 14, 14, 38, 30));
+        when(vinChargingOrderMapper.selectOne(any())).thenReturn(activeVinOrder);
+        stubGunPileAndSite();
+        when(uploadRealTimeMonitoringDataService.getLastDataById("VD20261014002")).thenReturn(null);
+
+        ChargingDetails details = service.getChargingDetails(5);
+
+        assertNotNull(details, "普通订单已结束时不应定格完成态,应返回充电中的 VIN 订单");
+        assertEquals("2002", details.getId());
+        assertEquals(Integer.valueOf(3), details.getStatus());
+        assertEquals("VD20261014002", details.getCode());
+        assertEquals(0, new BigDecimal("3.44").compareTo(details.getChargingCost()));
+    }
+
+    @Test
+    void getChargingDetailsKeepsActiveNormalOrderWithoutQueryingVinOrder() {
+        // 普通订单充电中(3)时走原快路径直接返回,不再查询 VIN 订单表
+        LoginUserApplet loginUser = new LoginUserApplet();
+        loginUser.setUserId(88L);
+        when(tokenService.getLoginUserApplet()).thenReturn(loginUser);
+        TChargingOrder activeNormalOrder = new TChargingOrder();
+        activeNormalOrder.setId(3004L);
+        activeNormalOrder.setAppUserId(88L);
+        activeNormalOrder.setChargingGunId(5);
+        activeNormalOrder.setStatus(3);
+        activeNormalOrder.setCode("CH20261014002");
+        activeNormalOrder.setResidualAmount(new BigDecimal("8.80"));
+        activeNormalOrder.setCreateTime(LocalDateTime.of(2026, 10, 14, 15, 0));
+        when(mapper.selectOne(any())).thenReturn(activeNormalOrder);
+        stubGunPileAndSite();
+        when(uploadRealTimeMonitoringDataService.getLastDataById("CH20261014002")).thenReturn(null);
+
+        ChargingDetails details = service.getChargingDetails(5);
+
+        assertNotNull(details);
+        assertEquals("3004", details.getId());
+        assertEquals(Integer.valueOf(3), details.getStatus());
+        assertEquals("CH20261014002", details.getCode());
+        verify(vinChargingOrderMapper, never()).selectOne(any());
+    }
+
+    @Test
+    void getChargingDetailsPrefersNewerFinishedOrderWhenBothFinished() {
+        // 两笔均已结束(5)时取创建时间更近的一笔:VIN 订单结束后完成页应展示 VIN 订单,而非更早的普通订单
+        LoginUserApplet loginUser = new LoginUserApplet();
+        loginUser.setUserId(88L);
+        when(tokenService.getLoginUserApplet()).thenReturn(loginUser);
+        TChargingOrder finishedNormalOrder = new TChargingOrder();
+        finishedNormalOrder.setId(3003L);
+        finishedNormalOrder.setAppUserId(88L);
+        finishedNormalOrder.setChargingGunId(5);
+        finishedNormalOrder.setStatus(5);
+        finishedNormalOrder.setCode("CH20261014001");
+        finishedNormalOrder.setResidualAmount(new BigDecimal("2.06"));
+        finishedNormalOrder.setCreateTime(LocalDateTime.of(2026, 10, 14, 14, 22, 49));
+        when(mapper.selectOne(any())).thenReturn(finishedNormalOrder);
+        TVinChargingOrder finishedVinOrder = new TVinChargingOrder();
+        finishedVinOrder.setId(2003L);
+        finishedVinOrder.setAppUserId(88L);
+        finishedVinOrder.setChargingGunId(5);
+        finishedVinOrder.setStatus(5);
+        finishedVinOrder.setCode("VD20261014003");
+        finishedVinOrder.setResidualAmount(new BigDecimal("5.20"));
+        finishedVinOrder.setCreateTime(LocalDateTime.of(2026, 10, 14, 14, 42, 26));
+        when(vinChargingOrderMapper.selectOne(any())).thenReturn(finishedVinOrder);
+        stubGunPileAndSite();
+        when(uploadRealTimeMonitoringDataService.getLastDataById("VD20261014003")).thenReturn(null);
+
+        ChargingDetails details = service.getChargingDetails(5);
+
+        assertNotNull(details);
+        assertEquals("2003", details.getId());
+        assertEquals(Integer.valueOf(5), details.getStatus());
+        assertEquals("VD20261014003", details.getCode());
+        assertEquals(0, new BigDecimal("5.20").compareTo(details.getChargingCost()));
+    }
+
     /** getChargingDetails 组装链路依赖的充电枪/充电桩/站点远程调用 stub */
     private void stubGunPileAndSite() {
         TChargingGun gun = new TChargingGun();

--
Gitblit v1.7.1