Explorar o código

feat(business): 增加价格策略日志与同步更新逻辑

- 在AppletHomeServiceImpl中添加详细日志,记录查询流程和结果
- 在ChargingJob中实现价格策略同步任务的执行标记,防止并发调度
- 调整同步任务执行频率为每10分钟一次,增加异常处理和休眠时间
- 缩减OkHttp最大重试次数为2次并调整重试等待时间
- 在PolicyFeeServiceImpl新增添加策略费用前的价格策略数据校验
- 在ThirdPartyChargingServiceImpl实现价格策略变化时同步更新相关policy_fee记录的综合销售费
- 启用ZsElectricBootApplication中的定时任务调度功能@EnableScheduling
SheepHy hai 2 días
pai
achega
160a913993

+ 2 - 0
src/main/java/com/zsElectric/boot/ZsElectricBootApplication.java

@@ -3,6 +3,7 @@ package com.zsElectric.boot;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
+import org.springframework.scheduling.annotation.EnableScheduling;
 
 /**
  * 应用启动类
@@ -12,6 +13,7 @@ import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
  */
 @SpringBootApplication
 @ConfigurationPropertiesScan // 开启配置属性绑定
+@EnableScheduling // 开启Spring定时任务
 public class ZsElectricBootApplication {
 
     public static void main(String[] args) {

+ 31 - 0
src/main/java/com/zsElectric/boot/business/service/impl/AppletHomeServiceImpl.java

@@ -385,9 +385,13 @@ public class AppletHomeServiceImpl implements AppletHomeService {
         // 查询站点信息
         ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectById(stationId);
         if (stationInfo == null) {
+            log.warn("站点信息不存在,stationId: {}", stationId);
             return null;
         }
         
+        log.info("查询站点价格列表,stationId: {}, stationName: {}, station_id字段: {}", 
+                stationId, stationInfo.getStationName(), stationInfo.getStationId());
+        
         AppletStationPriceListVO result = new AppletStationPriceListVO();
         result.setStationId(stationId);
         result.setStationName(stationInfo.getStationName());
@@ -395,6 +399,7 @@ public class AppletHomeServiceImpl implements AppletHomeService {
         
         // 获取当前登录用户ID
         Long userId = SecurityUtils.getUserId();
+        log.info("当前用户ID: {}", userId);
         
         // 查询用户是否为企业用户,获取企业ID
         Long firmId = null;
@@ -406,11 +411,13 @@ public class AppletHomeServiceImpl implements AppletHomeService {
             );
             if (userFirm != null) {
                 firmId = userFirm.getFirmId();
+                log.info("用户所属企业ID: {}", firmId);
             }
         }
         
         // 获取当前时间(HHmmss格式)
         String currentTime = LocalTime.now().format(TIME_FORMATTER);
+        log.info("当前时间: {}", currentTime);
         
         // 查询站点对应的价格策略
         // 1. 先查询充电接口
@@ -421,10 +428,13 @@ public class AppletHomeServiceImpl implements AppletHomeService {
         );
         
         if (connector == null) {
+            log.warn("未找到充电接口信息,station_id: {}", stationInfo.getStationId());
             result.setPriceList(new ArrayList<>());
             return result;
         }
         
+        log.info("找到充电接口,connectorId: {}", connector.getConnectorId());
+        
         // 2. 查询价格策略
         ThirdPartyEquipmentPricePolicy pricePolicy = thirdPartyEquipmentPricePolicyMapper.selectOne(
                 new LambdaQueryWrapper<ThirdPartyEquipmentPricePolicy>()
@@ -434,10 +444,13 @@ public class AppletHomeServiceImpl implements AppletHomeService {
         );
         
         if (pricePolicy == null) {
+            log.warn("未找到价格策略,connectorId: {}", connector.getConnectorId());
             result.setPriceList(new ArrayList<>());
             return result;
         }
         
+        log.info("找到价格策略,pricePolicyId: {}", pricePolicy.getId());
+        
         // 3. 查询价格明细列表
         List<ThirdPartyPolicyInfo> policyInfoList = thirdPartyPolicyInfoMapper.selectList(
                 new LambdaQueryWrapper<ThirdPartyPolicyInfo>()
@@ -446,6 +459,16 @@ public class AppletHomeServiceImpl implements AppletHomeService {
                         .orderByAsc(ThirdPartyPolicyInfo::getStartTime)
         );
         
+        log.info("查询到价格明细记录数: {}", policyInfoList.size());
+        
+        // 如果没有查询到价格策略明细,说明该站点未配置价格策略,直接返回空列表
+        if (policyInfoList.isEmpty()) {
+            log.warn("third_party_policy_info表中没有价格策略数据,pricePolicyId: {}", pricePolicy.getId());
+            result.setPriceList(new ArrayList<>());
+            result.setHasEnterprisePrice(false);
+            return result;
+        }
+        
         // 4. 如果是企业用户,查询企业价格
         Map<String, BigDecimal> enterprisePriceMap = new HashMap<>();
         boolean hasEnterprisePrice = false;
@@ -458,6 +481,9 @@ public class AppletHomeServiceImpl implements AppletHomeService {
                             .eq(PolicyFee::getIsDeleted, 0)
             );
             
+            log.info("查询企业价格记录数: {}, stationInfoId: {}, firmId: {}", 
+                    policyFeeList.size(), stationId, firmId);
+            
             // 如果查询到企业价格记录,设置标志为true
             if (!policyFeeList.isEmpty()) {
                 hasEnterprisePrice = true;
@@ -480,12 +506,17 @@ public class AppletHomeServiceImpl implements AppletHomeService {
                     
                     BigDecimal enterprisePrice = elecPrice.add(servicePrice).add(opFee).add(compSalesFee);
                     enterprisePriceMap.put(policyFee.getStartTime(), enterprisePrice);
+                    log.debug("企业价格计算 - 时段: {}, 电费: {}, 服务费: {}, 运营费: {}, 综合销售费: {}, 企业价: {}",
+                            policyFee.getStartTime(), elecPrice, servicePrice, opFee, compSalesFee, enterprisePrice);
+                } else {
+                    log.warn("未找到匹配的价格策略明细,startTime: {}", policyFee.getStartTime());
                 }
             }
         }
         
         // 设置是否有企业价格
         result.setHasEnterprisePrice(hasEnterprisePrice);
+        log.info("是否有企业价格: {}", hasEnterprisePrice);
         
         // 5. 构建价格列表
         List<AppletStationPriceListVO.PriceItemVO> priceList = new ArrayList<>();

+ 19 - 0
src/main/java/com/zsElectric/boot/business/service/impl/PolicyFeeServiceImpl.java

@@ -49,6 +49,25 @@ public class PolicyFeeServiceImpl implements PolicyFeeService {
 
     @Override
     public boolean addPolicyFee(AddPolicyFeeDTO addPolicyFeeDTO) {
+        // 先校验 third_party_policy_info 表中是否存在对应的价格策略数据
+        ThirdPartyPolicyInfo policyInfo = policyInfoMapper.selectElecAndServicePriceByStation(
+                addPolicyFeeDTO.getStationInfoId(), 
+                addPolicyFeeDTO.getTimePeriod()
+        );
+        
+        if (policyInfo == null) {
+            log.error("无法添加策略费用:third_party_policy_info表中不存在对应的价格策略数据。stationInfoId: {}, timePeriod: {}",
+                    addPolicyFeeDTO.getStationInfoId(), addPolicyFeeDTO.getTimePeriod());
+            throw new IllegalArgumentException(
+                    String.format("站点ID[%d]的时段[%s]未配置价格策略,请先配置third_party_policy_info表数据",
+                            addPolicyFeeDTO.getStationInfoId(), addPolicyFeeDTO.getTimePeriod())
+            );
+        }
+        
+        log.info("校验通过,找到对应的价格策略。stationInfoId: {}, timePeriod: {}, elecPrice: {}, servicePrice: {}",
+                addPolicyFeeDTO.getStationInfoId(), addPolicyFeeDTO.getTimePeriod(), 
+                policyInfo.getElecPrice(), policyInfo.getServicePrice());
+        
         // 根据站点+时段+销售类型+企业/渠道方查询是否已存在
         PolicyFee existPolicyFee = policyFeeMapper.selectOne(Wrappers.<PolicyFee>lambdaQuery()
                 .eq(PolicyFee::getStationInfoId, addPolicyFeeDTO.getStationInfoId())

+ 101 - 0
src/main/java/com/zsElectric/boot/business/service/impl/ThirdPartyChargingServiceImpl.java

@@ -9,6 +9,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.zsElectric.boot.charging.entity.*;
 import com.zsElectric.boot.business.mapper.FirmInfoMapper;
+import com.zsElectric.boot.business.mapper.PolicyFeeMapper;
 import com.zsElectric.boot.business.mapper.ThirdPartyEquipmentInfoMapper;
 import com.zsElectric.boot.business.mapper.ThirdPartyInfoMapper;
 import com.zsElectric.boot.business.mapper.ThirdPartyStationInfoMapper;
@@ -16,6 +17,7 @@ import com.zsElectric.boot.charging.mapper.ThirdPartyConnectorInfoMapper;
 import com.zsElectric.boot.charging.mapper.ThirdPartyEquipmentPricePolicyMapper;
 import com.zsElectric.boot.charging.mapper.ThirdPartyPolicyInfoMapper;
 import com.zsElectric.boot.business.model.entity.FirmInfo;
+import com.zsElectric.boot.business.model.entity.PolicyFee;
 import com.zsElectric.boot.business.model.entity.ThirdPartyInfo;
 import com.zsElectric.boot.business.model.query.ThirdPartyEquipmentInfoQuery;
 import com.zsElectric.boot.business.model.query.ThirdPartyStationInfoQuery;
@@ -59,6 +61,7 @@ public class ThirdPartyChargingServiceImpl implements ThirdPartyChargingService
     private final ThirdPartyPolicyInfoMapper policyInfoMapper;
     private final FirmInfoMapper firmInfoMapper;
     private final ThirdPartyInfoMapper thirdPartyInfoMapper;
+    private final PolicyFeeMapper policyFeeMapper;
     private final ObjectMapper objectMapper;
 
     // ==================== 充电站信息查询 ====================
@@ -655,6 +658,9 @@ public class ThirdPartyChargingServiceImpl implements ThirdPartyChargingService
                 // 存在且数据变化,执行更新
                 updatePolicyInfoDetail(existing, policyInfo);
                 log.debug("价格策略明细更新成功 - policyId: {}, startTime: {}", policyId, policyInfo.getStartTime());
+                
+                // 价格变化后,同步更新 c_policy_fee 表中的 comp_sales_fee
+                updateRelatedPolicyFeeCompSalesFee(policyId, policyInfo.getStartTime());
             } else {
                 // 数据未变化,但仍更新同步时间
                 updateSyncTime(existing);
@@ -700,6 +706,101 @@ public class ThirdPartyChargingServiceImpl implements ThirdPartyChargingService
         existing.setUpdateTime(LocalDateTime.now());
         policyInfoMapper.updateById(existing);
     }
+    
+    /**
+     * 价格策略变化后,同步更新 c_policy_fee 表中的 comp_sales_fee
+     * 根据 pricePolicyId 查询对应的 stationInfoId,然后更新相关的 policy_fee 记录
+     * 
+     * @param policyId 价格策略ID
+     * @param startTime 时段开始时间
+     */
+    private void updateRelatedPolicyFeeCompSalesFee(Long policyId, String startTime) {
+        try {
+            // 1. 通过 policyId 查询 connectorId
+            ThirdPartyEquipmentPricePolicy pricePolicy = pricePolicyMapper.selectById(policyId);
+            if (pricePolicy == null) {
+                log.warn("未找到价格策略记录,policyId: {}", policyId);
+                return;
+            }
+            
+            // 2. 通过 connectorId 查询 stationId
+            ThirdPartyConnectorInfo connector = connectorInfoMapper.selectOne(
+                    Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
+                            .eq(ThirdPartyConnectorInfo::getConnectorId, pricePolicy.getConnectorId())
+                            .last("LIMIT 1")
+            );
+            
+            if (connector == null) {
+                log.warn("未找到充电接口记录,connectorId: {}", pricePolicy.getConnectorId());
+                return;
+            }
+            
+            // 3. 通过 stationId 查询 stationInfoId
+            ThirdPartyStationInfo station = stationInfoMapper.selectOne(
+                    Wrappers.<ThirdPartyStationInfo>lambdaQuery()
+                            .eq(ThirdPartyStationInfo::getStationId, connector.getStationId())
+                            .last("LIMIT 1")
+            );
+            
+            if (station == null) {
+                log.warn("未找到站点记录,stationId: {}", connector.getStationId());
+                return;
+            }
+            
+            // 4. 查询该站点、该时段的所有 policy_fee 记录
+            List<PolicyFee> policyFees = policyFeeMapper.selectList(
+                    Wrappers.<PolicyFee>lambdaQuery()
+                            .eq(PolicyFee::getStationInfoId, station.getId())
+                            .eq(PolicyFee::getStartTime, startTime)
+                            .eq(PolicyFee::getIsDeleted, 0)
+            );
+            
+            if (policyFees.isEmpty()) {
+                log.debug("该站点该时段没有 policy_fee 记录,stationInfoId: {}, startTime: {}", station.getId(), startTime);
+                return;
+            }
+            
+            // 5. 重新计算并更新每条记录的 comp_sales_fee
+            for (PolicyFee policyFee : policyFees) {
+                BigDecimal newCompSalesFee = calculateCompSalesFeeForPolicyFee(
+                        station.getId(), 
+                        startTime, 
+                        policyFee.getOpFee()
+                );
+                
+                policyFee.setCompSalesFee(newCompSalesFee);
+                policyFeeMapper.updateById(policyFee);
+                
+                log.info("更新 policy_fee 的 comp_sales_fee - id: {}, stationInfoId: {}, startTime: {}, salesType: {}, 新值: {}",
+                        policyFee.getId(), station.getId(), startTime, policyFee.getSalesType(), newCompSalesFee);
+            }
+            
+        } catch (Exception e) {
+            log.error("更新 policy_fee 的 comp_sales_fee 失败 - policyId: {}, startTime: {}", policyId, startTime, e);
+            // 不抛出异常,避免影响主流程
+        }
+    }
+    
+    /**
+     * 计算 comp_sales_fee
+     * 公式:compSalesFee = elec_price + service_price + op_fee
+     * 注意:这里不加字典值,与 PolicyFeeServiceImpl 中的计算逻辑保持一致
+     */
+    private BigDecimal calculateCompSalesFeeForPolicyFee(Long stationInfoId, String timePeriod, BigDecimal opFee) {
+        BigDecimal elecPrice = BigDecimal.ZERO;
+        BigDecimal servicePrice = BigDecimal.ZERO;
+        
+        // 查询电价和服务费
+        ThirdPartyPolicyInfo policyInfo = policyInfoMapper.selectElecAndServicePriceByStation(stationInfoId, timePeriod);
+        
+        if (policyInfo != null) {
+            elecPrice = policyInfo.getElecPrice() != null ? policyInfo.getElecPrice() : BigDecimal.ZERO;
+            servicePrice = policyInfo.getServicePrice() != null ? policyInfo.getServicePrice() : BigDecimal.ZERO;
+        }
+        
+        BigDecimal opFeeValue = opFee != null ? opFee : BigDecimal.ZERO;
+        return elecPrice.add(servicePrice).add(opFeeValue);
+    }
 
     /**
      * 保存价格策略明细

+ 26 - 8
src/main/java/com/zsElectric/boot/charging/quartz/ChargingJob.java

@@ -29,6 +29,9 @@ public class ChargingJob {
 
     private final ChargingBusinessService chargingBusinessService;
     private final ThirdPartyConnectorInfoMapper connectorInfoMapper;
+    
+    // 任务执行标记,防止并发执行
+    private volatile boolean isPricePolicySyncRunning = false;
 
     private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 
@@ -71,11 +74,18 @@ public class ChargingJob {
 
     /**
      * 定时同步设备价格策略信息
-     * 每天凌晨5:30执行,查询所有充电桩的价格策略并存储到数据库
-     * cron表达式: 0 30 5 * * ? 表示每天凌晨5点30分执行
+     * 每10分钟执行一次,查询所有充电桩的价格策略并存储到数据库
+     * cron表达式: 0 10 * * * ? 表示每10分钟执行
      */
-    @Scheduled(cron = "0 */3 * * * ?")
+    @Scheduled(cron = "0 */10 * * * ?")
     public void syncEquipmentPricePolicy() {
+        // 检查任务是否正在执行,防止并发
+        if (isPricePolicySyncRunning) {
+            log.warn("价格策略同步任务正在执行中,跳过本次调度");
+            return;
+        }
+        
+        isPricePolicySyncRunning = true;
         log.info("开始执行设备价格策略同步定时任务");
         
         try {
@@ -103,6 +113,10 @@ public class ChargingJob {
                     // 调用业务服务查询价格策略(会自动保存到数据库)
                     ChargingPricePolicyVO result = chargingBusinessService.queryEquipBusinessPolicy(equipmentId, connectorId);
                     
+                    // 立即休眠10秒,避免触发第三方接口保护机制
+                    // 第三方接口可能有频率限制,需要足够的间隔时间
+                    Thread.sleep(18000); // 10秒间隔
+                    
                     if (result != null && result.getSuccStat() != null && result.getSuccStat() == 0) {
                         successCount++;
                         log.info("价格策略同步成功 - connectorId: {}, 时段数: {}", connectorId, result.getSumPeriod());
@@ -112,9 +126,11 @@ public class ChargingJob {
                                 result != null ? result.getFailReason() : "返回结果为空");
                     }
                     
-                    // 适当延迟,避免频繁调用第三方接口
-                    Thread.sleep(500);
-                    
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    log.error("线程休眠被中断 - connectorId: {}", connector.getConnectorId(), e);
+                    failCount++;
+                    break; // 中断后退出循环
                 } catch (Exception e) {
                     failCount++;
                     log.error("同步价格策略失败 - connectorId: {}", connector.getConnectorId(), e);
@@ -125,8 +141,10 @@ public class ChargingJob {
             
         } catch (Exception e) {
             log.error("设备价格策略同步定时任务执行异常", e);
+        } finally {
+            // 确保任务执行完毕后释放锁
+            isPricePolicySyncRunning = false;
+            log.info("设备价格策略同步定时任务执行结束");
         }
-        
-        log.info("设备价格策略同步定时任务执行结束");
     }
 }

+ 5 - 2
src/main/java/com/zsElectric/boot/config/OkHttpConfig.java

@@ -37,7 +37,7 @@ public class OkHttpConfig {
     @Value("${okhttp.connection-pool.keep-alive-duration:300}")
     private Duration keepAliveDuration;
     
-    @Value("${okhttp.max-retry-count:3}")
+    @Value("${okhttp.max-retry-count:2}")
     private int maxRetryCount;
 
     @Bean
@@ -71,7 +71,10 @@ public class OkHttpConfig {
                     if (i > 0) {
                         log.warn("第 {} 次重试请求: {}", i, request.url());
                         // 重试前等待一段时间,使用指数退避策略
-                        Thread.sleep((long) Math.pow(2, i - 1) * 1000);
+                        // 第1次重试等待2秒,第2次等待4秒
+                        long waitTime = (long) Math.pow(2, i) * 1000;
+                        log.info("重试前等待 {} 毫秒", waitTime);
+                        Thread.sleep(waitTime);
                     }
                     response = chain.proceed(request);
                     // 如果响应成功,直接返回