| | |
| | | import com.ruoyi.order.util.mongodb.service.UploadRealTimeMonitoringDataService; |
| | | import com.ruoyi.order.vo.EndOfChargePageInfo; |
| | | import com.baomidou.mybatisplus.core.MybatisConfiguration; |
| | | import com.baomidou.mybatisplus.core.conditions.AbstractWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; |
| | | import com.ruoyi.system.api.model.LoginUserApplet; |
| | | import org.apache.ibatis.builder.MapperBuilderAssistant; |
| | |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.junit.jupiter.api.extension.ExtendWith; |
| | | import org.mockito.ArgumentCaptor; |
| | | import org.mockito.InjectMocks; |
| | | import org.mockito.Mock; |
| | | import org.mockito.junit.jupiter.MockitoExtension; |
| | |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.junit.jupiter.api.Assertions.assertNotNull; |
| | | 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.verify; |
| | | import static org.mockito.Mockito.when; |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | @Test |
| | | void getChargingDetailsUsesPaidAmountAsUsedCostWhenRealTimeDataPresent() { |
| | | LoginUserApplet loginUser = new LoginUserApplet(); |
| | | loginUser.setUserId(88L); |
| | | when(tokenService.getLoginUserApplet()).thenReturn(loginUser); |
| | | when(mapper.selectOne(any())).thenReturn(null); |
| | | TVinChargingOrder vinOrder = new TVinChargingOrder(); |
| | | vinOrder.setId(1001L); |
| | | vinOrder.setAppUserId(88L); |
| | | vinOrder.setChargingGunId(5); |
| | | vinOrder.setStatus(3); |
| | | vinOrder.setCode("VD20261013001"); |
| | | vinOrder.setResidualAmount(new BigDecimal("66.60")); |
| | | when(vinChargingOrderMapper.selectOne(any())).thenReturn(vinOrder); |
| | | TChargingGun gun = new TChargingGun(); |
| | | gun.setChargingPileId(7); |
| | | when(chargingGunClient.getChargingGunById(5)).thenReturn(R.ok(gun)); |
| | | TChargingPile pile = new TChargingPile(); |
| | | pile.setName("1号桩"); |
| | | pile.setSiteId(9); |
| | | when(chargingPileClient.getChargingPileById(7)).thenReturn(R.ok(pile)); |
| | | Site site = new Site(); |
| | | site.setName("城东站"); |
| | | when(siteClient.getSiteByIds(Arrays.asList(9))).thenReturn(R.ok(Collections.singletonList(site))); |
| | | UploadRealTimeMonitoringData data = new UploadRealTimeMonitoringData(); |
| | | data.setOutput_current(new BigDecimal("10")); |
| | | data.setOutput_voltage(new BigDecimal("220")); |
| | | data.setSoc(50); |
| | | data.setTime_remaining(30); |
| | | data.setCharging_degree(new BigDecimal("5.5")); |
| | | data.setCumulative_charging_time(75); |
| | | // 设备上报已充金额为 4 位小数,展示口径统一保留 2 位 |
| | | data.setPaid_amount(new BigDecimal("12.3456")); |
| | | when(uploadRealTimeMonitoringDataService.getLastDataById("VD20261013001")).thenReturn(data); |
| | | |
| | | ChargingDetails details = service.getChargingDetails(5); |
| | | |
| | | assertEquals(0, new BigDecimal("12.35").compareTo(details.getChargingCost())); |
| | | } |
| | | |
| | | @Test |
| | | void getChargingDetailsReturnsNullWhenNeitherNormalNorVinOrderExists() { |
| | | LoginUserApplet loginUser = new LoginUserApplet(); |
| | | loginUser.setUserId(88L); |
| | |
| | | assertNotNull(exception); |
| | | assertEquals("充电订单不存在", exception.getMessage()); |
| | | } |
| | | |
| | | @Test |
| | | void getChargingDetailsReturnsFinishedNormalOrderAndQueriesStatus5() { |
| | | // 小程序主动结束充电后订单已结束(5),充电中页面仍需拿到该笔订单, |
| | | // 用于关闭「请勿拔枪,正在结束充电」并展示「充电完成,可拔枪」 |
| | | LoginUserApplet loginUser = new LoginUserApplet(); |
| | | loginUser.setUserId(88L); |
| | | when(tokenService.getLoginUserApplet()).thenReturn(loginUser); |
| | | TChargingOrder order = new TChargingOrder(); |
| | | order.setId(3003L); |
| | | order.setAppUserId(88L); |
| | | order.setChargingGunId(5); |
| | | order.setStatus(5); |
| | | order.setCode("CH20261014001"); |
| | | order.setResidualAmount(new BigDecimal("20.00")); |
| | | when(mapper.selectOne(any())).thenReturn(order); |
| | | stubGunPileAndSite(); |
| | | when(uploadRealTimeMonitoringDataService.getLastDataById("CH20261014001")).thenReturn(null); |
| | | |
| | | ChargingDetails details = service.getChargingDetails(5); |
| | | |
| | | assertNotNull(details, "订单已结束时应返回完成态而非 null"); |
| | | assertEquals("3003", details.getId()); |
| | | assertEquals(Integer.valueOf(5), details.getStatus()); |
| | | assertEquals("CH20261014001", details.getCode()); |
| | | assertEquals(0, new BigDecimal("20.00").compareTo(details.getChargingCost())); |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | ArgumentCaptor<Wrapper<TChargingOrder>> captor = ArgumentCaptor.forClass(Wrapper.class); |
| | | verify(mapper).selectOne(captor.capture()); |
| | | assertStatusFilterCoversFinished(captor.getValue()); |
| | | } |
| | | |
| | | @Test |
| | | void getChargingDetailsReturnsFinishedVinOrderAndQueriesStatus5() { |
| | | // VIN 码订单结束后同样需要返回完成态,兜底查询的状态过滤必须与主查询一致 |
| | | LoginUserApplet loginUser = new LoginUserApplet(); |
| | | loginUser.setUserId(88L); |
| | | when(tokenService.getLoginUserApplet()).thenReturn(loginUser); |
| | | when(mapper.selectOne(any())).thenReturn(null); |
| | | TVinChargingOrder vinOrder = new TVinChargingOrder(); |
| | | vinOrder.setId(1001L); |
| | | vinOrder.setAppUserId(88L); |
| | | vinOrder.setChargingGunId(5); |
| | | vinOrder.setStatus(5); |
| | | vinOrder.setCode("VD20261014001"); |
| | | vinOrder.setResidualAmount(new BigDecimal("66.60")); |
| | | when(vinChargingOrderMapper.selectOne(any())).thenReturn(vinOrder); |
| | | stubGunPileAndSite(); |
| | | when(uploadRealTimeMonitoringDataService.getLastDataById("VD20261014001")).thenReturn(null); |
| | | |
| | | ChargingDetails details = service.getChargingDetails(5); |
| | | |
| | | assertNotNull(details, "VIN 订单已结束时应返回完成态而非 null"); |
| | | assertEquals(Integer.valueOf(5), details.getStatus()); |
| | | assertEquals("VD20261014001", details.getCode()); |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | ArgumentCaptor<Wrapper<TVinChargingOrder>> captor = ArgumentCaptor.forClass(Wrapper.class); |
| | | verify(vinChargingOrderMapper).selectOne(captor.capture()); |
| | | assertStatusFilterCoversFinished(captor.getValue()); |
| | | } |
| | | |
| | | /** getChargingDetails 组装链路依赖的充电枪/充电桩/站点远程调用 stub */ |
| | | private void stubGunPileAndSite() { |
| | | TChargingGun gun = new TChargingGun(); |
| | | gun.setChargingPileId(7); |
| | | when(chargingGunClient.getChargingGunById(5)).thenReturn(R.ok(gun)); |
| | | TChargingPile pile = new TChargingPile(); |
| | | pile.setName("1号桩"); |
| | | pile.setSiteId(9); |
| | | when(chargingPileClient.getChargingPileById(7)).thenReturn(R.ok(pile)); |
| | | Site site = new Site(); |
| | | site.setName("城东站"); |
| | | when(siteClient.getSiteByIds(Arrays.asList(9))).thenReturn(R.ok(Collections.singletonList(site))); |
| | | } |
| | | |
| | | /** |
| | | * 断言订单查询条件中的 status 过滤覆盖 2、3、4、5。 |
| | | * 已结束(5) 必须在过滤范围内,否则小程序结束充电后拿不到订单,会一直停留在「正在结束充电」提示。 |
| | | */ |
| | | private void assertStatusFilterCoversFinished(Wrapper<?> wrapper) { |
| | | AbstractWrapper<?, ?, ?> queryWrapper = (AbstractWrapper<?, ?, ?>) wrapper; |
| | | Matcher inMatcher = Pattern.compile("status\\s+in\\s*\\(([^)]*)\\)", Pattern.CASE_INSENSITIVE) |
| | | .matcher(queryWrapper.getSqlSegment()); |
| | | assertTrue(inMatcher.find(), "查询条件中应存在 status IN 过滤"); |
| | | List<Object> statusValues = new ArrayList<>(); |
| | | Matcher placeholderMatcher = Pattern.compile("MPGENVAL\\d+").matcher(inMatcher.group(1)); |
| | | while (placeholderMatcher.find()) { |
| | | statusValues.add(queryWrapper.getParamNameValuePairs().get(placeholderMatcher.group())); |
| | | } |
| | | assertTrue(statusValues.containsAll(Arrays.asList(2, 3, 4, 5)), |
| | | "status 过滤应包含 2,3,4,5,实际为:" + statusValues); |
| | | } |
| | | } |