| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796 |
- package com.zsElectric.boot.charging.service.impl;
- import cn.hutool.core.util.ObjUtil;
- import cn.hutool.core.util.ObjectUtil;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.core.toolkit.Wrappers;
- import com.fasterxml.jackson.databind.JsonNode;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.zsElectric.boot.business.mapper.*;
- import com.zsElectric.boot.business.model.entity.*;
- import com.zsElectric.boot.business.service.ChargeOrderInfoService;
- import com.zsElectric.boot.charging.entity.*;
- import com.zsElectric.boot.charging.mapper.ThirdPartyChargeStatusMapper;
- import com.zsElectric.boot.charging.mapper.ThirdPartyConnectorInfoMapper;
- import com.zsElectric.boot.charging.mapper.ThirdPartyPolicyInfoMapper;
- import com.zsElectric.boot.charging.service.ChargingBusinessService;
- import com.zsElectric.boot.charging.service.ChargingReceptionService;
- import com.zsElectric.boot.charging.vo.ChargeResponseVO;
- import com.zsElectric.boot.charging.vo.QueryStationStatusVO;
- import com.zsElectric.boot.common.constant.ConnectivityConstants;
- import com.zsElectric.boot.common.constant.SystemConstants;
- import com.zsElectric.boot.common.util.DateUtils;
- import com.zsElectric.boot.common.util.electric.ChargingUtil;
- import com.zsElectric.boot.common.util.electric.RequestParmsEntity;
- import com.zsElectric.boot.common.util.electric.ResponseParmsEntity;
- import com.zsElectric.boot.core.exception.BusinessException;
- import com.zsElectric.boot.system.mapper.DictItemMapper;
- import com.zsElectric.boot.system.model.entity.DictItem;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.redisson.api.RLock;
- import org.redisson.api.RedissonClient;
- import org.springframework.stereotype.Service;
- import org.springframework.util.CollectionUtils;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.time.LocalDateTime;
- import java.time.format.DateTimeFormatter;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Objects;
- import java.util.concurrent.TimeUnit;
- import java.util.function.Consumer;
- import static com.zsElectric.boot.common.constant.ConnectivityConstants.FAIL_REASON_NONE;
- import static com.zsElectric.boot.common.constant.ConnectivityConstants.STATUS_OK;
- import static com.zsElectric.boot.common.util.HmacMD5Util.genSign;
- import static com.zsElectric.boot.common.util.HmacMD5Util.verify;
- /**
- * 第三方充电推送接收服务实现
- *
- * @author system
- * @since 2025-12-11
- */
- @Slf4j
- @Service
- @RequiredArgsConstructor
- public class ChargingReceptionServiceImpl implements ChargingReceptionService {
- private final ChargingUtil chargingUtil;
- private final ThirdPartyConnectorInfoMapper connectorInfoMapper;
- private final ThirdPartyChargeStatusMapper chargeStatusMapper;
- private final ObjectMapper objectMapper;
- private final ChargeOrderInfoService chargeOrderInfoService;
- private final RedissonClient redissonClient;
- private final UserAccountMapper userAccountMapper;
- private final UserFirmMapper userFirmMapper;
- private final PolicyFeeMapper policyFeeMapper;
- private final DictItemMapper dictItemMapper;
- private final ThirdPartyEquipmentInfoMapper thirdPartyEquipmentInfoMapper;
- private final ChargingBusinessService chargingBusinessService;
- private final ThirdPartyStationInfoMapper thirdPartyStationInfoMapper;
- private final ThirdPartyPolicyInfoMapper thirdPartyPolicyInfoMapper;
- private final DiscountsActivityMapper discountsActivityMapper;
- /**
- * 熔断检查锁前缀
- */
- private static final String BREAK_CHECK_LOCK_KEY = "charging:break:check:";
- /**
- * 锁等待时间(秒)
- */
- private static final long LOCK_WAIT_TIME = 3;
- /**
- * 锁持有时间(秒)
- */
- private static final long LOCK_LEASE_TIME = 10;
- private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
- // ==================== 接口实现 ====================
- @Override
- public ResponseParmsEntity chargeResponse(RequestParmsEntity requestDTO) {
- log.info("接收推送启动充电结果请求参数:{}", requestDTO);
- return processStartChargeResultRequest(requestDTO);
- }
- @Override
- public ResponseParmsEntity chargeStatusResponse(RequestParmsEntity requestDTO) {
- log.info("接收推送充电状态请求参数:{}", requestDTO);
- return processChargeStatusRequest(requestDTO);
- }
- @Override
- public ResponseParmsEntity stopChargeResponse(RequestParmsEntity requestDTO) {
- log.info("接收推送停止充电结果请求参数:{}", requestDTO);
- return processStopChargeResultRequest(requestDTO);
- }
- @Override
- public ResponseParmsEntity chargeOrderResponse(RequestParmsEntity requestDTO) throws Exception {
- log.info("接收推送充电订单信息请求参数:{}", requestDTO);
- return processChargeRequest(requestDTO, jsonNode -> {
- log.debug("充电订单信息 - StartChargeSeq: {}", getTextValue(jsonNode, "StartChargeSeq"));
- });
- }
- @Override
- public ResponseParmsEntity stationStatus(RequestParmsEntity requestDTO) {
- log.info("接收设备状态变化推送请求参数:{}", requestDTO);
- return processStationStatusRequest(requestDTO);
- }
- // ==================== 公共处理方法 ====================
- /**
- * 通用充电请求处理模板
- */
- private ResponseParmsEntity processChargeRequest(RequestParmsEntity requestDTO, Consumer<JsonNode> businessHandler) {
- try {
- JsonNode jsonNode = verifyAndDecrypt(requestDTO);
- //查询订单
- String startChargeSeq = getTextValue(jsonNode, "StartChargeSeq");
- String stopReason = getTextValue(jsonNode, "StopReason");
- String endTime = getTextValue(jsonNode, "EndTime");
- String startTime = getTextValue(jsonNode, "StartTime");
- String totalPower = getTextValue(jsonNode, "TotalPower");
- String totalElecMoney = getTextValue(jsonNode, "TotalElecMoney");
- String totalMoney = getTextValue(jsonNode, "TotalMoney");
- String totalSeviceMoney = getTextValue(jsonNode, "TotalSeviceMoney");
- String connectorID = getTextValue(jsonNode, "ConnectorID");
- ChargeOrderInfo chargeOrderInfo = chargeOrderInfoService.getOne(new LambdaQueryWrapper<ChargeOrderInfo>()
- .eq(ChargeOrderInfo::getStartChargeSeq, startChargeSeq).last("LIMIT 1"));
- //推送订单明细
- chargeOrderInfo.setChargeDetails(jsonNode.toString());
- //优惠单价
- BigDecimal discountPrice = BigDecimal.ZERO;
- //判断当前订单是否为首单
- 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" +"为空===============================================");
- }
- //平台服务费
- 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));
- }
- }
- }
- log.info("计算后的平台服务费:{}", serviceFee);
- chargeOrderInfo.setDiscountMoney(discountFee);
- chargeOrderInfo.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
- //订单结算:平台实际收取金额 = 互联互通金额 + 中数电动金额(平台总服务费)
- chargeOrderInfo.setRealCost(chargeOrderInfo.getRealServiceCost().add(chargeOrderInfo.getThirdPartyTotalCost()));
- //订单状态->已完成
- chargeOrderInfo.setStatus(SystemConstants.STATUS_THREE);
- //计算充电时间
- chargeOrderInfo.setChargeTime(DateUtils.getDuration(chargeOrderInfo.getStartTime(), chargeOrderInfo.getEndTime()));
- //修改订单
- chargeOrderInfoService.updateById(chargeOrderInfo);
- //账户余额扣减(积分增加)
- log.info("执行账户余额扣减(积分增加)");
- chargeOrderInfoService.orderSettlement(chargeOrderInfo.getId());
- // 执行业务处理
- businessHandler.accept(jsonNode);
- // 构建响应
- return buildChargeResponse(getTextValue(jsonNode, "StartChargeSeq"));
- } catch (BusinessException e) {
- throw e;
- } catch (Exception e) {
- log.error("处理请求失败:{}", e.getMessage());
- throw new BusinessException("处理请求失败:" + e.getMessage(), e);
- }
- }
- /**
- * 处理启动充电结果推送请求
- * 数据格式:{"ConnectorID":"xxx","StartChargeSeq":"xxx","StartChargeSeqStat":2,"StartTime":"xxx"}
- */
- private ResponseParmsEntity processStartChargeResultRequest(RequestParmsEntity requestDTO) {
- try {
- JsonNode jsonNode = verifyAndDecrypt(requestDTO);
-
- // 启动充电结果业务处理
- String startChargeSeq = getTextValue(jsonNode, "StartChargeSeq");
- Integer startChargeSeqStat = getIntValue(jsonNode, "StartChargeSeqStat");
- String startTime = getTextValue(jsonNode, "StartTime");
-
- ChargeOrderInfo chargeOrderInfo = chargeOrderInfoService.getOne(new LambdaQueryWrapper<ChargeOrderInfo>()
- .eq(ChargeOrderInfo::getStartChargeSeq, startChargeSeq).last("LIMIT 1"));
-
- if (startChargeSeqStat != null) {
- switch (startChargeSeqStat) {
- case 1 -> log.info("启动中 - StartChargeSeq: {}", startChargeSeq);
- case 2 -> {
- log.info("充电中 - StartChargeSeq: {}", startChargeSeq);
- // 修改订单状态
- if (ObjectUtil.isNotEmpty(chargeOrderInfo)) {
- if (Objects.equals(chargeOrderInfo.getStatus(), SystemConstants.STATUS_ZERO)) {
- chargeOrderInfo.setStatus(SystemConstants.STATUS_ONE);
- chargeOrderInfo.setStartTime(startTime);
- chargeOrderInfoService.updateById(chargeOrderInfo);
- }
- }
- }
- case 3 -> log.info("停止中 - StartChargeSeq: {}", startChargeSeq);
- case 4 -> log.info("已结束 - StartChargeSeq: {}", startChargeSeq);
- case 5 -> log.info("未知 - StartChargeSeq: {}", startChargeSeq);
- default -> log.warn("未知状态 - StartChargeSeq: {}, Stat: {}", startChargeSeq, startChargeSeqStat);
- }
- }
-
- // 构建响应
- return buildChargeResponse(startChargeSeq);
- } catch (BusinessException e) {
- throw e;
- } catch (Exception e) {
- log.error("处理启动充电结果推送失败:{}", e.getMessage(), e);
- throw new BusinessException("处理启动充电结果推送失败:" + e.getMessage(), e);
- }
- }
- /**
- * 处理停止充电结果推送请求
- * 数据格式:{"ConnectorID":"xxx","FailReason":0,"StartChargeSeq":"xxx","StartChargeSeqStat":4,"SuccStat":0}
- */
- private ResponseParmsEntity processStopChargeResultRequest(RequestParmsEntity requestDTO) {
- try {
- JsonNode jsonNode = verifyAndDecrypt(requestDTO);
-
- // 停止充电结果业务处理
- String startChargeSeq = getTextValue(jsonNode, "StartChargeSeq");
- Integer startChargeSeqStat = getIntValue(jsonNode, "StartChargeSeqStat");
- Integer succStat = getIntValue(jsonNode, "SuccStat");
- Integer failReason = getIntValue(jsonNode, "FailReason");
-
- 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)) {
- 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(), SystemConstants.STATUS_ONE) ||
- Objects.equals(chargeOrderInfo.getStatus(), SystemConstants.STATUS_THREE)) {
- chargeOrderInfo.setStatus(SystemConstants.STATUS_TWO);
- chargeOrderInfoService.updateById(chargeOrderInfo);
- log.info("更新订单状态为结算中 - orderId: {}", chargeOrderInfo.getId());
- }
- }
- case 5 -> log.info("未知 - StartChargeSeq: {}", startChargeSeq);
- default -> log.warn("未知状态 - StartChargeSeq: {}, Stat: {}", startChargeSeq, startChargeSeqStat);
- }
- }
-
- // 构建响应
- return buildChargeResponse(startChargeSeq);
- } catch (BusinessException e) {
- throw e;
- } catch (Exception e) {
- log.error("处理停止充电结果推送失败:{}", e.getMessage(), e);
- throw new BusinessException("处理停止充电结果推送失败:" + e.getMessage(), e);
- }
- }
- /**
- * 处理实时充电状态推送请求
- * 数据格式:{"ConnectorID":"xxx","ConnectorStatus":3,"TotalPower":1.95,"ElecMoney":1.89,...}
- */
- private ResponseParmsEntity processChargeStatusRequest(RequestParmsEntity requestDTO) {
- try {
- JsonNode jsonNode = verifyAndDecrypt(requestDTO);
-
- // 保存或更新充电状态
- saveOrUpdateChargeStatus(jsonNode);
-
- // 构建响应
- return buildChargeResponse(getTextValue(jsonNode, "StartChargeSeq"));
- } catch (BusinessException e) {
- throw e;
- } catch (Exception e) {
- log.error("处理充电状态推送失败:{}", e.getMessage(), e);
- throw new BusinessException("处理充电状态推送失败:" + e.getMessage(), e);
- }
- }
- /**
- * 处理设备状态变化推送请求
- */
- private ResponseParmsEntity processStationStatusRequest(RequestParmsEntity requestDTO) {
- try {
- String decryptData = verifyAndDecryptRaw(requestDTO);
- // 解析并更新设备状态
- QueryStationStatusVO stationStatusVO = objectMapper.readValue(decryptData, QueryStationStatusVO.class);
- updateConnectorStatus(stationStatusVO);
- // 构建响应
- return buildStatusResponse();
- } catch (BusinessException e) {
- throw e;
- } catch (Exception e) {
- log.error("处理设备状态推送失败:{}", e.getMessage());
- throw new BusinessException("处理设备状态推送失败:" + e.getMessage(), e);
- }
- }
- /**
- * 验签并解密请求数据
- */
- private JsonNode verifyAndDecrypt(RequestParmsEntity requestDTO) throws Exception {
- String decryptData = verifyAndDecryptRaw(requestDTO);
- return objectMapper.readTree(decryptData);
- }
- /**
- * 验签并解密请求数据(返回原始字符串)
- */
- private String verifyAndDecryptRaw(RequestParmsEntity requestDTO) throws Exception {
- String signData = requestDTO.getOperatorID() + requestDTO.getData() + requestDTO.getTimeStamp() + requestDTO.getSeq();
- if (!verify(signData, ConnectivityConstants.SIG_SECRET, requestDTO.getSig())) {
- log.error("数据验签失败");
- throw new BusinessException("数据验签失败");
- }
- String decryptData = chargingUtil.decryptData(requestDTO.getData());
- log.info("==================== 解密数据开始 ====================");
- log.info("操作员ID: {}", requestDTO.getOperatorID());
- log.info("解密后的数据:{}", decryptData);
- log.info("==================== 解密数据结束 ====================");
- return decryptData;
- }
- // ==================== 响应构建 ====================
- /**
- * 构建充电响应
- */
- private ResponseParmsEntity buildChargeResponse(String startChargeSeq) throws Exception {
- ChargeResponseVO chargeResponseVO = new ChargeResponseVO();
- chargeResponseVO.setStartChargeSeq(startChargeSeq);
- chargeResponseVO.setSuccStat(STATUS_OK);
- chargeResponseVO.setFailReason(FAIL_REASON_NONE);
- String encryptData = chargingUtil.encryptData(objectMapper.writeValueAsString(chargeResponseVO));
- String sign = genSign(STATUS_OK, "请求成功", encryptData, ConnectivityConstants.SIG_SECRET);
- ResponseParmsEntity response = new ResponseParmsEntity();
- response.setRet(STATUS_OK);
- response.setMsg("请求成功");
- response.setData(encryptData);
- response.setSig(sign);
- return response;
- }
- /**
- * 构建设备状态响应
- */
- private ResponseParmsEntity buildStatusResponse() throws Exception {
- Map<String, Integer> statusMap = new HashMap<>();
- statusMap.put("Status", 0);
- String encryptData = chargingUtil.encryptData(objectMapper.writeValueAsString(statusMap));
- String sign = genSign(STATUS_OK, "", encryptData, ConnectivityConstants.SIG_SECRET);
- ResponseParmsEntity response = new ResponseParmsEntity();
- response.setRet(STATUS_OK);
- response.setMsg("");
- response.setData(encryptData);
- response.setSig(sign);
- return response;
- }
- // ==================== 状态更新 ====================
- /**
- * 更新充电接口状态
- */
- private void updateConnectorStatus(QueryStationStatusVO stationStatusVO) {
- if (stationStatusVO == null) {
- return;
- }
-
- // 处理单个连接器状态推送格式:{"ConnectorStatusInfo":{"ConnectorID":"xxx","Status":2}}
- ConnectorStatusInfo singleConnector = stationStatusVO.getConnectorStatusInfo();
- if (singleConnector != null && singleConnector.getConnectorID() != null) {
- connectorInfoMapper.update(null, Wrappers.<ThirdPartyConnectorInfo>lambdaUpdate()
- .eq(ThirdPartyConnectorInfo::getConnectorId, singleConnector.getConnectorID())
- .set(ThirdPartyConnectorInfo::getStatus, singleConnector.getStatus())
- .set(ThirdPartyConnectorInfo::getUpdateTime, LocalDateTime.now()));
- log.info("更新充电接口状态(单个) - connectorId: {}, status: {}",
- singleConnector.getConnectorID(), singleConnector.getStatus());
- return;
- }
-
- // 处理批量连接器状态推送格式
- if (CollectionUtils.isEmpty(stationStatusVO.getStationStatusInfos())) {
- return;
- }
- for (StationStatusInfo stationStatusInfo : stationStatusVO.getStationStatusInfos()) {
- List<ConnectorStatusInfo> connectorStatusInfos = stationStatusInfo.getConnectorStatusInfos();
- if (CollectionUtils.isEmpty(connectorStatusInfos)) {
- continue;
- }
- for (ConnectorStatusInfo connectorStatus : connectorStatusInfos) {
- connectorInfoMapper.update(null, Wrappers.<ThirdPartyConnectorInfo>lambdaUpdate()
- .eq(ThirdPartyConnectorInfo::getConnectorId, connectorStatus.getConnectorID())
- .set(ThirdPartyConnectorInfo::getStatus, connectorStatus.getStatus())
- .set(ThirdPartyConnectorInfo::getUpdateTime, LocalDateTime.now()));
- log.debug("更新充电接口状态 - connectorId: {}, status: {}",
- connectorStatus.getConnectorID(), connectorStatus.getStatus());
- }
- }
- }
- /**
- * 保存或更新充电状态数据
- */
- private void saveOrUpdateChargeStatus(JsonNode jsonNode) {
- try {
- log.info("保存或更新充电状态数据 - StartChargeSeq: {}", jsonNode);
- String startChargeSeq = jsonNode.get("StartChargeSeq").asText();
- String connectorId = getTextValue(jsonNode, "ConnectorID");
- // 获取第三方推送的实时数据
- BigDecimal totalPower = getDecimalValue(jsonNode, "TotalPower"); // 实际充电度数
- BigDecimal totalMoney = getDecimalValue(jsonNode, "TotalMoney"); // 第三方总费用
- BigDecimal elecMoney = getDecimalValue(jsonNode, "ElecMoney"); // 第三方电费
- BigDecimal serviceMoney = getDecimalValue(jsonNode, "SeviceMoney"); // 第三方服务费
-
- // 修改订单状态并实时更新消费字段
- ChargeOrderInfo chargeOrderInfo = chargeOrderInfoService.getOne(new LambdaQueryWrapper<ChargeOrderInfo>()
- .eq(ChargeOrderInfo::getStartChargeSeq, startChargeSeq).last("limit 1"));
- if(ObjUtil.isNotEmpty(chargeOrderInfo)){
- Integer connectorStatus = getIntValue(jsonNode, "ConnectorStatus");
- // 计算平台实际收取金额(根据度数和平台价格策略计算)
- BigDecimal realCost = calculateRealCost(chargeOrderInfo, totalPower);
- if (Objects.equals(connectorStatus, SystemConstants.STATUS_THREE) && Objects.equals(chargeOrderInfo.getStatus(), SystemConstants.STATUS_ZERO)) {
- // 充电中
- log.info("充电中 - StartChargeSeq: {}", startChargeSeq);
- chargeOrderInfo.setStatus(SystemConstants.STATUS_ONE);
- }
- if (Objects.equals(connectorStatus, SystemConstants.STATUS_FOUR) && Objects.equals(chargeOrderInfo.getStatus(),
- SystemConstants.STATUS_ONE)) {
- // 结算中
- log.info("结算中 - StartChargeSeq: {}", startChargeSeq);
- chargeOrderInfo.setStatus(SystemConstants.STATUS_TWO);
- }
-
- chargeOrderInfoService.updateById(chargeOrderInfo);
- log.info("实时更新订单消费 - startChargeSeq: {}, totalPower: {}, realCost: {}",
- startChargeSeq, totalPower, realCost);
- }
- // 查询是否已存在该充电状态记录
- ThirdPartyChargeStatus existing = chargeStatusMapper.selectOne(
- Wrappers.<ThirdPartyChargeStatus>lambdaQuery()
- .eq(ThirdPartyChargeStatus::getStartChargeSeq, startChargeSeq)
- );
- ThirdPartyChargeStatus chargeStatus = (existing != null) ? existing : new ThirdPartyChargeStatus();
- // 设置字段值
- chargeStatus.setStartChargeSeq(startChargeSeq);
- chargeStatus.setConnectorId(connectorId);
- chargeStatus.setConnectorStatus(getIntValue(jsonNode, "ConnectorStatus"));
- chargeStatus.setStartChargeSeqStat(getIntValue(jsonNode, "StartChargeSeqStat"));
- chargeStatus.setStartTime(parseDateTime(getTextValue(jsonNode, "StartTime")));
- chargeStatus.setEndTime(parseDateTime(getTextValue(jsonNode, "EndTime")));
- chargeStatus.setTotalPower(totalPower);
- chargeStatus.setTotalMoney(totalMoney);
- chargeStatus.setElecMoney(elecMoney);
- chargeStatus.setServiceMoney(serviceMoney);
- chargeStatus.setSoc(getIntValue(jsonNode, "Soc"));
- chargeStatus.setVoltageA(getDecimalValue(jsonNode, "VoltageA"));
- chargeStatus.setVoltageB(getDecimalValue(jsonNode, "VoltageB"));
- chargeStatus.setVoltageC(getDecimalValue(jsonNode, "VoltageC"));
- chargeStatus.setCurrentA(getDecimalValue(jsonNode, "CurrentA"));
- chargeStatus.setCurrentB(getDecimalValue(jsonNode, "CurrentB"));
- chargeStatus.setCurrentC(getDecimalValue(jsonNode, "CurrentC"));
- // 兼容处理:如果有ChargeDetails字段,则存储为JSON字符串
- if (jsonNode.has("ChargeDetails") && !jsonNode.get("ChargeDetails").isNull()) {
- chargeStatus.setChargeDetails(jsonNode.get("ChargeDetails").toString());
- }
- if (existing != null) {
- chargeStatus.setUpdateTime(LocalDateTime.now());
- chargeStatusMapper.updateById(chargeStatus);
- log.info("更新充电状态成功 - startChargeSeq: {}", startChargeSeq);
- } else {
- chargeStatus.setCreateTime(LocalDateTime.now());
- chargeStatusMapper.insert(chargeStatus);
- log.info("新增充电状态成功 - startChargeSeq: {}", startChargeSeq);
- }
- // 熔断保护 - 余额不足判断
- isNeedBreak(chargeStatus, chargeOrderInfo);
- } catch (Exception e) {
- log.error("保存充电状态数据失败", e);
- }
- }
-
- /**
- * 计算平台实际收取金额
- * 根据充电度数 * 当前时段的平台价格策略计算(支持跨时段计费)
- */
- private BigDecimal calculateRealCost(ChargeOrderInfo chargeOrderInfo, BigDecimal totalPower) {
- if (totalPower == null || totalPower.compareTo(BigDecimal.ZERO) <= 0) {
- return BigDecimal.ZERO;
- }
-
- try {
- // 获取用户企业信息
- UserFirm userFirm = userFirmMapper.selectOne(Wrappers.<UserFirm>lambdaQuery()
- .eq(UserFirm::getUserId, chargeOrderInfo.getUserId())
- .eq(UserFirm::getIsDeleted, 0));
-
- // 获取设备信息
- ThirdPartyEquipmentInfo equipmentInfo = thirdPartyEquipmentInfoMapper.selectOne(
- Wrappers.<ThirdPartyEquipmentInfo>lambdaQuery()
- .eq(ThirdPartyEquipmentInfo::getEquipmentId, chargeOrderInfo.getEquipmentId())
- .eq(ThirdPartyEquipmentInfo::getIsDeleted, 0));
-
- if (equipmentInfo == null) {
- log.warn("未找到设备信息 - equipmentId: {}", chargeOrderInfo.getEquipmentId());
- return BigDecimal.ZERO;
- }
-
- // 获取站点信息
- ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectOne(
- Wrappers.<ThirdPartyStationInfo>lambdaQuery()
- .eq(ThirdPartyStationInfo::getStationId, equipmentInfo.getStationId())
- .eq(ThirdPartyStationInfo::getIsDeleted, 0));
-
- if (stationInfo == null) {
- log.warn("未找到站点信息 - stationId: {}", equipmentInfo.getStationId());
- return BigDecimal.ZERO;
- }
-
- // 获取当前时间,格式为 HHmmss
- String currentTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HHmmss"));
-
- // 根据当前时间查询当前时段的价格策略(核心:支持跨时段计费)
- ThirdPartyPolicyInfo currentPeriodPolicy = thirdPartyPolicyInfoMapper
- .selectCurrentPeriodPolicyByStation(stationInfo.getId(), currentTime);
-
- if (currentPeriodPolicy == null || currentPeriodPolicy.getPeriodFlag() == null) {
- log.warn("未找到当前时段价格策略 - stationInfoId: {}, currentTime: {}",
- stationInfo.getId(), currentTime);
- return BigDecimal.ZERO;
- }
-
- Integer currentPeriodFlag = currentPeriodPolicy.getPeriodFlag();
- log.info("当前时段 - stationInfoId: {}, currentTime: {}, periodFlag: {}",
- stationInfo.getId(), currentTime, currentPeriodFlag);
-
- // 查询当前时段对应的价格策略
- Integer salesType = (userFirm != null) ? 1 : 0; // 1-企业 0-平台
- Long firmId = (userFirm != null) ? userFirm.getFirmId() : null;
-
- PolicyFee policyFee = policyFeeMapper.selectOne(Wrappers.<PolicyFee>lambdaQuery()
- .eq(PolicyFee::getStationInfoId, stationInfo.getId())
- .eq(PolicyFee::getPeriodFlag, currentPeriodFlag)
- .eq(PolicyFee::getSalesType, salesType)
- .eq(salesType == 1, PolicyFee::getFirmId, firmId)
- .eq(PolicyFee::getIsDeleted, 0)
- .last("LIMIT 1"));
-
- if (policyFee == null) {
- log.warn("未找到当前时段的价格策略 - stationInfoId: {}, periodFlag: {}, salesType: {}",
- stationInfo.getId(), currentPeriodFlag, salesType);
- return BigDecimal.ZERO;
- }
-
- // 获取综合销售费作为单价
- BigDecimal unitPrice = policyFee.getCompSalesFee() != null ? policyFee.getCompSalesFee() : BigDecimal.ZERO;
-
- // 实际收取金额 = 充电度数 * 当前时段单价
- BigDecimal realCost = totalPower.multiply(unitPrice).setScale(2, BigDecimal.ROUND_HALF_UP);
-
- log.info("计算实际收取金额 - totalPower: {}, periodFlag: {}, unitPrice: {}, realCost: {}",
- totalPower, currentPeriodFlag, unitPrice, realCost);
-
- return realCost;
-
- } catch (Exception e) {
- log.error("计算平台实际收取金额失败", e);
- return BigDecimal.ZERO;
- }
- }
- // ==================== JSON解析工具方法 ====================
- private String getTextValue(JsonNode node, String fieldName) {
- JsonNode field = node.get(fieldName);
- return (field != null && !field.isNull()) ? field.asText() : null;
- }
- private Integer getIntValue(JsonNode node, String fieldName) {
- JsonNode field = node.get(fieldName);
- return (field != null && !field.isNull()) ? field.asInt() : null;
- }
- private BigDecimal getDecimalValue(JsonNode node, String fieldName) {
- JsonNode field = node.get(fieldName);
- return (field != null && !field.isNull()) ? new BigDecimal(field.asText()) : null;
- }
- private LocalDateTime parseDateTime(String dateTimeStr) {
- if (dateTimeStr == null || dateTimeStr.isEmpty()) {
- return null;
- }
- try {
- return LocalDateTime.parse(dateTimeStr, DATE_TIME_FORMATTER);
- } catch (Exception e) {
- log.warn("解析时间失败: {}", dateTimeStr);
- return null;
- }
- }
- /**
- * 根据充电订单号StartChargeSeq 获取订单信息判断是否需要熔断,提前跳枪
- * 使用分布式锁防止并发重复检查
- *
- * @param chargeStatus 充电状态
- * @param chargeOrderInfo 订单信息
- */
- private void isNeedBreak(ThirdPartyChargeStatus chargeStatus, ChargeOrderInfo chargeOrderInfo) {
- // 订单为空或不是充电中状态,不需要熔断检查
- if (chargeOrderInfo == null || !Objects.equals(chargeOrderInfo.getStatus(), SystemConstants.STATUS_ONE)) {
- return;
- }
-
- String lockKey = BREAK_CHECK_LOCK_KEY + chargeStatus.getStartChargeSeq();
- RLock lock = redissonClient.getLock(lockKey);
- try {
- // 尝试获取锁,最多等待3秒,持有锁最多10秒
- if (lock.tryLock(LOCK_WAIT_TIME, LOCK_LEASE_TIME, TimeUnit.SECONDS)) {
- try {
- // 获取安全阈值配置
- DictItem dictItem = dictItemMapper.selectOne(
- new LambdaQueryWrapper<DictItem>()
- .eq(DictItem::getDictCode, "up_recharge")
- .eq(DictItem::getStatus, 1)
- .last("LIMIT 1"));
-
- BigDecimal safetyThreshold = BigDecimal.ZERO;
- if (dictItem != null && dictItem.getValue() != null) {
- safetyThreshold = new BigDecimal(dictItem.getValue());
- }
-
- // 获取用户余额
- UserAccount userAccount = userAccountMapper.selectOne(Wrappers.<UserAccount>lambdaQuery()
- .eq(UserAccount::getUserId, chargeOrderInfo.getUserId())
- .eq(UserAccount::getIsDeleted, 0));
-
- if (userAccount == null) {
- log.warn("未找到用户账户信息 - userId: {}", chargeOrderInfo.getUserId());
- return;
- }
-
- BigDecimal balance = userAccount.getBalance() != null ? userAccount.getBalance() : BigDecimal.ZERO;
-
- // 获取当前实时消费金额
- BigDecimal realCost = chargeOrderInfo.getRealCost() != null ? chargeOrderInfo.getRealCost() : BigDecimal.ZERO;
-
- // 剩余余额 = 账户余额 - 实时消费
- BigDecimal remainingBalance = balance.subtract(realCost);
-
- log.info("熔断检查 - startChargeSeq: {}, 用户余额: {}, 实时消费: {}, 安全阈值: {}, 剩余余额: {}",
- chargeStatus.getStartChargeSeq(), balance, realCost, safetyThreshold, remainingBalance);
-
- // 熔断条件:剩余余额 < 安全阈值 且 已产生实际消费(实时消费 > 0)
- // 这样可以避免刚开始充电(消费为0)时因余额小于阈值而被误熔断
- if (remainingBalance.compareTo(safetyThreshold) < 0 && realCost.compareTo(BigDecimal.ZERO) > 0) {
- log.warn("余额不足,触发熔断停止充电 - startChargeSeq: {}, 用户余额: {}, 实时消费: {}",
- chargeStatus.getStartChargeSeq(), balance, realCost);
-
- // 调用第三方停止充电接口
- try {
- chargingBusinessService.stopCharging(
- chargeStatus.getStartChargeSeq(),
- chargeStatus.getConnectorId());
- log.info("已发送停止充电请求 - startChargeSeq: {}, connectorId: {}",
- chargeStatus.getStartChargeSeq(), chargeStatus.getConnectorId());
-
- // 更新订单停止类型为余额不足停止
- chargeOrderInfo.setStopType(3); // 3-余额不足停止
- chargeOrderInfo.setStopReason("余额不足,系统自动停止充电");
- chargeOrderInfoService.updateById(chargeOrderInfo);
-
- } catch (Exception e) {
- log.error("调用第三方停止充电接口失败 - startChargeSeq: {}",
- chargeStatus.getStartChargeSeq(), e);
- }
- }
-
- } finally {
- lock.unlock();
- }
- } else {
- log.warn("获取熔断检查锁超时 - startChargeSeq: {}", chargeStatus.getStartChargeSeq());
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- log.error("获取熔断检查锁被中断 - startChargeSeq: {}", chargeStatus.getStartChargeSeq(), e);
- } catch (Exception e) {
- log.error("熔断检查失败 - startChargeSeq: {}", chargeStatus.getStartChargeSeq(), e);
- }
- }
- }
|