| | |
| | | |
| | | Map<String, Object> accountingSummaryByOrderIds(@Param("orderIds") List<Long> orderIds); |
| | | |
| | | List<Map<String, Object>> capacitySummaryByOrderIds(@Param("orderIds") List<Long> orderIds); |
| | | |
| | | List<Map<String, Object>> balanceIncomeDetail(@Param("query") CardChargingOrderQuery query); |
| | | |
| | | List<Map<String, Object>> accountingStrategyList(@Param("chargingOrderId") Long chargingOrderId); |
| | |
| | | query.setSiteIds(siteIds); |
| | | } |
| | | |
| | | private void fillElectronicProportion(List<ChargingOrderVO> list) { |
| | | List<Long> orderIds = list.stream().map(ChargingOrderVO::getId).filter(Objects::nonNull).collect(Collectors.toList()); |
| | | if (orderIds.isEmpty()) { |
| | | return; |
| | | } |
| | | List<Map<String, Object>> capacityRows = new ArrayList<>(); |
| | | int batchSize = 500; |
| | | for (int i = 0; i < orderIds.size(); i += batchSize) { |
| | | List<Long> batchIds = orderIds.subList(i, Math.min(i + batchSize, orderIds.size())); |
| | | capacityRows.addAll(Optional.ofNullable(baseMapper.capacitySummaryByOrderIds(batchIds)) |
| | | .orElse(Collections.emptyList())); |
| | | } |
| | | Map<Long, Map<String, Object>> capacityByOrderId = capacityRows.stream() |
| | | .filter(item -> item.get("orderId") != null) |
| | | .collect(Collectors.toMap(item -> Long.valueOf(item.get("orderId").toString()), item -> item, (a, b) -> a)); |
| | | for (ChargingOrderVO order : list) { |
| | | Map<String, Object> capacity = capacityByOrderId.get(order.getId()); |
| | | Map<String, BigDecimal> summary = emptyAccountingSummary(); |
| | | if (capacity != null) { |
| | | for (String key : new String[]{"capacityTotal", "capacity1", "capacity2", "capacity3", "capacity4"}) { |
| | | summary.put(key, summaryDecimal(capacity, key)); |
| | | } |
| | | } |
| | | order.setElectronicProportion(buildProportion(summary, "capacity")); |
| | | } |
| | | } |
| | | |
| | | private void fillPageExtra(List<ChargingOrderVO> list) { |
| | | if (list == null || list.isEmpty()) { |
| | | return; |
| | | } |
| | | fillElectronicProportion(list); |
| | | List<Integer> siteIds = list.stream().map(ChargingOrderVO::getSiteId).filter(Objects::nonNull).distinct().collect(Collectors.toList()); |
| | | List<Integer> gunIds = list.stream().map(ChargingOrderVO::getChargingGunId).filter(Objects::nonNull).distinct().collect(Collectors.toList()); |
| | | List<Long> carIds = list.stream().map(ChargingOrderVO::getAppUserCarId).filter(Objects::nonNull).distinct().collect(Collectors.toList()); |
| | |
| | | </sql> |
| | | |
| | | <select id="pageList" resultType="com.ruoyi.order.api.vo.ChargingOrderVO"> |
| | | SELECT o.*, |
| | | CONCAT(IFNULL(ROUND(a.capacity1 / NULLIF(a.capacity_total, 0) * 100, 2), 0), '%-', |
| | | IFNULL(ROUND(a.capacity2 / NULLIF(a.capacity_total, 0) * 100, 2), 0), '%-', |
| | | IFNULL(ROUND(a.capacity3 / NULLIF(a.capacity_total, 0) * 100, 2), 0), '%-', |
| | | IFNULL(ROUND(a.capacity4 / NULLIF(a.capacity_total, 0) * 100, 2), 0), '%') AS electronicProportion |
| | | SELECT o.* |
| | | FROM t_card_charging_order o |
| | | 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 |
| | | FROM t_card_charging_order_accounting_strategy |
| | | GROUP BY charging_order_id |
| | | ) a ON a.charging_order_id = o.id |
| | | <include refid="queryCondition"/> |
| | | ORDER BY o.create_time DESC |
| | | LIMIT #{offset}, #{pageSize} |
| | |
| | | </foreach> |
| | | </select> |
| | | |
| | | <select id="capacitySummaryByOrderIds" resultType="java.util.LinkedHashMap"> |
| | | SELECT charging_order_id AS orderId, |
| | | 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 |
| | | FROM t_card_charging_order_accounting_strategy |
| | | WHERE charging_order_id IN |
| | | <foreach collection="orderIds" item="orderId" open="(" separator="," close=")"> |
| | | #{orderId} |
| | | </foreach> |
| | | GROUP BY charging_order_id |
| | | </select> |
| | | |
| | | <select id="balanceIncomeDetail" resultType="java.util.LinkedHashMap"> |
| | | SELECT o.card_id AS cardId, |
| | | o.card_no AS cardNo, |
| | |
| | | @Test |
| | | void splitsSummaryQueriesForMyCatAndRequiresCompleteTimeRanges() throws IOException { |
| | | String mapper = resource("mapper/order/TCardChargingOrderMapper.xml"); |
| | | String pageList = select(mapper, "pageList"); |
| | | String summary = select(mapper, "summary"); |
| | | String orderIds = select(mapper, "summaryOrderIds"); |
| | | String share = select(mapper, "shareIncomeSummaryByOrderIds"); |
| | | String accounting = select(mapper, "accountingSummaryByOrderIds"); |
| | | String capacity = select(mapper, "capacitySummaryByOrderIds"); |
| | | |
| | | assertTrue(pageList.contains("SELECT o.*")); |
| | | assertFalse(pageList.contains(" JOIN ")); |
| | | assertFalse(pageList.contains("t_card_charging_order_accounting_strategy")); |
| | | assertTrue(summary.contains("FROM t_card_charging_order o")); |
| | | assertFalse(summary.contains(" JOIN ")); |
| | | assertFalse(summary.contains("t_card_charging_order_share_record")); |
| | |
| | | assertTrue(orderIds.contains("<include refid=\"queryCondition\"/>")); |
| | | assertTrue(share.contains("charging_order_id IN")); |
| | | assertTrue(accounting.contains("charging_order_id IN")); |
| | | assertTrue(capacity.contains("charging_order_id AS orderId")); |
| | | assertTrue(capacity.contains("GROUP BY charging_order_id")); |
| | | assertTrue(mapper.contains("startTime1 != null and startTime1 != '' and startTime2 != null and startTime2 != ''")); |
| | | assertTrue(mapper.contains("endTime1 != null and endTime1 != '' and endTime2 != null and endTime2 != ''")); |
| | | } |
| | |
| | | import static org.mockito.ArgumentMatchers.any; |
| | | import static org.mockito.ArgumentMatchers.anyList; |
| | | import static org.mockito.ArgumentMatchers.isNull; |
| | | import static org.mockito.Mockito.doReturn; |
| | | import static org.mockito.Mockito.mock; |
| | | import static org.mockito.Mockito.times; |
| | | import static org.mockito.Mockito.verify; |
| | |
| | | class TCardChargingOrderSummaryTest { |
| | | |
| | | @Test |
| | | void fillsElectronicProportionFromCapacitySummaryInBatches() { |
| | | TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl(); |
| | | TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class); |
| | | ReflectionTestUtils.setField(service, "baseMapper", mapper); |
| | | List<com.ruoyi.order.api.vo.ChargingOrderVO> orders = new ArrayList<>(); |
| | | for (long id = 1; id <= 501; id++) { |
| | | com.ruoyi.order.api.vo.ChargingOrderVO order = new com.ruoyi.order.api.vo.ChargingOrderVO(); |
| | | order.setId(id); |
| | | orders.add(order); |
| | | } |
| | | Map<String, Object> capacity = new HashMap<>(); |
| | | capacity.put("orderId", 1L); |
| | | capacity.put("capacityTotal", new BigDecimal("10")); |
| | | capacity.put("capacity1", new BigDecimal("4")); |
| | | capacity.put("capacity2", new BigDecimal("3")); |
| | | capacity.put("capacity3", new BigDecimal("2")); |
| | | capacity.put("capacity4", BigDecimal.ONE); |
| | | doReturn(Collections.singletonList(capacity), Collections.emptyList()) |
| | | .when(mapper).capacitySummaryByOrderIds(anyList()); |
| | | |
| | | ReflectionTestUtils.invokeMethod(service, "fillElectronicProportion", orders); |
| | | |
| | | assertEquals("40%-30%-20%-10%", orders.get(0).getElectronicProportion()); |
| | | assertEquals("0%-0%-0%-0%", orders.get(500).getElectronicProportion()); |
| | | verify(mapper, times(2)).capacitySummaryByOrderIds(anyList()); |
| | | } |
| | | |
| | | @Test |
| | | void mergesShareAndAccountingSummariesInBatches() { |
| | | TCardChargingOrderServiceImpl service = new TCardChargingOrderServiceImpl(); |
| | | TCardChargingOrderMapper mapper = mock(TCardChargingOrderMapper.class); |
| New file |
| | |
| | | -- Add VIN snapshot column to every physical charging-order shard. |
| | | -- Execute directly on the backend MySQL instance, not through the database proxy. |
| | | -- The procedure is idempotent and only alters existing tables that lack the column. |
| | | |
| | | USE `charging_pile_order`; |
| | | |
| | | DROP PROCEDURE IF EXISTS `add_charging_order_vin`; |
| | | DELIMITER $$ |
| | | CREATE PROCEDURE `add_charging_order_vin`() |
| | | BEGIN |
| | | DECLARE shard_no INT DEFAULT 0; |
| | | DECLARE target_table VARCHAR(64); |
| | | DECLARE table_exists INT DEFAULT 0; |
| | | DECLARE column_exists INT DEFAULT 0; |
| | | |
| | | WHILE shard_no < 50 DO |
| | | SET target_table = CONCAT('t_charging_order_', shard_no); |
| | | |
| | | SELECT COUNT(*) INTO table_exists |
| | | FROM information_schema.tables |
| | | WHERE table_schema = DATABASE() |
| | | AND table_name = target_table; |
| | | |
| | | SELECT COUNT(*) INTO column_exists |
| | | FROM information_schema.columns |
| | | WHERE table_schema = DATABASE() |
| | | AND table_name = target_table |
| | | AND column_name = 'vin'; |
| | | |
| | | IF table_exists = 1 AND column_exists = 0 THEN |
| | | SET @ddl = CONCAT( |
| | | 'ALTER TABLE `', target_table, |
| | | '` ADD COLUMN `vin` varchar(17) NULL AFTER `reservation_time`' |
| | | ); |
| | | PREPARE stmt FROM @ddl; |
| | | EXECUTE stmt; |
| | | DEALLOCATE PREPARE stmt; |
| | | END IF; |
| | | |
| | | SET shard_no = shard_no + 1; |
| | | END WHILE; |
| | | END$$ |
| | | DELIMITER ; |
| | | |
| | | CALL `add_charging_order_vin`(); |
| | | DROP PROCEDURE `add_charging_order_vin`; |
| | | |
| | | SELECT COUNT(*) AS shard_count, |
| | | SUM(CASE WHEN c.column_name = 'vin' THEN 1 ELSE 0 END) AS vin_column_count |
| | | FROM information_schema.tables t |
| | | LEFT JOIN information_schema.columns c |
| | | ON c.table_schema = t.table_schema |
| | | AND c.table_name = t.table_name |
| | | AND c.column_name = 'vin' |
| | | WHERE t.table_schema = DATABASE() |
| | | AND t.table_name REGEXP '^t_charging_order_[0-9]+$'; |