فهرست منبع

fix(charging): 优化充电订单分布式锁处理逻辑

- 调整充电流程中订单查询为分布式锁机制,防止并发更新数据冲突
- 修正停止充电异常提示,简化错误信息提示
- 停止充电结果处理新增分布式锁,避免重复状态更新
- 完善订单完成状态处理,优化订单结算和账户余额扣减流程
- 充电订单优惠和服务费计算逻辑调整与完善
- 注释掉熔断保护余额不足判断功能
- 调整XSS和SQL注入防护配置,dev和prod环境均关闭相关防护
- 修改合作方渠道通知接口调用逻辑以适配加锁后的订单处理
- 修正部分日志输出,增加锁获取失败和中断日志提示
- 更新WFT支付订单测试数据,调整退款相关字段值
wzq 2 هفته پیش
والد
کامیت
c5ced03ee7

+ 2 - 1
src/main/java/com/zsElectric/boot/business/service/ChargeOrderInfoService.java

@@ -1,5 +1,6 @@
 package com.zsElectric.boot.business.service;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.zsElectric.boot.business.model.dto.ChargeOrderInfoExportDTO;
 import com.zsElectric.boot.business.model.entity.ChargeOrderInfo;
 import com.zsElectric.boot.business.model.form.ChargeOrderInfoForm;
@@ -65,7 +66,7 @@ public interface ChargeOrderInfoService extends IService<ChargeOrderInfo> {
 
     IPage<ChargeOrderInfoVO> getPage(AppChargeOrderInfoQuery queryParams);
 
-    AppChargeVO invokeCharge(AppInvokeChargeForm formData);
+    AppChargeVO invokeCharge(AppInvokeChargeForm formData) throws JsonProcessingException;
 
     AppChargeVO stopCharge(AppStopChargeForm formData);
 

+ 3 - 3
src/main/java/com/zsElectric/boot/business/service/WFTOrderService.java

@@ -1111,12 +1111,12 @@ public class WFTOrderService {
     public static void main(String[] args) throws IOException {
         SortedMap<String, String> params = new TreeMap<>();
         SwiftpassConfig swiftpassConfig = new SwiftpassConfig();
-        params.put("transaction_id", "2301202601062012757716");//商户订单号
+        params.put("transaction_id", "2301202601162014907802");//商户订单号
 //        params.put("out_trade_no", "ZSWL20251201000000201343");//商户订单号
-        params.put("out_refund_no", "TK2301202601062012757716");//商户退款单号
+        params.put("out_refund_no", "TK2301202601162014907802");//商户退款单号
         params.put("attach", "");//退款原因
         params.put("total_fee", "3000");//原订单金额
-        params.put("refund_fee", "1566");//退款金额
+        params.put("refund_fee", "1904");//退款金额
         params.put("sign_type", "RSA_1_256");
         PayUtill payUtill = new PayUtill();
         swiftpassConfig.setKey("f5131b3f07acb965a59041b690a29911");

+ 2 - 2
src/main/java/com/zsElectric/boot/business/service/impl/ChargeOrderInfoServiceImpl.java

@@ -333,7 +333,7 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
             StopChargingOperationResponseVO stopChargingOperationResponseVO = chargingBusinessService.stopCharging(chargeOrderInfo.getStartChargeSeq(), chargeOrderInfo.getConnectorId());
 
             if (!Objects.equals(stopChargingOperationResponseVO.getSuccStat(), SystemConstants.STATUS_ZERO)) {
-                throw new BusinessException("停止充电失败,请切换设备或稍后再重试!");
+                throw new BusinessException("停止充电失败,请稍后再重试!");
             }
 
             // 更新订单状态为停止中(状态3)
@@ -346,7 +346,7 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
             return appInvokeChargeVO;
         } catch (Exception e) {
             log.error("停止充电失败,系统错误", e);
-            throw new BusinessException("停止充电失败,请切换设备或稍后再重试!");
+            throw new BusinessException("停止充电失败,请稍后再重试!");
         }
     }
 

+ 288 - 235
src/main/java/com/zsElectric/boot/charging/service/impl/ChargingReceptionServiceImpl.java

@@ -141,11 +141,12 @@ public class ChargingReceptionServiceImpl implements ChargingReceptionService {
      * 通用充电请求处理模板
      */
     private ResponseParmsEntity processChargeRequest(RequestParmsEntity requestDTO, Consumer<JsonNode> businessHandler) {
+        String startChargeSeq = null;
         try {
             JsonNode jsonNode = verifyAndDecrypt(requestDTO);
 
             //查询订单
-            String startChargeSeq = getTextValue(jsonNode, "StartChargeSeq");
+            startChargeSeq = getTextValue(jsonNode, "StartChargeSeq");
             String stopReason = getTextValue(jsonNode, "StopReason");
             String endTime = getTextValue(jsonNode, "EndTime");
             String startTime = getTextValue(jsonNode, "StartTime");
@@ -155,233 +156,259 @@ public class ChargingReceptionServiceImpl implements ChargingReceptionService {
             String totalSeviceMoney = getTextValue(jsonNode, "TotalSeviceMoney");
             String connectorID = getTextValue(jsonNode, "ConnectorID");
 
-            ChargeOrderInfo chargeOrderInfo = chargeOrderInfoService.getOne(new LambdaQueryWrapper<ChargeOrderInfo>()
-                    .eq(ChargeOrderInfo::getStartChargeSeq, startChargeSeq).last("LIMIT 1"));
-
-            if (ObjectUtil.isNotEmpty(chargeOrderInfo)) {
-                if (Objects.equals(chargeOrderInfo.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)) {
-                    //订单信息渠道方推送
-                    Map<String, Object> map = objectMapper.convertValue(jsonNode, Map.class);
-                    map.put("chargeOrderNo", chargeOrderInfo.getChargeOrderNo());
-                    FirmInfo firmInfo = firmInfoMapper.selectById(chargeOrderInfo.getFirmId());
-                    if (ObjectUtil.isNotNull(firmInfo)) {
-                        okHttpUtil.doPostForm(firmInfo.getChannelUrl() + "/notification_charge_order_info", map, null);
-                    }
-                }
-                //推送订单明细
-                chargeOrderInfo.setChargeDetails(jsonNode.toString());
-
-                //优惠单价
-                BigDecimal discountPrice = BigDecimal.ZERO;
-
-                if (Objects.equals(chargeOrderInfo.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)) {
-                    //判断当前订单是否为首单
-                    Long userId = chargeOrderInfo.getUserId();
-                    List<ChargeOrderInfo> list = chargeOrderInfoService.list(Wrappers.<ChargeOrderInfo>lambdaQuery().eq(ChargeOrderInfo::getUserId, userId).eq(ChargeOrderInfo::getStatus,
-                            SystemConstants.STATUS_THREE));
-                    if (ObjectUtil.isEmpty(list)) {
-                        DiscountsActivity discountsActivity = discountsActivityMapper.selectOne(Wrappers.<DiscountsActivity>lambdaQuery()
-                                .eq(DiscountsActivity::getType, SystemConstants.STATUS_ONE)
-                                .eq(DiscountsActivity::getStatus, SystemConstants.STATUS_ONE)
-                                .last("LIMIT 1"));
-                        if (ObjectUtil.isNotEmpty(discountsActivity)) {
-                            chargeOrderInfo.setDiscountInfoId(discountsActivity.getId());
-                            chargeOrderInfo.setDiscountDesc(discountsActivity.getActivityDesc());
-                            discountPrice = discountsActivity.getDiscount();
-                        }
-                    }
-                }
-
-                chargeOrderInfo.setStopReason(stopReason);
-                chargeOrderInfo.setStartTime(startTime);
-                chargeOrderInfo.setEndTime(endTime);
-                chargeOrderInfo.setTotalCharge(new BigDecimal(totalPower));
-
-                chargeOrderInfo.setThirdPartyTotalCost(new BigDecimal(totalMoney));
-                chargeOrderInfo.setThirdPartyServerfee(new BigDecimal(totalSeviceMoney));
-                chargeOrderInfo.setThirdPartyElecfee(new BigDecimal(totalElecMoney));
-
-                ThirdPartyConnectorInfo thirdPartyConnectorInfo = connectorInfoMapper.selectOne(Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
-                        .eq(ThirdPartyConnectorInfo::getConnectorId, connectorID).last("LIMIT 1"));
-                String stationId = thirdPartyConnectorInfo.getStationId();
-                ThirdPartyStationInfo thirdPartyStationInfo = thirdPartyStationInfoMapper.selectOne(Wrappers.<ThirdPartyStationInfo>lambdaQuery()
-                        .eq(ThirdPartyStationInfo::getStationId, stationId).last("LIMIT 1"));
-                if (ObjectUtil.isEmpty(thirdPartyConnectorInfo)) {
-                    log.error("thirdPartyConnectorInfo" + "为空===============================================");
-                }
+            // 使用分布式锁防止并发操作
+            String lockKey = CHARGE_ORDER_LOCK_KEY + startChargeSeq;
+            RLock lock = redissonClient.getLock(lockKey);
+            final String finalStartChargeSeq = startChargeSeq;
+            
+            try {
+                if (lock.tryLock(LOCK_WAIT_TIME, LOCK_LEASE_TIME, java.util.concurrent.TimeUnit.SECONDS)) {
+                    try {
+                        // 加锁后重新查询订单状态,确保状态最新
+                        ChargeOrderInfo chargeOrderInfo = chargeOrderInfoService.getOne(new LambdaQueryWrapper<ChargeOrderInfo>()
+                                .eq(ChargeOrderInfo::getStartChargeSeq, finalStartChargeSeq).last("LIMIT 1"));
 
-                //平台服务费
-                BigDecimal serviceFee = BigDecimal.ZERO;
-                //优惠金额
-                BigDecimal discountFee = BigDecimal.ZERO;
-                JsonNode chargeDetails = jsonNode.get("ChargeDetails");
-                if (ObjectUtil.isNotEmpty(chargeDetails)) {
-                    for (JsonNode node : chargeDetails) {
-                        //提取字段值
-                        String itemFlag = node.get("ItemFlag").asText();
-                        node.get("DetailPower").asText();
-                        BigDecimal detailPower = new BigDecimal(node.get("DetailPower").asText());
-                        PolicyFee policyFee = policyFeeMapper.selectOne(Wrappers.<PolicyFee>lambdaQuery()
-                                .eq(PolicyFee::getStationInfoId, thirdPartyStationInfo.getId())
-                                .eq(PolicyFee::getPeriodFlag, Integer.parseInt(itemFlag))
-                                .last("LIMIT 1"));
-                        if (ObjectUtil.isNotEmpty(policyFee)) {
-                            BigDecimal opFee = policyFee.getOpFee();
-                            if (ObjectUtil.isNotEmpty(chargeOrderInfo.getDiscountInfoId())) {
-                                opFee = opFee.subtract(discountPrice);
+                        if (ObjectUtil.isNotEmpty(chargeOrderInfo)) {
+                            // 检查订单状态,如果已经是已完成状态,则跳过处理
+                            if (Objects.equals(chargeOrderInfo.getStatus(), SystemConstants.STATUS_THREE)) {
+                                log.info("订单已完成,跳过处理 - startChargeSeq: {}", finalStartChargeSeq);
+                                businessHandler.accept(jsonNode);
+                                return buildChargeResponse(finalStartChargeSeq);
                             }
-                            log.info("策略费用:{}", opFee);
-                            serviceFee = serviceFee.add(opFee.multiply(detailPower));
-                            discountFee = discountFee.add(discountPrice.multiply(detailPower));
-                        }
-                    }
-                } else {
-                    log.error("充电订单明细为空===============================================");
-                    if (chargeOrderInfo.getThirdPartyTotalCost().compareTo(BigDecimal.ZERO) > 0 && chargeOrderInfo.getTotalCharge().compareTo(BigDecimal.ZERO) > 0) {
-                        //判断当前订单创建时间在哪个时段
-                        ThirdPartyChargeStatus thirdPartyChargeStatus = chargeStatusMapper.selectOne(Wrappers.<ThirdPartyChargeStatus>lambdaQuery()
-                                .eq(ThirdPartyChargeStatus::getStartChargeSeq, chargeOrderInfo.getStartChargeSeq()));
-
-                        ThirdPartyEquipmentPricePolicy thirdPartyEquipmentPricePolicy = thirdPartyEquipmentPricePolicyMapper.selectOne(Wrappers.<ThirdPartyEquipmentPricePolicy>lambdaQuery()
-                                .eq(ThirdPartyEquipmentPricePolicy::getConnectorId, thirdPartyChargeStatus.getConnectorId())
-                                .last("LIMIT 1"));
-                        
-                        // 查询该价格策略下的所有时段信息,按startTime升序排列
-                        List<ThirdPartyPolicyInfo> allPolicyInfos = thirdPartyPolicyInfoMapper.selectList(Wrappers.<ThirdPartyPolicyInfo>lambdaQuery()
-                                .eq(ThirdPartyPolicyInfo::getPricePolicyId, thirdPartyEquipmentPricePolicy.getId())
-                                .orderByAsc(ThirdPartyPolicyInfo::getStartTime));
-                        
-                        // 将充电开始时间和结束时间转换为HHmmss格式字符串进行匹配
-                        LocalDateTime chargeStartTime = thirdPartyChargeStatus.getStartTime();
-                        LocalDateTime chargeEndTime = thirdPartyChargeStatus.getEndTime();
-                        String chargeStartTimeStr = chargeStartTime.format(DateTimeFormatter.ofPattern("HHmmss"));
-                        String chargeEndTimeStr = chargeEndTime.format(DateTimeFormatter.ofPattern("HHmmss"));
-                        
-                        // 找到充电开始时间所在的时段索引
-                        int startIndex = -1;
-                        for (int i = allPolicyInfos.size() - 1; i >= 0; i--) {
-                            if (chargeStartTimeStr.compareTo(allPolicyInfos.get(i).getStartTime()) >= 0) {
-                                startIndex = i;
-                                break;
+                            
+                            if (Objects.equals(chargeOrderInfo.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)) {
+                                //订单信息渠道方推送
+                                Map<String, Object> map = objectMapper.convertValue(jsonNode, Map.class);
+                                map.put("chargeOrderNo", chargeOrderInfo.getChargeOrderNo());
+                                FirmInfo firmInfo = firmInfoMapper.selectById(chargeOrderInfo.getFirmId());
+                                if (ObjectUtil.isNotNull(firmInfo)) {
+                                    okHttpUtil.doPostForm(firmInfo.getChannelUrl() + "/notification_charge_order_info", map, null);
+                                }
                             }
-                        }
-                        if (startIndex == -1 && !allPolicyInfos.isEmpty()) {
-                            startIndex = allPolicyInfos.size() - 1;
-                        }
-                        
-                        // 找到充电结束时间所在的时段索引
-                        int endIndex = -1;
-                        for (int i = allPolicyInfos.size() - 1; i >= 0; i--) {
-                            if (chargeEndTimeStr.compareTo(allPolicyInfos.get(i).getStartTime()) >= 0) {
-                                endIndex = i;
-                                break;
+                            //推送订单明细
+                            chargeOrderInfo.setChargeDetails(jsonNode.toString());
+
+                            //优惠单价
+                            BigDecimal discountPrice = BigDecimal.ZERO;
+
+                            if (Objects.equals(chargeOrderInfo.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)) {
+                                //判断当前订单是否为首单
+                                Long userId = chargeOrderInfo.getUserId();
+                                List<ChargeOrderInfo> list = chargeOrderInfoService.list(Wrappers.<ChargeOrderInfo>lambdaQuery().eq(ChargeOrderInfo::getUserId, userId).eq(ChargeOrderInfo::getStatus,
+                                        SystemConstants.STATUS_THREE));
+                                if (ObjectUtil.isEmpty(list)) {
+                                    DiscountsActivity discountsActivity = discountsActivityMapper.selectOne(Wrappers.<DiscountsActivity>lambdaQuery()
+                                            .eq(DiscountsActivity::getType, SystemConstants.STATUS_ONE)
+                                            .eq(DiscountsActivity::getStatus, SystemConstants.STATUS_ONE)
+                                            .last("LIMIT 1"));
+                                    if (ObjectUtil.isNotEmpty(discountsActivity)) {
+                                        chargeOrderInfo.setDiscountInfoId(discountsActivity.getId());
+                                        chargeOrderInfo.setDiscountDesc(discountsActivity.getActivityDesc());
+                                        discountPrice = discountsActivity.getDiscount();
+                                    }
+                                }
                             }
-                        }
-                        if (endIndex == -1 && !allPolicyInfos.isEmpty()) {
-                            endIndex = allPolicyInfos.size() - 1;
-                        }
-                        
-                        // 获取充电时间跨越的所有时段集合
-                        List<ThirdPartyPolicyInfo> matchedPolicyInfos = new ArrayList<>();
-                        if (startIndex != -1 && endIndex != -1) {
-                            if (startIndex <= endIndex) {
-                                // 同一天内:从开始时段到结束时段
-                                for (int i = startIndex; i <= endIndex; i++) {
-                                    matchedPolicyInfos.add(allPolicyInfos.get(i));
+
+                            chargeOrderInfo.setStopReason(stopReason);
+                            chargeOrderInfo.setStartTime(startTime);
+                            chargeOrderInfo.setEndTime(endTime);
+                            chargeOrderInfo.setTotalCharge(new BigDecimal(totalPower));
+
+                            chargeOrderInfo.setThirdPartyTotalCost(new BigDecimal(totalMoney));
+                            chargeOrderInfo.setThirdPartyServerfee(new BigDecimal(totalSeviceMoney));
+                            chargeOrderInfo.setThirdPartyElecfee(new BigDecimal(totalElecMoney));
+
+                            ThirdPartyConnectorInfo thirdPartyConnectorInfo = connectorInfoMapper.selectOne(Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
+                                    .eq(ThirdPartyConnectorInfo::getConnectorId, connectorID).last("LIMIT 1"));
+                            String stationId = thirdPartyConnectorInfo.getStationId();
+                            ThirdPartyStationInfo thirdPartyStationInfo = thirdPartyStationInfoMapper.selectOne(Wrappers.<ThirdPartyStationInfo>lambdaQuery()
+                                    .eq(ThirdPartyStationInfo::getStationId, stationId).last("LIMIT 1"));
+                            if (ObjectUtil.isEmpty(thirdPartyConnectorInfo)) {
+                                log.error("thirdPartyConnectorInfo" + "为空===============================================");
+                            }
+
+                            //平台服务费
+                            BigDecimal serviceFee = BigDecimal.ZERO;
+                            //优惠金额
+                            BigDecimal discountFee = BigDecimal.ZERO;
+                            JsonNode chargeDetails = jsonNode.get("ChargeDetails");
+                            if (ObjectUtil.isNotEmpty(chargeDetails)) {
+                                for (JsonNode node : chargeDetails) {
+                                    //提取字段值
+                                    String itemFlag = node.get("ItemFlag").asText();
+                                    node.get("DetailPower").asText();
+                                    BigDecimal detailPower = new BigDecimal(node.get("DetailPower").asText());
+                                    PolicyFee policyFee = policyFeeMapper.selectOne(Wrappers.<PolicyFee>lambdaQuery()
+                                            .eq(PolicyFee::getStationInfoId, thirdPartyStationInfo.getId())
+                                            .eq(PolicyFee::getPeriodFlag, Integer.parseInt(itemFlag))
+                                            .last("LIMIT 1"));
+                                    if (ObjectUtil.isNotEmpty(policyFee)) {
+                                        BigDecimal opFee = policyFee.getOpFee();
+                                        if (ObjectUtil.isNotEmpty(chargeOrderInfo.getDiscountInfoId())) {
+                                            opFee = opFee.subtract(discountPrice);
+                                        }
+                                        log.info("策略费用:{}", opFee);
+                                        serviceFee = serviceFee.add(opFee.multiply(detailPower));
+                                        discountFee = discountFee.add(discountPrice.multiply(detailPower));
+                                    }
                                 }
                             } else {
-                                // 跨天情况:从开始时段到最后 + 从第一个到结束时段
-                                for (int i = startIndex; i < allPolicyInfos.size(); i++) {
-                                    matchedPolicyInfos.add(allPolicyInfos.get(i));
-                                }
-                                for (int i = 0; i <= endIndex; i++) {
-                                    matchedPolicyInfos.add(allPolicyInfos.get(i));
-                                }
-                            }
-                        }
-                        
-                        log.info("充电时间段:{} - {},匹配到{}个时段", chargeStartTimeStr, chargeEndTimeStr, matchedPolicyInfos.size());
-                        
-                        // 遍历所有匹配的时段,找到费用最高的时段计算服务费
-                        if (!matchedPolicyInfos.isEmpty()) {
-                            PolicyFee maxPolicyFee = null;
-                            ThirdPartyPolicyInfo maxPolicyInfo = null;
-                            for (ThirdPartyPolicyInfo policyInfo : matchedPolicyInfos) {
-                                PolicyFee policyFee = policyFeeMapper.selectOne(Wrappers.<PolicyFee>lambdaQuery()
-                                        .eq(PolicyFee::getStationInfoId, thirdPartyStationInfo.getId())
-                                        .eq(PolicyFee::getPeriodFlag, policyInfo.getPeriodFlag())
-                                        .last("LIMIT 1"));
-                                if (ObjectUtil.isNotEmpty(policyFee)) {
-                                    if (maxPolicyFee == null || policyFee.getOpFee().compareTo(maxPolicyFee.getOpFee()) > 0) {
-                                        maxPolicyFee = policyFee;
-                                        maxPolicyInfo = policyInfo;
+                                log.error("充电订单明细为空===============================================");
+                                if (chargeOrderInfo.getThirdPartyTotalCost().compareTo(BigDecimal.ZERO) > 0 && chargeOrderInfo.getTotalCharge().compareTo(BigDecimal.ZERO) > 0) {
+                                    //判断当前订单创建时间在哪个时段
+                                    ThirdPartyChargeStatus thirdPartyChargeStatus = chargeStatusMapper.selectOne(Wrappers.<ThirdPartyChargeStatus>lambdaQuery()
+                                            .eq(ThirdPartyChargeStatus::getStartChargeSeq, chargeOrderInfo.getStartChargeSeq()));
+
+                                    ThirdPartyEquipmentPricePolicy thirdPartyEquipmentPricePolicy = thirdPartyEquipmentPricePolicyMapper.selectOne(Wrappers.<ThirdPartyEquipmentPricePolicy>lambdaQuery()
+                                            .eq(ThirdPartyEquipmentPricePolicy::getConnectorId, thirdPartyChargeStatus.getConnectorId())
+                                            .last("LIMIT 1"));
+                                    
+                                    // 查询该价格策略下的所有时段信息,按startTime升序排列
+                                    List<ThirdPartyPolicyInfo> allPolicyInfos = thirdPartyPolicyInfoMapper.selectList(Wrappers.<ThirdPartyPolicyInfo>lambdaQuery()
+                                            .eq(ThirdPartyPolicyInfo::getPricePolicyId, thirdPartyEquipmentPricePolicy.getId())
+                                            .orderByAsc(ThirdPartyPolicyInfo::getStartTime));
+                                    
+                                    // 将充电开始时间和结束时间转换为HHmmss格式字符串进行匹配
+                                    LocalDateTime chargeStartTime = thirdPartyChargeStatus.getStartTime();
+                                    LocalDateTime chargeEndTime = thirdPartyChargeStatus.getEndTime();
+                                    String chargeStartTimeStr = chargeStartTime.format(DateTimeFormatter.ofPattern("HHmmss"));
+                                    String chargeEndTimeStr = chargeEndTime.format(DateTimeFormatter.ofPattern("HHmmss"));
+                                    
+                                    // 找到充电开始时间所在的时段索引
+                                    int startIndex = -1;
+                                    for (int i = allPolicyInfos.size() - 1; i >= 0; i--) {
+                                        if (chargeStartTimeStr.compareTo(allPolicyInfos.get(i).getStartTime()) >= 0) {
+                                            startIndex = i;
+                                            break;
+                                        }
+                                    }
+                                    if (startIndex == -1 && !allPolicyInfos.isEmpty()) {
+                                        startIndex = allPolicyInfos.size() - 1;
+                                    }
+                                    
+                                    // 找到充电结束时间所在的时段索引
+                                    int endIndex = -1;
+                                    for (int i = allPolicyInfos.size() - 1; i >= 0; i--) {
+                                        if (chargeEndTimeStr.compareTo(allPolicyInfos.get(i).getStartTime()) >= 0) {
+                                            endIndex = i;
+                                            break;
+                                        }
+                                    }
+                                    if (endIndex == -1 && !allPolicyInfos.isEmpty()) {
+                                        endIndex = allPolicyInfos.size() - 1;
+                                    }
+                                    
+                                    // 获取充电时间跨越的所有时段集合
+                                    List<ThirdPartyPolicyInfo> matchedPolicyInfos = new ArrayList<>();
+                                    if (startIndex != -1 && endIndex != -1) {
+                                        if (startIndex <= endIndex) {
+                                            // 同一天内:从开始时段到结束时段
+                                            for (int i = startIndex; i <= endIndex; i++) {
+                                                matchedPolicyInfos.add(allPolicyInfos.get(i));
+                                            }
+                                        } else {
+                                            // 跨天情况:从开始时段到最后 + 从第一个到结束时段
+                                            for (int i = startIndex; i < allPolicyInfos.size(); i++) {
+                                                matchedPolicyInfos.add(allPolicyInfos.get(i));
+                                            }
+                                            for (int i = 0; i <= endIndex; i++) {
+                                                matchedPolicyInfos.add(allPolicyInfos.get(i));
+                                            }
+                                        }
+                                    }
+                                    
+                                    log.info("充电时间段:{} - {},匹配到{}个时段", chargeStartTimeStr, chargeEndTimeStr, matchedPolicyInfos.size());
+                                    
+                                    // 遍历所有匹配的时段,找到费用最高的时段计算服务费
+                                    if (!matchedPolicyInfos.isEmpty()) {
+                                        PolicyFee maxPolicyFee = null;
+                                        ThirdPartyPolicyInfo maxPolicyInfo = null;
+                                        for (ThirdPartyPolicyInfo policyInfo : matchedPolicyInfos) {
+                                            PolicyFee policyFee = policyFeeMapper.selectOne(Wrappers.<PolicyFee>lambdaQuery()
+                                                    .eq(PolicyFee::getStationInfoId, thirdPartyStationInfo.getId())
+                                                    .eq(PolicyFee::getPeriodFlag, policyInfo.getPeriodFlag())
+                                                    .last("LIMIT 1"));
+                                            if (ObjectUtil.isNotEmpty(policyFee)) {
+                                                if (maxPolicyFee == null || policyFee.getOpFee().compareTo(maxPolicyFee.getOpFee()) > 0) {
+                                                    maxPolicyFee = policyFee;
+                                                    maxPolicyInfo = policyInfo;
+                                                }
+                                            }
+                                        }
+                                        if (maxPolicyFee != null) {
+                                            log.info("使用最高费用时段:startTime={}, periodFlag={}, opFee={}", 
+                                                    maxPolicyInfo.getStartTime(), maxPolicyInfo.getPeriodFlag(), maxPolicyFee.getOpFee());
+                                            serviceFee = serviceFee.add(maxPolicyFee.getOpFee().multiply(chargeOrderInfo.getTotalCharge()));
+                                        }
                                     }
                                 }
                             }
-                            if (maxPolicyFee != null) {
-                                log.info("使用最高费用时段:startTime={}, periodFlag={}, opFee={}", 
-                                        maxPolicyInfo.getStartTime(), maxPolicyInfo.getPeriodFlag(), maxPolicyFee.getOpFee());
-                                serviceFee = serviceFee.add(maxPolicyFee.getOpFee().multiply(chargeOrderInfo.getTotalCharge()));
-                            }
-                        }
-                    }
-                }
 
-                log.info("计算后的平台服务费:{}", serviceFee);
-                if (chargeOrderInfo.getOrderType().equals(SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)) {
-                    chargeOrderInfo.setDiscountMoney(discountFee);
-                    chargeOrderInfo.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
-                    //订单结算:平台实际收取金额 = 互联互通金额 + 中数电动金额(平台总服务费)
-                    chargeOrderInfo.setRealCost(chargeOrderInfo.getRealServiceCost().add(chargeOrderInfo.getThirdPartyTotalCost()));
+                            log.info("计算后的平台服务费:{}", serviceFee);
+                            if (chargeOrderInfo.getOrderType().equals(SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)) {
+                                chargeOrderInfo.setDiscountMoney(discountFee);
+                                chargeOrderInfo.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
+                                //订单结算:平台实际收取金额 = 互联互通金额 + 中数电动金额(平台总服务费)
+                                chargeOrderInfo.setRealCost(chargeOrderInfo.getRealServiceCost().add(chargeOrderInfo.getThirdPartyTotalCost()));
 
-                    //订单状态->已完成
-                    chargeOrderInfo.setStatus(SystemConstants.STATUS_THREE);
+                                //订单状态->已完成
+                                chargeOrderInfo.setStatus(SystemConstants.STATUS_THREE);
 
-                    //计算充电时间
-                    chargeOrderInfo.setChargeTime(DateUtils.getDuration(chargeOrderInfo.getStartTime(), chargeOrderInfo.getEndTime()));
+                                //计算充电时间
+                                chargeOrderInfo.setChargeTime(DateUtils.getDuration(chargeOrderInfo.getStartTime(), chargeOrderInfo.getEndTime()));
 
-                    //修改订单
-                    chargeOrderInfoService.updateById(chargeOrderInfo);
+                                //修改订单
+                                chargeOrderInfoService.updateById(chargeOrderInfo);
 
-                    //账户余额扣减(积分增加)
-                    log.info("执行账户余额扣减(积分增加)");
-                    chargeOrderInfoService.orderSettlement(chargeOrderInfo.getId());
-                }
-                if (chargeOrderInfo.getOrderType().equals(SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)) {
-                    chargeOrderInfo.setRealServiceCost(BigDecimal.ZERO);
-                    //订单结算:平台实际收取金额 = 互联互通金额 + 中数电动金额(平台总服务费)
-                    chargeOrderInfo.setRealCost(chargeOrderInfo.getRealServiceCost().add(chargeOrderInfo.getThirdPartyTotalCost()));
-                    //订单状态->已完成
-                    chargeOrderInfo.setStatus(SystemConstants.STATUS_THREE);
-                    //计算充电时间
-                    chargeOrderInfo.setChargeTime(DateUtils.getDuration(chargeOrderInfo.getStartTime(), chargeOrderInfo.getEndTime()));
-                    //修改订单
-                    chargeOrderInfoService.updateById(chargeOrderInfo);
-                    //渠道方账户余额扣减
-                    BigDecimal cost = chargeOrderInfo.getRealCost();
-                    FirmInfo firmInfo = firmInfoMapper.selectById(chargeOrderInfo.getFirmId());
-                    FirmAccountLog accountLog = new FirmAccountLog();
-                    accountLog.setFirmId(firmInfo.getId());
-                    accountLog.setFirmType(firmInfo.getFirmType());
-                    accountLog.setEventDesc("渠道方充电订单下账");
-                    accountLog.setSerialNo(chargeOrderInfo.getChargeOrderNo());
-                    accountLog.setIncomeType(2);
-                    accountLog.setBeforeChange(firmInfo.getBalance());
-                    accountLog.setAfterChange(firmInfo.getBalance().subtract(cost));
-                    accountLog.setMoneyChange(cost);
-                    firmAccountLogMapper.insert(accountLog);
-
-                    // 渠道方账户余额修改
-                    firmInfo.setBalance(firmInfo.getBalance().subtract(cost));
-                    firmInfoMapper.updateById(firmInfo);
+                                //账户余额扣减(积分增加)
+                                log.info("执行账户余额扣减(积分增加)");
+                                chargeOrderInfoService.orderSettlement(chargeOrderInfo.getId());
+                            }
+                            if (chargeOrderInfo.getOrderType().equals(SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)) {
+                                chargeOrderInfo.setRealServiceCost(BigDecimal.ZERO);
+                                //订单结算:平台实际收取金额 = 互联互通金额 + 中数电动金额(平台总服务费)
+                                chargeOrderInfo.setRealCost(chargeOrderInfo.getRealServiceCost().add(chargeOrderInfo.getThirdPartyTotalCost()));
+                                //订单状态->已完成
+                                chargeOrderInfo.setStatus(SystemConstants.STATUS_THREE);
+                                //计算充电时间
+                                chargeOrderInfo.setChargeTime(DateUtils.getDuration(chargeOrderInfo.getStartTime(), chargeOrderInfo.getEndTime()));
+                                //修改订单
+                                chargeOrderInfoService.updateById(chargeOrderInfo);
+                                //渠道方账户余额扣减
+                                BigDecimal cost = chargeOrderInfo.getRealCost();
+                                FirmInfo firmInfo = firmInfoMapper.selectById(chargeOrderInfo.getFirmId());
+                                FirmAccountLog accountLog = new FirmAccountLog();
+                                accountLog.setFirmId(firmInfo.getId());
+                                accountLog.setFirmType(firmInfo.getFirmType());
+                                accountLog.setEventDesc("渠道方充电订单下账");
+                                accountLog.setSerialNo(chargeOrderInfo.getChargeOrderNo());
+                                accountLog.setIncomeType(2);
+                                accountLog.setBeforeChange(firmInfo.getBalance());
+                                accountLog.setAfterChange(firmInfo.getBalance().subtract(cost));
+                                accountLog.setMoneyChange(cost);
+                                firmAccountLogMapper.insert(accountLog);
+
+                                // 渠道方账户余额修改
+                                firmInfo.setBalance(firmInfo.getBalance().subtract(cost));
+                                firmInfoMapper.updateById(firmInfo);
+                            }
+
+                            // 执行业务处理
+                            businessHandler.accept(jsonNode);
+                        }
+                    } finally {
+                        lock.unlock();
+                    }
+                } else {
+                    log.warn("获取订单锁失败 - StartChargeSeq: {}", finalStartChargeSeq);
                 }
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                log.error("获取订单锁被中断 - StartChargeSeq: {}", finalStartChargeSeq);
             }
 
-            // 执行业务处理
-            businessHandler.accept(jsonNode);
-
             // 构建响应
-            return buildChargeResponse(getTextValue(jsonNode, "StartChargeSeq"));
+            return buildChargeResponse(startChargeSeq);
         } catch (BusinessException e) {
             throw e;
         } catch (Exception e) {
@@ -447,16 +474,22 @@ public class ChargingReceptionServiceImpl implements ChargingReceptionService {
         }
     }
 
+    /**
+     * 充电订单分布式锁前缀
+     */
+    private static final String CHARGE_ORDER_LOCK_KEY = "charging:order:lock:";
+
     /**
      * 处理停止充电结果推送请求
      * 数据格式:{"ConnectorID":"xxx","FailReason":0,"StartChargeSeq":"xxx","StartChargeSeqStat":4,"SuccStat":0}
      */
     private ResponseParmsEntity processStopChargeResultRequest(RequestParmsEntity requestDTO) {
+        String startChargeSeq = null;
         try {
             JsonNode jsonNode = verifyAndDecrypt(requestDTO);
             
             // 停止充电结果业务处理
-            String startChargeSeq = getTextValue(jsonNode, "StartChargeSeq");
+            startChargeSeq = getTextValue(jsonNode, "StartChargeSeq");
             Integer startChargeSeqStat = getIntValue(jsonNode, "StartChargeSeqStat");
             Integer succStat = getIntValue(jsonNode, "SuccStat");
             Integer failReason = getIntValue(jsonNode, "FailReason");
@@ -464,33 +497,53 @@ public class ChargingReceptionServiceImpl implements ChargingReceptionService {
             log.info("停止充电结果 - StartChargeSeq: {}, Stat: {}, SuccStat: {}, FailReason: {}",
                     startChargeSeq, startChargeSeqStat, succStat, failReason);
             
-            ChargeOrderInfo chargeOrderInfo = chargeOrderInfoService.getOne(new LambdaQueryWrapper<ChargeOrderInfo>()
-                    .eq(ChargeOrderInfo::getStartChargeSeq, startChargeSeq).last("LIMIT 1"));
-            
-            if (startChargeSeqStat != null && ObjectUtil.isNotEmpty(chargeOrderInfo)) {
+            if (startChargeSeqStat != null && startChargeSeqStat == 4) {
+                // 使用分布式锁防止并发操作
+                String lockKey = CHARGE_ORDER_LOCK_KEY + startChargeSeq;
+                RLock lock = redissonClient.getLock(lockKey);
+                try {
+                    if (lock.tryLock(LOCK_WAIT_TIME, LOCK_LEASE_TIME, java.util.concurrent.TimeUnit.SECONDS)) {
+                        try {
+                            // 加锁后重新查询订单状态,确保状态最新
+                            ChargeOrderInfo chargeOrderInfo = chargeOrderInfoService.getOne(new LambdaQueryWrapper<ChargeOrderInfo>()
+                                    .eq(ChargeOrderInfo::getStartChargeSeq, startChargeSeq).last("LIMIT 1"));
+                            
+                            if (ObjectUtil.isNotEmpty(chargeOrderInfo)) {
+                                log.info("已结束 - StartChargeSeq: {}, 当前订单状态: {}", startChargeSeq, chargeOrderInfo.getStatus());
+                                // 仅当状态为0(待充电)或1(充电中)时才更新为结算中,已完成(3)的订单不再处理
+                                if (Objects.equals(chargeOrderInfo.getStatus(), 0) ||
+                                    Objects.equals(chargeOrderInfo.getStatus(), 1)) {
+                                    chargeOrderInfo.setStatus(SystemConstants.STATUS_TWO);
+                                    chargeOrderInfoService.updateById(chargeOrderInfo);
+                                    log.info("更新订单状态为结算中 - orderId: {}", chargeOrderInfo.getId());
+
+                                    // 推送停止充电订单结果
+                                    FirmInfo firmInfo = firmInfoMapper.selectById(chargeOrderInfo.getFirmId());
+                                    if (ObjectUtil.isNotNull(firmInfo)) {
+                                        HashMap<String, Object> map = new HashMap<>();
+                                        map.put("chargeOrderNo", chargeOrderInfo.getChargeOrderNo());
+                                        map.put("status", SystemConstants.STATUS_TWO);
+                                        okHttpUtil.doPostForm(firmInfo.getChannelUrl() + "/notification_stop_charge_result", map, null);
+                                    }
+                                } else {
+                                    log.info("订单状态已更新,跳过处理 - orderId: {}, status: {}", chargeOrderInfo.getId(), chargeOrderInfo.getStatus());
+                                }
+                            }
+                        } finally {
+                            lock.unlock();
+                        }
+                    } else {
+                        log.warn("获取订单锁失败 - StartChargeSeq: {}", startChargeSeq);
+                    }
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    log.error("获取订单锁被中断 - StartChargeSeq: {}", startChargeSeq);
+                }
+            } else if (startChargeSeqStat != null) {
                 switch (startChargeSeqStat) {
                     case 1 -> log.info("启动中 - StartChargeSeq: {}", startChargeSeq);
                     case 2 -> log.info("充电中 - StartChargeSeq: {}", startChargeSeq);
                     case 3 -> log.info("停止中 - StartChargeSeq: {}", startChargeSeq);
-                    case 4 -> {
-                        log.info("已结束 - StartChargeSeq: {}", startChargeSeq);
-                        // 修改订单状态为结算中
-                        if (Objects.equals(chargeOrderInfo.getStatus(), 0) ||
-                            Objects.equals(chargeOrderInfo.getStatus(), 1)) {
-                            chargeOrderInfo.setStatus(SystemConstants.STATUS_TWO);
-                            chargeOrderInfoService.updateById(chargeOrderInfo);
-                            log.info("更新订单状态为结算中 - orderId: {}", chargeOrderInfo.getId());
-
-                            // 推送停止充电订单结果
-                            FirmInfo firmInfo = firmInfoMapper.selectById(chargeOrderInfo.getFirmId());
-                            if (ObjectUtil.isNotNull(firmInfo)) {
-                                HashMap<String, Object> map = new HashMap<>();
-                                map.put("chargeOrderNo", chargeOrderInfo.getChargeOrderNo());
-                                map.put("status", SystemConstants.STATUS_TWO);
-                                okHttpUtil.doPostForm(firmInfo.getChannelUrl() + "/notification_stop_charge_result", map, null);
-                            }
-                        }
-                    }
                     case 5 -> log.info("未知 - StartChargeSeq: {}", startChargeSeq);
                     default -> log.warn("未知状态 - StartChargeSeq: {}, Stat: {}", startChargeSeq, startChargeSeqStat);
                 }
@@ -742,7 +795,7 @@ public class ChargingReceptionServiceImpl implements ChargingReceptionService {
             pushChargeStatusTask(startChargeSeq, chargeStatus);
 
             // 熔断保护 - 余额不足判断
-            isNeedBreak(chargeStatus, chargeOrderInfo);
+//            isNeedBreak(chargeStatus, chargeOrderInfo);
         } catch (Exception e) {
             log.error("保存充电状态数据失败", e);
         }

+ 4 - 4
src/main/resources/application-dev.yml

@@ -133,13 +133,13 @@ security:
   # XSS 和 SQL 注入防护过滤器配置
   filter:
     # 是否启用 XSS 防护
-    xss-enabled: true
+    xss-enabled: false
     # 是否启用 SQL 注入防护
-    sql-injection-enabled: true
+    sql-injection-enabled: false
     # SQL 注入检测严格模式
     # true: 严格模式,可能误判一些正常输入
     # false: 宽松模式,减少误判但可能漏掉一些攻击
-    sql-strict-mode: true
+    sql-strict-mode: false
     # 排除的 URL 路径(不进行安全检查,注意:默认已经排除了 /doc.html、/swagger-ui 等接口文档相关路径)
     exclude-urls:
       - /api/v1/auth/captcha  # 验证码接口
@@ -153,7 +153,7 @@ security:
       - /applet/v1/homePage/test  # 首页测试接口(包含加密数据)
     # 额外需要检查的请求头(默认已检查 User-Agent、Referer、X-Forwarded-For)
     check-headers:
-      - X-Forwarded-For
+#      - X-Forwarded-For
 
 okhttp:
   connect-timeout: 30s

+ 5 - 5
src/main/resources/application-prod.yml

@@ -134,13 +134,13 @@ security:
   # XSS 和 SQL 注入防护过滤器配置
   filter:
     # 是否启用 XSS 防护
-    xss-enabled: true
+    xss-enabled: false
     # 是否启用 SQL 注入防护
-    sql-injection-enabled: true
+    sql-injection-enabled: false
     # SQL 注入检测严格模式
     # true: 严格模式,可能误判一些正常输入
     # false: 宽松模式,减少误判但可能漏掉一些攻击
-    sql-strict-mode: true
+    sql-strict-mode: false
     # 排除的 URL 路径(不进行安全检查,注意:默认已经排除了 /doc.html、/swagger-ui 等接口文档相关路径)
     exclude-urls:
       - /api/v1/auth/captcha  # 验证码接口
@@ -153,8 +153,8 @@ security:
       - /charge-business/v1/linkData/query_token
     # 额外需要检查的请求头(默认已检查 User-Agent、Referer、X-Forwarded-For)
     check-headers:
-      - Referer
-      - X-Forwarded-For
+#      - Referer
+#      - X-Forwarded-For
 
 okhttp:
   connect-timeout: 30s