|
|
@@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
|
import com.zsElectric.boot.business.converter.ChargeOrderInfoConverter;
|
|
|
import com.zsElectric.boot.business.mapper.*;
|
|
|
+import com.zsElectric.boot.business.mapper.ThirdPartyStationInfoMapper;
|
|
|
import com.zsElectric.boot.business.model.dto.ChargeOrderInfoExportDTO;
|
|
|
import com.zsElectric.boot.business.model.entity.*;
|
|
|
import com.zsElectric.boot.business.model.form.ChargeOrderInfoForm;
|
|
|
@@ -39,11 +40,27 @@ import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
-import java.util.Arrays;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Objects;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+import com.zsElectric.boot.charging.entity.ThirdPartyChargeStatus;
|
|
|
+import com.zsElectric.boot.charging.entity.ThirdPartyConnectorInfo;
|
|
|
+import com.zsElectric.boot.charging.entity.ThirdPartyStationInfo;
|
|
|
+import com.zsElectric.boot.charging.entity.ThirdPartyEquipmentPricePolicy;
|
|
|
+import com.zsElectric.boot.charging.entity.ThirdPartyPolicyInfo;
|
|
|
+import com.zsElectric.boot.charging.mapper.ThirdPartyChargeStatusMapper;
|
|
|
+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.charging.mapper.ThirdPartyApiLogMapper;
|
|
|
+import com.zsElectric.boot.charging.entity.ThirdPartyApiLog;
|
|
|
+import com.zsElectric.boot.common.util.DateUtils;
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
+import com.fasterxml.jackson.databind.JsonNode;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
/**
|
|
|
* 充电订单信息服务实现类
|
|
|
@@ -74,6 +91,16 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
|
|
|
private final UserMapper userMapper;
|
|
|
|
|
|
+ private final ThirdPartyChargeStatusMapper chargeStatusMapper;
|
|
|
+ private final ThirdPartyConnectorInfoMapper connectorInfoMapper;
|
|
|
+ private final ThirdPartyStationInfoMapper thirdPartyStationInfoMapper;
|
|
|
+ private final PolicyFeeMapper policyFeeMapper;
|
|
|
+ private final ThirdPartyEquipmentPricePolicyMapper thirdPartyEquipmentPricePolicyMapper;
|
|
|
+ private final ThirdPartyPolicyInfoMapper thirdPartyPolicyInfoMapper;
|
|
|
+ private final DiscountsActivityMapper discountsActivityMapper;
|
|
|
+ private final ThirdPartyApiLogMapper thirdPartyApiLogMapper;
|
|
|
+ private final ObjectMapper objectMapper;
|
|
|
+
|
|
|
//充电订单号前缀
|
|
|
private final String ORDER_NO_PREFIX = "CD";
|
|
|
//设备流水号前缀
|
|
|
@@ -169,6 +196,7 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
//渠道方启动充电
|
|
|
if (Objects.equals(formData.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)) {
|
|
|
|
|
|
+ log.info("渠道方启动充电开始,用户ID:{},设备认证流水号:{},充电桩编号:{}", SecurityUtils.getUserId(), formData.getEquipAuthSeq(), formData.getEquipmentId());
|
|
|
String orderNo = channelInvokeCharge(formData);
|
|
|
appInvokeChargeVO.setChargeOrderNo(orderNo);
|
|
|
return appInvokeChargeVO;
|
|
|
@@ -336,8 +364,6 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
throw new BusinessException("停止充电失败,请稍后再重试!");
|
|
|
}
|
|
|
|
|
|
- // 更新订单状态为停止中(状态3)
|
|
|
- chargeOrderInfo.setStatus(SystemConstants.STATUS_THREE);
|
|
|
chargeOrderInfo.setStopType(1); // 1-主动停止
|
|
|
this.updateById(chargeOrderInfo);
|
|
|
|
|
|
@@ -411,4 +437,786 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
return head + sdf.format(date) + uid + (int) ((Math.random() * 9 + 1) * 1000);
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 修复未处理的充电订单
|
|
|
+ * 优先通过third_party_api_log表获取推送充电订单信息,
|
|
|
+ * 若没有则通过third_party_charge_status表查询total_power>0的数据
|
|
|
+ * 重新处理这些订单:更新状态、计算费用、扣减余额
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public String repairUnprocessedOrders() {
|
|
|
+ log.info("开始修复未处理的充电订单...");
|
|
|
+
|
|
|
+ // 1. 查询状态为5(未成功充电)的订单
|
|
|
+ List<ChargeOrderInfo> unprocessedOrders = this.list(Wrappers.<ChargeOrderInfo>lambdaQuery()
|
|
|
+ .eq(ChargeOrderInfo::getStatus, 5)
|
|
|
+ .isNotNull(ChargeOrderInfo::getStartChargeSeq));
|
|
|
+
|
|
|
+ if (unprocessedOrders.isEmpty()) {
|
|
|
+ log.info("没有找到需要修复的订单");
|
|
|
+ return "没有找到需要修复的订单";
|
|
|
+ }
|
|
|
+
|
|
|
+ int totalCount = 0;
|
|
|
+ int successCount = 0;
|
|
|
+ int skipCount = 0;
|
|
|
+ int apiLogCount = 0;
|
|
|
+ int chargeStatusCount = 0;
|
|
|
+ List<String> failedOrders = new ArrayList<>();
|
|
|
+
|
|
|
+ for (ChargeOrderInfo order : unprocessedOrders) {
|
|
|
+ totalCount++;
|
|
|
+ try {
|
|
|
+ // 2. 优先从third_party_api_log表查询推送充电订单信息
|
|
|
+ ThirdPartyApiLog apiLog = thirdPartyApiLogMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyApiLog>lambdaQuery()
|
|
|
+ .eq(ThirdPartyApiLog::getInterfaceDescription, "推送充电订单信息")
|
|
|
+ .like(ThirdPartyApiLog::getDecryptedRequestData, order.getStartChargeSeq())
|
|
|
+ .orderByDesc(ThirdPartyApiLog::getCreatedTime)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+
|
|
|
+ if (apiLog != null && apiLog.getDecryptedRequestData() != null) {
|
|
|
+ // 使用API日志中的推送数据处理订单
|
|
|
+ boolean success = processOrderFromApiLog(order, apiLog);
|
|
|
+ if (success) {
|
|
|
+ // 设置补偿状态为已补偿
|
|
|
+ order.setCompensateStatus(1);
|
|
|
+ this.updateById(order);
|
|
|
+ successCount++;
|
|
|
+ apiLogCount++;
|
|
|
+ log.info("订单{}通过API日志修复成功", order.getChargeOrderNo());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 备选方案:从third_party_charge_status表查询
|
|
|
+ ThirdPartyChargeStatus chargeStatus = chargeStatusMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyChargeStatus>lambdaQuery()
|
|
|
+ .eq(ThirdPartyChargeStatus::getStartChargeSeq, order.getStartChargeSeq()));
|
|
|
+
|
|
|
+ if (chargeStatus == null || chargeStatus.getTotalPower() == null
|
|
|
+ || chargeStatus.getTotalPower().compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ log.info("订单{}无有效充电数据,设置为异常无须补偿", order.getChargeOrderNo());
|
|
|
+ // 设置补偿状态为异常无须补偿
|
|
|
+ order.setCompensateStatus(2);
|
|
|
+ this.updateById(order);
|
|
|
+ skipCount++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("开始通过充电状态表修复订单: {}, 充电量: {}", order.getChargeOrderNo(), chargeStatus.getTotalPower());
|
|
|
+
|
|
|
+ // 4. 获取站点信息
|
|
|
+ ThirdPartyConnectorInfo connectorInfo = connectorInfoMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyConnectorInfo::getConnectorId, order.getConnectorId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (connectorInfo == null) {
|
|
|
+ log.warn("订单{}找不到充电接口信息", order.getChargeOrderNo());
|
|
|
+ failedOrders.add(order.getChargeOrderNo());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyStationInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyStationInfo::getStationId, connectorInfo.getStationId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (stationInfo == null) {
|
|
|
+ log.warn("订单{}找不到站点信息", order.getChargeOrderNo());
|
|
|
+ failedOrders.add(order.getChargeOrderNo());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 设置第三方费用信息
|
|
|
+ order.setTotalCharge(chargeStatus.getTotalPower());
|
|
|
+ order.setThirdPartyTotalCost(chargeStatus.getTotalMoney() != null ? chargeStatus.getTotalMoney() : BigDecimal.ZERO);
|
|
|
+ order.setThirdPartyServerfee(chargeStatus.getServiceMoney() != null ? chargeStatus.getServiceMoney() : BigDecimal.ZERO);
|
|
|
+ order.setThirdPartyElecfee(chargeStatus.getElecMoney() != null ? chargeStatus.getElecMoney() : BigDecimal.ZERO);
|
|
|
+
|
|
|
+ // 6. 计算平台服务费
|
|
|
+ BigDecimal serviceFee = calculateServiceFee(order, chargeStatus, stationInfo);
|
|
|
+
|
|
|
+ // 7. 更新订单信息
|
|
|
+ order.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ order.setRealCost(serviceFee.add(order.getThirdPartyTotalCost()));
|
|
|
+ order.setStatus(SystemConstants.STATUS_THREE); // 已完成
|
|
|
+
|
|
|
+ // 设置充电时间
|
|
|
+ if (chargeStatus.getStartTime() != null && chargeStatus.getEndTime() != null) {
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+ order.setStartTime(chargeStatus.getStartTime().format(formatter));
|
|
|
+ order.setEndTime(chargeStatus.getEndTime().format(formatter));
|
|
|
+ order.setChargeTime(DateUtils.getDuration(order.getStartTime(), order.getEndTime()));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置修复备注
|
|
|
+ order.setRemark("通过补偿修复处理");
|
|
|
+ // 设置补偿状态为已补偿
|
|
|
+ order.setCompensateStatus(1);
|
|
|
+
|
|
|
+ this.updateById(order);
|
|
|
+
|
|
|
+ // 8. 执行账户余额扣减(仅平台订单和企业订单)
|
|
|
+ if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)
|
|
|
+ || Objects.equals(order.getOrderType(), SystemConstants.STATUS_ONE)) {
|
|
|
+ orderSettlement(order.getId());
|
|
|
+ log.info("订单{}余额扣减完成", order.getChargeOrderNo());
|
|
|
+ }
|
|
|
+
|
|
|
+ successCount++;
|
|
|
+ chargeStatusCount++;
|
|
|
+ log.info("订单{}通过充电状态表修复成功,实际费用: {}", order.getChargeOrderNo(), order.getRealCost());
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("修复订单{}失败: {}", order.getChargeOrderNo(), e.getMessage(), e);
|
|
|
+ failedOrders.add(order.getChargeOrderNo());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String result = String.format("修复完成!总计: %d, 成功: %d (API日志: %d, 充电状态: %d), 跳过: %d, 失败: %d",
|
|
|
+ totalCount, successCount, apiLogCount, chargeStatusCount, skipCount, failedOrders.size());
|
|
|
+ if (!failedOrders.isEmpty()) {
|
|
|
+ result += ", 失败订单: " + String.join(",", failedOrders);
|
|
|
+ }
|
|
|
+ log.info(result);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通过API日志中的推送数据处理订单
|
|
|
+ * @param order 订单信息
|
|
|
+ * @param apiLog API日志
|
|
|
+ * @return 是否处理成功
|
|
|
+ */
|
|
|
+ private boolean processOrderFromApiLog(ChargeOrderInfo order, ThirdPartyApiLog apiLog) {
|
|
|
+ try {
|
|
|
+ JsonNode jsonNode = objectMapper.readTree(apiLog.getDecryptedRequestData());
|
|
|
+
|
|
|
+ // 解析推送数据
|
|
|
+ String startChargeSeq = getJsonTextValue(jsonNode, "StartChargeSeq");
|
|
|
+ if (startChargeSeq == null || !startChargeSeq.equals(order.getStartChargeSeq())) {
|
|
|
+ log.warn("订单{}的StartChargeSeq不匹配,跳过API日志处理", order.getChargeOrderNo());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ String totalPowerStr = getJsonTextValue(jsonNode, "TotalPower");
|
|
|
+ if (totalPowerStr == null || new BigDecimal(totalPowerStr).compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ log.info("订单{}的API日志充电量为0,跳过处理", order.getChargeOrderNo());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("开始通过API日志修复订单: {}, 充电量: {}", order.getChargeOrderNo(), totalPowerStr);
|
|
|
+
|
|
|
+ // 设置充电信息
|
|
|
+ order.setTotalCharge(new BigDecimal(totalPowerStr));
|
|
|
+ order.setStopReason(getJsonTextValue(jsonNode, "StopReason"));
|
|
|
+ order.setStartTime(getJsonTextValue(jsonNode, "StartTime"));
|
|
|
+ order.setEndTime(getJsonTextValue(jsonNode, "EndTime"));
|
|
|
+ order.setChargeDetails(jsonNode.toString());
|
|
|
+
|
|
|
+ // 第三方费用
|
|
|
+ String totalMoney = getJsonTextValue(jsonNode, "TotalMoney");
|
|
|
+ String totalSeviceMoney = getJsonTextValue(jsonNode, "TotalSeviceMoney");
|
|
|
+ String totalElecMoney = getJsonTextValue(jsonNode, "TotalElecMoney");
|
|
|
+ order.setThirdPartyTotalCost(totalMoney != null ? new BigDecimal(totalMoney) : BigDecimal.ZERO);
|
|
|
+ order.setThirdPartyServerfee(totalSeviceMoney != null ? new BigDecimal(totalSeviceMoney) : BigDecimal.ZERO);
|
|
|
+ order.setThirdPartyElecfee(totalElecMoney != null ? new BigDecimal(totalElecMoney) : BigDecimal.ZERO);
|
|
|
+
|
|
|
+ // 获取连接器和站点信息
|
|
|
+ String connectorId = getJsonTextValue(jsonNode, "ConnectorID");
|
|
|
+ if (connectorId == null) {
|
|
|
+ connectorId = order.getConnectorId();
|
|
|
+ }
|
|
|
+
|
|
|
+ ThirdPartyConnectorInfo connectorInfo = connectorInfoMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyConnectorInfo::getConnectorId, connectorId)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (connectorInfo == null) {
|
|
|
+ log.warn("订单{}找不到充电接口信息", order.getChargeOrderNo());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyStationInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyStationInfo::getStationId, connectorInfo.getStationId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (stationInfo == null) {
|
|
|
+ log.warn("订单{}找不到站点信息", order.getChargeOrderNo());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算平台服务费(从ChargeDetails中解析)
|
|
|
+ BigDecimal serviceFee = calculateServiceFeeFromChargeDetails(order, jsonNode, stationInfo);
|
|
|
+
|
|
|
+ // 更新订单信息
|
|
|
+ order.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ order.setRealCost(serviceFee.add(order.getThirdPartyTotalCost()));
|
|
|
+ order.setStatus(SystemConstants.STATUS_THREE); // 已完成
|
|
|
+
|
|
|
+ // 计算充电时间
|
|
|
+ if (order.getStartTime() != null && order.getEndTime() != null) {
|
|
|
+ order.setChargeTime(DateUtils.getDuration(order.getStartTime(), order.getEndTime()));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置修复备注
|
|
|
+ order.setRemark("通过补偿修复处理");
|
|
|
+
|
|
|
+ this.updateById(order);
|
|
|
+
|
|
|
+ // 执行账户余额扣减(仅平台订单和企业订单)
|
|
|
+ if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)
|
|
|
+ || Objects.equals(order.getOrderType(), SystemConstants.STATUS_ONE)) {
|
|
|
+ orderSettlement(order.getId());
|
|
|
+ log.info("订单{}余额扣减完成", order.getChargeOrderNo());
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("订单{}通过API日志处理成功,实际费用: {}", order.getChargeOrderNo(), order.getRealCost());
|
|
|
+ return true;
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("通过API日志处理订单{}失败: {}", order.getChargeOrderNo(), e.getMessage(), e);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 从ChargeDetails计算平台服务费
|
|
|
+ */
|
|
|
+ private BigDecimal calculateServiceFeeFromChargeDetails(ChargeOrderInfo order, JsonNode jsonNode,
|
|
|
+ ThirdPartyStationInfo stationInfo) {
|
|
|
+ BigDecimal serviceFee = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ JsonNode chargeDetails = jsonNode.get("ChargeDetails");
|
|
|
+ if (chargeDetails != null && chargeDetails.isArray()) {
|
|
|
+ for (JsonNode node : chargeDetails) {
|
|
|
+ String itemFlag = getJsonTextValue(node, "ItemFlag");
|
|
|
+ String detailPowerStr = getJsonTextValue(node, "DetailPower");
|
|
|
+
|
|
|
+ if (itemFlag != null && detailPowerStr != null) {
|
|
|
+ BigDecimal detailPower = new BigDecimal(detailPowerStr);
|
|
|
+ PolicyFee policyFee = policyFeeMapper.selectOne(Wrappers.<PolicyFee>lambdaQuery()
|
|
|
+ .eq(PolicyFee::getStationInfoId, stationInfo.getId())
|
|
|
+ .eq(PolicyFee::getPeriodFlag, Integer.parseInt(itemFlag))
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (policyFee != null && policyFee.getOpFee() != null) {
|
|
|
+ serviceFee = serviceFee.add(policyFee.getOpFee().multiply(detailPower));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // 无明细时,使用最高费用时段计算
|
|
|
+ log.info("订单{}无充电明细,使用简化计算", order.getChargeOrderNo());
|
|
|
+ ThirdPartyEquipmentPricePolicy pricePolicy = thirdPartyEquipmentPricePolicyMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyEquipmentPricePolicy>lambdaQuery()
|
|
|
+ .eq(ThirdPartyEquipmentPricePolicy::getConnectorId, order.getConnectorId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (pricePolicy != null) {
|
|
|
+ List<ThirdPartyPolicyInfo> policyInfos = thirdPartyPolicyInfoMapper.selectList(
|
|
|
+ Wrappers.<ThirdPartyPolicyInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyPolicyInfo::getPricePolicyId, pricePolicy.getId()));
|
|
|
+ PolicyFee maxPolicyFee = null;
|
|
|
+ for (ThirdPartyPolicyInfo policyInfo : policyInfos) {
|
|
|
+ PolicyFee policyFee = policyFeeMapper.selectOne(Wrappers.<PolicyFee>lambdaQuery()
|
|
|
+ .eq(PolicyFee::getStationInfoId, stationInfo.getId())
|
|
|
+ .eq(PolicyFee::getPeriodFlag, policyInfo.getPeriodFlag())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (policyFee != null && policyFee.getOpFee() != null) {
|
|
|
+ if (maxPolicyFee == null || policyFee.getOpFee().compareTo(maxPolicyFee.getOpFee()) > 0) {
|
|
|
+ maxPolicyFee = policyFee;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (maxPolicyFee != null) {
|
|
|
+ serviceFee = maxPolicyFee.getOpFee().multiply(order.getTotalCharge());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return serviceFee;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 安全获取JSON节点的文本值
|
|
|
+ */
|
|
|
+ private String getJsonTextValue(JsonNode node, String fieldName) {
|
|
|
+ if (node == null || !node.has(fieldName) || node.get(fieldName).isNull()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return node.get(fieldName).asText();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算平台服务费
|
|
|
+ */
|
|
|
+ private BigDecimal calculateServiceFee(ChargeOrderInfo order, ThirdPartyChargeStatus chargeStatus,
|
|
|
+ ThirdPartyStationInfo stationInfo) {
|
|
|
+ BigDecimal serviceFee = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ // 查询价格策略
|
|
|
+ ThirdPartyEquipmentPricePolicy pricePolicy = thirdPartyEquipmentPricePolicyMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyEquipmentPricePolicy>lambdaQuery()
|
|
|
+ .eq(ThirdPartyEquipmentPricePolicy::getConnectorId, chargeStatus.getConnectorId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+
|
|
|
+ if (pricePolicy == null) {
|
|
|
+ log.warn("订单{}找不到价格策略", order.getChargeOrderNo());
|
|
|
+ return serviceFee;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询时段信息
|
|
|
+ List<ThirdPartyPolicyInfo> allPolicyInfos = thirdPartyPolicyInfoMapper.selectList(
|
|
|
+ Wrappers.<ThirdPartyPolicyInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyPolicyInfo::getPricePolicyId, pricePolicy.getId())
|
|
|
+ .orderByAsc(ThirdPartyPolicyInfo::getStartTime));
|
|
|
+
|
|
|
+ if (allPolicyInfos.isEmpty()) {
|
|
|
+ log.warn("订单{}找不到时段信息", order.getChargeOrderNo());
|
|
|
+ return serviceFee;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据充电时间段匹配费用
|
|
|
+ if (chargeStatus.getStartTime() != null && chargeStatus.getEndTime() != null) {
|
|
|
+ String chargeStartTimeStr = chargeStatus.getStartTime().format(DateTimeFormatter.ofPattern("HHmmss"));
|
|
|
+ String chargeEndTimeStr = chargeStatus.getEndTime().format(DateTimeFormatter.ofPattern("HHmmss"));
|
|
|
+
|
|
|
+ // 找到充电时间跨越的所有时段,使用最高费用时段计算
|
|
|
+ PolicyFee maxPolicyFee = null;
|
|
|
+ for (ThirdPartyPolicyInfo policyInfo : allPolicyInfos) {
|
|
|
+ if (chargeStartTimeStr.compareTo(policyInfo.getStartTime()) >= 0
|
|
|
+ || chargeEndTimeStr.compareTo(policyInfo.getStartTime()) >= 0) {
|
|
|
+ PolicyFee policyFee = policyFeeMapper.selectOne(
|
|
|
+ Wrappers.<PolicyFee>lambdaQuery()
|
|
|
+ .eq(PolicyFee::getStationInfoId, stationInfo.getId())
|
|
|
+ .eq(PolicyFee::getPeriodFlag, policyInfo.getPeriodFlag())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (policyFee != null && policyFee.getOpFee() != null) {
|
|
|
+ if (maxPolicyFee == null || policyFee.getOpFee().compareTo(maxPolicyFee.getOpFee()) > 0) {
|
|
|
+ maxPolicyFee = policyFee;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (maxPolicyFee != null) {
|
|
|
+ serviceFee = maxPolicyFee.getOpFee().multiply(order.getTotalCharge());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return serviceFee;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据充电订单号修复已完成订单
|
|
|
+ * 修复状态为3(已完成)的订单,重新处理订单状态变更、数据修改及余额扣减
|
|
|
+ * 优先通过third_party_api_log表获取推送数据,备选通过third_party_charge_status表查询
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public String repairOrderByOrderNo(String chargeOrderNo) {
|
|
|
+ log.info("开始根据订单号修复订单: {}", chargeOrderNo);
|
|
|
+
|
|
|
+ // 1. 查询订单
|
|
|
+ ChargeOrderInfo order = this.getOne(Wrappers.<ChargeOrderInfo>lambdaQuery()
|
|
|
+ .eq(ChargeOrderInfo::getChargeOrderNo, chargeOrderNo)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+
|
|
|
+ if (order == null) {
|
|
|
+ return "订单不存在: " + chargeOrderNo;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("开始修复订单: {}, 当前状态: {}", chargeOrderNo, order.getStatus());
|
|
|
+
|
|
|
+ // 2. 检查订单是否需要修复(只有充电度数、平台费用、三方费用同时为0扏null的订单才处理)
|
|
|
+ boolean needRepair = isZeroOrNull(order.getTotalCharge())
|
|
|
+ && isZeroOrNull(order.getRealCost())
|
|
|
+ && isZeroOrNull(order.getRealServiceCost())
|
|
|
+ && isZeroOrNull(order.getThirdPartyTotalCost())
|
|
|
+ && isZeroOrNull(order.getThirdPartyServerfee());
|
|
|
+
|
|
|
+ if (!needRepair) {
|
|
|
+ return "订单" + chargeOrderNo + "已有充电数据,无需修复。充电度数:" + order.getTotalCharge()
|
|
|
+ + ", 平台收取金额:" + order.getRealCost()
|
|
|
+ + ", 平台服务费:" + order.getRealServiceCost()
|
|
|
+ + ", 三方消费总额:" + order.getThirdPartyTotalCost()
|
|
|
+ + ", 三方服务费:" + order.getThirdPartyServerfee();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (order.getStartChargeSeq() == null) {
|
|
|
+ return "订单缺少StartChargeSeq,无法修复";
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 3. 优先从third_party_api_log表查询推送充电订单信息
|
|
|
+ ThirdPartyApiLog apiLog = thirdPartyApiLogMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyApiLog>lambdaQuery()
|
|
|
+ .eq(ThirdPartyApiLog::getInterfaceDescription, "推送充电订单信息")
|
|
|
+ .like(ThirdPartyApiLog::getDecryptedRequestData, order.getStartChargeSeq())
|
|
|
+ .orderByDesc(ThirdPartyApiLog::getCreatedTime)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+
|
|
|
+ if (apiLog != null && apiLog.getDecryptedRequestData() != null) {
|
|
|
+ // 使用API日志中的推送数据处理订单
|
|
|
+ boolean success = repairOrderFromApiLogByOrderNo(order, apiLog);
|
|
|
+ if (success) {
|
|
|
+ // 设置补偿状态为已补偿
|
|
|
+ order.setCompensateStatus(1);
|
|
|
+ this.updateById(order);
|
|
|
+ log.info("订单{}通过API日志修复成功", chargeOrderNo);
|
|
|
+ return "订单" + chargeOrderNo + "通过API日志修复成功,实际费用: " + order.getRealCost();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 4. 备选方案:从third_party_charge_status表查询
|
|
|
+ ThirdPartyChargeStatus chargeStatus = chargeStatusMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyChargeStatus>lambdaQuery()
|
|
|
+ .eq(ThirdPartyChargeStatus::getStartChargeSeq, order.getStartChargeSeq()));
|
|
|
+
|
|
|
+ if (chargeStatus == null || chargeStatus.getTotalPower() == null
|
|
|
+ || chargeStatus.getTotalPower().compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ // 设置补偿状态为异常无须补偿
|
|
|
+ order.setCompensateStatus(2);
|
|
|
+ this.updateById(order);
|
|
|
+ return "订单" + chargeOrderNo + "无有效充电数据,设置为异常无须补偿";
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("开始通过充电状态表修复订单: {}, 充电量: {}", chargeOrderNo, chargeStatus.getTotalPower());
|
|
|
+
|
|
|
+ // 5. 获取站点信息
|
|
|
+ ThirdPartyConnectorInfo connectorInfo = connectorInfoMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyConnectorInfo::getConnectorId, order.getConnectorId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (connectorInfo == null) {
|
|
|
+ return "订单" + chargeOrderNo + "找不到充电接口信息";
|
|
|
+ }
|
|
|
+
|
|
|
+ ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyStationInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyStationInfo::getStationId, connectorInfo.getStationId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (stationInfo == null) {
|
|
|
+ return "订单" + chargeOrderNo + "找不到站点信息";
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6. 设置第三方费用信息
|
|
|
+ order.setTotalCharge(chargeStatus.getTotalPower());
|
|
|
+ order.setThirdPartyTotalCost(chargeStatus.getTotalMoney() != null ? chargeStatus.getTotalMoney() : BigDecimal.ZERO);
|
|
|
+ order.setThirdPartyServerfee(chargeStatus.getServiceMoney() != null ? chargeStatus.getServiceMoney() : BigDecimal.ZERO);
|
|
|
+ order.setThirdPartyElecfee(chargeStatus.getElecMoney() != null ? chargeStatus.getElecMoney() : BigDecimal.ZERO);
|
|
|
+
|
|
|
+ // 7. 计算平台服务费
|
|
|
+ BigDecimal serviceFee = calculateServiceFee(order, chargeStatus, stationInfo);
|
|
|
+
|
|
|
+ // 8. 更新订单信息
|
|
|
+ order.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ order.setRealCost(serviceFee.add(order.getThirdPartyTotalCost()));
|
|
|
+
|
|
|
+ // 设置充电时间
|
|
|
+ if (chargeStatus.getStartTime() != null && chargeStatus.getEndTime() != null) {
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+ order.setStartTime(chargeStatus.getStartTime().format(formatter));
|
|
|
+ order.setEndTime(chargeStatus.getEndTime().format(formatter));
|
|
|
+ order.setChargeTime(DateUtils.getDuration(order.getStartTime(), order.getEndTime()));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置修复备注
|
|
|
+ order.setRemark("通过补偿修复处理");
|
|
|
+ // 设置补偿状态为已补偿
|
|
|
+ order.setCompensateStatus(1);
|
|
|
+
|
|
|
+ this.updateById(order);
|
|
|
+
|
|
|
+ // 9. 执行账户余额扣减(仅平台订单和企业订单)
|
|
|
+ if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)
|
|
|
+ || Objects.equals(order.getOrderType(), SystemConstants.STATUS_ONE)) {
|
|
|
+ orderSettlement(order.getId());
|
|
|
+ log.info("订单{}余额扣减完成", chargeOrderNo);
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("订单{}通过充电状态表修复成功,实际费用: {}", chargeOrderNo, order.getRealCost());
|
|
|
+ return "订单" + chargeOrderNo + "通过充电状态表修复成功,实际费用: " + order.getRealCost();
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("修复订单{}失败: {}", chargeOrderNo, e.getMessage(), e);
|
|
|
+ throw new BusinessException("修复订单失败: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通过API日志修复单个订单(根据订单号)
|
|
|
+ * @param order 订单信息
|
|
|
+ * @param apiLog API日志
|
|
|
+ * @return 是否处理成功
|
|
|
+ */
|
|
|
+ private boolean repairOrderFromApiLogByOrderNo(ChargeOrderInfo order, ThirdPartyApiLog apiLog) {
|
|
|
+ try {
|
|
|
+ JsonNode jsonNode = objectMapper.readTree(apiLog.getDecryptedRequestData());
|
|
|
+
|
|
|
+ // 解析推送数据
|
|
|
+ String startChargeSeq = getJsonTextValue(jsonNode, "StartChargeSeq");
|
|
|
+ if (startChargeSeq == null || !startChargeSeq.equals(order.getStartChargeSeq())) {
|
|
|
+ log.warn("订单{}的StartChargeSeq不匹配,跳过API日志处理", order.getChargeOrderNo());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ String totalPowerStr = getJsonTextValue(jsonNode, "TotalPower");
|
|
|
+ if (totalPowerStr == null || new BigDecimal(totalPowerStr).compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ log.info("订单{}的API日志充电量为0,跳过处理", order.getChargeOrderNo());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("开始通过API日志修复订单: {}, 充电量: {}", order.getChargeOrderNo(), totalPowerStr);
|
|
|
+
|
|
|
+ // 设置充电信息
|
|
|
+ order.setTotalCharge(new BigDecimal(totalPowerStr));
|
|
|
+ order.setStopReason(getJsonTextValue(jsonNode, "StopReason"));
|
|
|
+ order.setStartTime(getJsonTextValue(jsonNode, "StartTime"));
|
|
|
+ order.setEndTime(getJsonTextValue(jsonNode, "EndTime"));
|
|
|
+ order.setChargeDetails(jsonNode.toString());
|
|
|
+
|
|
|
+ // 第三方费用
|
|
|
+ String totalMoney = getJsonTextValue(jsonNode, "TotalMoney");
|
|
|
+ String totalSeviceMoney = getJsonTextValue(jsonNode, "TotalSeviceMoney");
|
|
|
+ String totalElecMoney = getJsonTextValue(jsonNode, "TotalElecMoney");
|
|
|
+ order.setThirdPartyTotalCost(totalMoney != null ? new BigDecimal(totalMoney) : BigDecimal.ZERO);
|
|
|
+ order.setThirdPartyServerfee(totalSeviceMoney != null ? new BigDecimal(totalSeviceMoney) : BigDecimal.ZERO);
|
|
|
+ order.setThirdPartyElecfee(totalElecMoney != null ? new BigDecimal(totalElecMoney) : BigDecimal.ZERO);
|
|
|
+
|
|
|
+ // 获取连接器和站点信息
|
|
|
+ String connectorId = getJsonTextValue(jsonNode, "ConnectorID");
|
|
|
+ if (connectorId == null) {
|
|
|
+ connectorId = order.getConnectorId();
|
|
|
+ }
|
|
|
+
|
|
|
+ ThirdPartyConnectorInfo connectorInfo = connectorInfoMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyConnectorInfo::getConnectorId, connectorId)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (connectorInfo == null) {
|
|
|
+ log.warn("订单{}找不到充电接口信息", order.getChargeOrderNo());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyStationInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyStationInfo::getStationId, connectorInfo.getStationId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (stationInfo == null) {
|
|
|
+ log.warn("订单{}找不到站点信息", order.getChargeOrderNo());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算平台服务费(从ChargeDetails中解析)
|
|
|
+ BigDecimal serviceFee = calculateServiceFeeFromChargeDetails(order, jsonNode, stationInfo);
|
|
|
+
|
|
|
+ // 更新订单信息
|
|
|
+ order.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ order.setRealCost(serviceFee.add(order.getThirdPartyTotalCost()));
|
|
|
+
|
|
|
+ // 计算充电时间
|
|
|
+ if (order.getStartTime() != null && order.getEndTime() != null) {
|
|
|
+ order.setChargeTime(DateUtils.getDuration(order.getStartTime(), order.getEndTime()));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置修复备注
|
|
|
+ order.setRemark("通过补偿修复处理");
|
|
|
+
|
|
|
+ this.updateById(order);
|
|
|
+
|
|
|
+ // 执行账户余额扣减(仅平台订单和企业订单)
|
|
|
+ if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)
|
|
|
+ || Objects.equals(order.getOrderType(), SystemConstants.STATUS_ONE)) {
|
|
|
+ orderSettlement(order.getId());
|
|
|
+ log.info("订单{}余额扣减完成", order.getChargeOrderNo());
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("订单{}通过API日志处理成功,实际费用: {}", order.getChargeOrderNo(), order.getRealCost());
|
|
|
+ return true;
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("通过API日志处理订单{}失败: {}", order.getChargeOrderNo(), e.getMessage(), e);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断BigDecimal是否为null或0
|
|
|
+ * @param value 要判断的值
|
|
|
+ * @return 如果为null或0返回true,否则返回false
|
|
|
+ */
|
|
|
+ private boolean isZeroOrNull(BigDecimal value) {
|
|
|
+ return value == null || value.compareTo(BigDecimal.ZERO) == 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 补偿未处理的充电订单(定时任务调用)
|
|
|
+ * 查找状态为3(已完成)或5(未成功充电)且充电数据为0的订单
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public String compensateUnprocessedOrders() {
|
|
|
+ log.info("开始执行充电订单补偿定时任务...");
|
|
|
+
|
|
|
+ // 1. 查询状态为3(已完成)或5(未成功充电)且充电数据为0的订单
|
|
|
+ List<ChargeOrderInfo> unprocessedOrders = this.list(Wrappers.<ChargeOrderInfo>lambdaQuery()
|
|
|
+ .in(ChargeOrderInfo::getStatus, 3, 5)
|
|
|
+ .isNotNull(ChargeOrderInfo::getStartChargeSeq)
|
|
|
+ // 充电度数为0或null
|
|
|
+ .and(wrapper -> wrapper
|
|
|
+ .isNull(ChargeOrderInfo::getTotalCharge)
|
|
|
+ .or()
|
|
|
+ .eq(ChargeOrderInfo::getTotalCharge, BigDecimal.ZERO))
|
|
|
+ // 平台实际收取金额为0或null
|
|
|
+ .and(wrapper -> wrapper
|
|
|
+ .isNull(ChargeOrderInfo::getRealCost)
|
|
|
+ .or()
|
|
|
+ .eq(ChargeOrderInfo::getRealCost, BigDecimal.ZERO))
|
|
|
+ // 平台总服务费为0或null
|
|
|
+ .and(wrapper -> wrapper
|
|
|
+ .isNull(ChargeOrderInfo::getRealServiceCost)
|
|
|
+ .or()
|
|
|
+ .eq(ChargeOrderInfo::getRealServiceCost, BigDecimal.ZERO))
|
|
|
+ // 三方充电消费总额为0或null
|
|
|
+ .and(wrapper -> wrapper
|
|
|
+ .isNull(ChargeOrderInfo::getThirdPartyTotalCost)
|
|
|
+ .or()
|
|
|
+ .eq(ChargeOrderInfo::getThirdPartyTotalCost, BigDecimal.ZERO))
|
|
|
+ // 三方充电服务费为0或null
|
|
|
+ .and(wrapper -> wrapper
|
|
|
+ .isNull(ChargeOrderInfo::getThirdPartyServerfee)
|
|
|
+ .or()
|
|
|
+ .eq(ChargeOrderInfo::getThirdPartyServerfee, BigDecimal.ZERO)));
|
|
|
+
|
|
|
+ if (unprocessedOrders.isEmpty()) {
|
|
|
+ log.info("充电订单补偿定时任务: 没有找到需要补偿的订单");
|
|
|
+ return "没有找到需要补偿的订单";
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("充电订单补偿定时任务: 找到{}个需要补偿的订单", unprocessedOrders.size());
|
|
|
+
|
|
|
+ int totalCount = 0;
|
|
|
+ int successCount = 0;
|
|
|
+ int skipCount = 0;
|
|
|
+ int apiLogCount = 0;
|
|
|
+ int chargeStatusCount = 0;
|
|
|
+ List<String> failedOrders = new ArrayList<>();
|
|
|
+
|
|
|
+ for (ChargeOrderInfo order : unprocessedOrders) {
|
|
|
+ totalCount++;
|
|
|
+ try {
|
|
|
+ // 2. 优先从third_party_api_log表查询推送充电订单信息
|
|
|
+ ThirdPartyApiLog apiLog = thirdPartyApiLogMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyApiLog>lambdaQuery()
|
|
|
+ .eq(ThirdPartyApiLog::getInterfaceDescription, "推送充电订单信息")
|
|
|
+ .like(ThirdPartyApiLog::getDecryptedRequestData, order.getStartChargeSeq())
|
|
|
+ .orderByDesc(ThirdPartyApiLog::getCreatedTime)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+
|
|
|
+ if (apiLog != null && apiLog.getDecryptedRequestData() != null) {
|
|
|
+ // 使用API日志中的推送数据处理订单
|
|
|
+ boolean success = processOrderFromApiLog(order, apiLog);
|
|
|
+ if (success) {
|
|
|
+ // 设置补偿状态为已补偿
|
|
|
+ order.setCompensateStatus(1);
|
|
|
+ this.updateById(order);
|
|
|
+ successCount++;
|
|
|
+ apiLogCount++;
|
|
|
+ log.info("补偿任务: 订单{}通过API日志补偿成功", order.getChargeOrderNo());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 备选方案:从third_party_charge_status表查询
|
|
|
+ ThirdPartyChargeStatus chargeStatus = chargeStatusMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyChargeStatus>lambdaQuery()
|
|
|
+ .eq(ThirdPartyChargeStatus::getStartChargeSeq, order.getStartChargeSeq()));
|
|
|
+
|
|
|
+ if (chargeStatus == null || chargeStatus.getTotalPower() == null
|
|
|
+ || chargeStatus.getTotalPower().compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ log.info("补偿任务: 订单{}无有效充电数据,设置为异常无须补偿", order.getChargeOrderNo());
|
|
|
+ // 设置补偿状态为异常无须补偿
|
|
|
+ order.setCompensateStatus(2);
|
|
|
+ this.updateById(order);
|
|
|
+ skipCount++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("补偿任务: 开始通过充电状态表补偿订单: {}, 充电量: {}", order.getChargeOrderNo(), chargeStatus.getTotalPower());
|
|
|
+
|
|
|
+ // 4. 获取站点信息
|
|
|
+ ThirdPartyConnectorInfo connectorInfo = connectorInfoMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyConnectorInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyConnectorInfo::getConnectorId, order.getConnectorId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (connectorInfo == null) {
|
|
|
+ log.warn("补偿任务: 订单{}找不到充电接口信息", order.getChargeOrderNo());
|
|
|
+ failedOrders.add(order.getChargeOrderNo());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ ThirdPartyStationInfo stationInfo = thirdPartyStationInfoMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyStationInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyStationInfo::getStationId, connectorInfo.getStationId())
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (stationInfo == null) {
|
|
|
+ log.warn("补偿任务: 订单{}找不到站点信息", order.getChargeOrderNo());
|
|
|
+ failedOrders.add(order.getChargeOrderNo());
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 设置第三方费用信息
|
|
|
+ order.setTotalCharge(chargeStatus.getTotalPower());
|
|
|
+ order.setThirdPartyTotalCost(chargeStatus.getTotalMoney() != null ? chargeStatus.getTotalMoney() : BigDecimal.ZERO);
|
|
|
+ order.setThirdPartyServerfee(chargeStatus.getServiceMoney() != null ? chargeStatus.getServiceMoney() : BigDecimal.ZERO);
|
|
|
+ order.setThirdPartyElecfee(chargeStatus.getElecMoney() != null ? chargeStatus.getElecMoney() : BigDecimal.ZERO);
|
|
|
+
|
|
|
+ // 6. 计算平台服务费
|
|
|
+ BigDecimal serviceFee = calculateServiceFee(order, chargeStatus, stationInfo);
|
|
|
+
|
|
|
+ // 7. 更新订单信息
|
|
|
+ order.setRealServiceCost(serviceFee.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ order.setRealCost(serviceFee.add(order.getThirdPartyTotalCost()));
|
|
|
+ order.setStatus(SystemConstants.STATUS_THREE); // 已完成
|
|
|
+
|
|
|
+ // 设置充电时间
|
|
|
+ if (chargeStatus.getStartTime() != null && chargeStatus.getEndTime() != null) {
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
+ order.setStartTime(chargeStatus.getStartTime().format(formatter));
|
|
|
+ order.setEndTime(chargeStatus.getEndTime().format(formatter));
|
|
|
+ order.setChargeTime(DateUtils.getDuration(order.getStartTime(), order.getEndTime()));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置修复备注
|
|
|
+ order.setRemark("通过补偿修复处理");
|
|
|
+
|
|
|
+ this.updateById(order);
|
|
|
+
|
|
|
+ // 8. 执行账户余额扣减(仅平台订单和企业订单)
|
|
|
+ if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_PLATFORM)
|
|
|
+ || Objects.equals(order.getOrderType(), SystemConstants.STATUS_ONE)) {
|
|
|
+ orderSettlement(order.getId());
|
|
|
+ log.info("补偿任务: 订单{}余额扣减完成", order.getChargeOrderNo());
|
|
|
+ }
|
|
|
+
|
|
|
+ successCount++;
|
|
|
+ chargeStatusCount++;
|
|
|
+ log.info("补偿任务: 订单{}通过充电状态表补偿成功,实际费用: {}", order.getChargeOrderNo(), order.getRealCost());
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("补偿任务: 补偿订单{}失败: {}", order.getChargeOrderNo(), e.getMessage(), e);
|
|
|
+ failedOrders.add(order.getChargeOrderNo());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String result = String.format("充电订单补偿完成!总计: %d, 成功: %d (API日志: %d, 充电状态: %d), 跳过: %d, 失败: %d",
|
|
|
+ totalCount, successCount, apiLogCount, chargeStatusCount, skipCount, failedOrders.size());
|
|
|
+ if (!failedOrders.isEmpty()) {
|
|
|
+ result += ", 失败订单: " + String.join(",", failedOrders);
|
|
|
+ }
|
|
|
+ log.info(result);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
}
|