|
|
@@ -629,6 +629,9 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
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);
|
|
|
+ if (StrUtil.isNotBlank(chargeStatus.getChargeDetails())) {
|
|
|
+ order.setChargeDetails(chargeStatus.getChargeDetails());
|
|
|
+ }
|
|
|
|
|
|
// 6. 计算平台服务费
|
|
|
BigDecimal serviceFee = calculateServiceFee(order, chargeStatus, stationInfo);
|
|
|
@@ -1003,6 +1006,9 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
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);
|
|
|
+ if (StrUtil.isNotBlank(chargeStatus.getChargeDetails())) {
|
|
|
+ order.setChargeDetails(chargeStatus.getChargeDetails());
|
|
|
+ }
|
|
|
|
|
|
// 7. 计算平台服务费
|
|
|
BigDecimal serviceFee = calculateServiceFee(order, chargeStatus, stationInfo);
|
|
|
@@ -1193,7 +1199,9 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
.eq(ChargeOrderInfo::getThirdPartyServerfee, BigDecimal.ZERO))
|
|
|
// 补偿状态为0或null
|
|
|
.and(wrapper -> wrapper
|
|
|
- .eq(ChargeOrderInfo::getCompensateStatus, BigDecimal.ZERO))
|
|
|
+ .isNull(ChargeOrderInfo::getCompensateStatus)
|
|
|
+ .or()
|
|
|
+ .eq(ChargeOrderInfo::getCompensateStatus, 0))
|
|
|
);
|
|
|
|
|
|
if (unprocessedOrders.isEmpty()) {
|
|
|
@@ -1278,6 +1286,9 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
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);
|
|
|
+ if (StrUtil.isNotBlank(chargeStatus.getChargeDetails())) {
|
|
|
+ order.setChargeDetails(chargeStatus.getChargeDetails());
|
|
|
+ }
|
|
|
|
|
|
// 6. 计算平台服务费
|
|
|
BigDecimal serviceFee = calculateServiceFee(order, chargeStatus, stationInfo);
|
|
|
@@ -1370,27 +1381,19 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
pushData = objectMapper.readValue(apiLogData, Map.class);
|
|
|
} else {
|
|
|
// 从order字段构建推送数据
|
|
|
- pushData = new HashMap<>();
|
|
|
- pushData.put("StartChargeSeq", order.getStartChargeSeq());
|
|
|
- pushData.put("ConnectorID", order.getConnectorId());
|
|
|
- pushData.put("StartTime", order.getStartTime());
|
|
|
- pushData.put("EndTime", order.getEndTime());
|
|
|
- pushData.put("TotalPower", order.getTotalCharge());
|
|
|
- pushData.put("TotalElecMoney", order.getThirdPartyElecfee());
|
|
|
- pushData.put("TotalSeviceMoney", order.getThirdPartyServerfee());
|
|
|
- pushData.put("TotalMoney", order.getThirdPartyTotalCost());
|
|
|
- pushData.put("StopReason", order.getStopReason());
|
|
|
+ pushData = buildCompensationPushData(order);
|
|
|
}
|
|
|
+ normalizeCompensationPushData(pushData, order);
|
|
|
pushData.put("chargeOrderNo", order.getChargeOrderNo());
|
|
|
|
|
|
String url = firmInfo.getChannelUrl() + "/notification_charge_order_info";
|
|
|
- String requestBody = com.alibaba.fastjson2.JSONObject.toJSONString(pushData);
|
|
|
+ String pushJson = objectMapper.writeValueAsString(pushData);
|
|
|
|
|
|
int maxRetries = 3;
|
|
|
int retryIntervalMs = 5000;
|
|
|
for (int attempt = 1; attempt <= maxRetries; attempt++) {
|
|
|
try {
|
|
|
- JsonNode response = okHttpUtil.doPostJson(url, requestBody, null);
|
|
|
+ JsonNode response = okHttpUtil.doPostForm(url, pushJson, null);
|
|
|
log.info("补偿任务: 渠道方推送充电订单信息成功 - chargeOrderNo: {}, firmId: {}, response: {}",
|
|
|
order.getChargeOrderNo(), order.getFirmId(), response);
|
|
|
return;
|
|
|
@@ -1415,6 +1418,208 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
/**
|
|
|
* 渠道方账户余额扣减 + 记录资金流水
|
|
|
*/
|
|
|
+ private Map<String, Object> buildCompensationPushData(ChargeOrderInfo order) throws JsonProcessingException {
|
|
|
+ Map<String, Object> pushData = new LinkedHashMap<>();
|
|
|
+
|
|
|
+ if (StrUtil.isNotBlank(order.getChargeDetails())) {
|
|
|
+ JsonNode chargeDetailsNode = objectMapper.readTree(order.getChargeDetails());
|
|
|
+ if (chargeDetailsNode.isObject()) {
|
|
|
+ pushData.putAll(objectMapper.convertValue(chargeDetailsNode, LinkedHashMap.class));
|
|
|
+ } else if (chargeDetailsNode.isArray()) {
|
|
|
+ pushData.put("ChargeDetails", objectMapper.convertValue(chargeDetailsNode, List.class));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ normalizeCompensationPushData(pushData, order);
|
|
|
+
|
|
|
+ return pushData;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void normalizeCompensationPushData(Map<String, Object> pushData, ChargeOrderInfo order) throws JsonProcessingException {
|
|
|
+ List<Map<String, Object>> chargeDetails = resolveChargeDetails(pushData, order);
|
|
|
+
|
|
|
+ putIfBlank(pushData, "ArrearsAmt", BigDecimal.ZERO);
|
|
|
+ pushData.put("ChargeDetails", chargeDetails);
|
|
|
+ pushData.put("SumPeriod", chargeDetails.size());
|
|
|
+ putIfBlank(pushData, "ConnectorID", order.getConnectorId());
|
|
|
+ putIfBlank(pushData, "EndTime", order.getEndTime());
|
|
|
+ putIfBlank(pushData, "OriginElecMoney", defaultDecimal(order.getThirdPartyElecfee()));
|
|
|
+ putIfBlank(pushData, "OriginMoney", defaultDecimal(order.getThirdPartyTotalCost()));
|
|
|
+ putIfBlank(pushData, "OriginServiceMoney", defaultDecimal(order.getThirdPartyServerfee()));
|
|
|
+ putIfBlank(pushData, "PlatOrderId", order.getId());
|
|
|
+ putIfBlank(pushData, "ReceiptsAmt", defaultDecimal(order.getThirdPartyTotalCost()));
|
|
|
+ putIfBlank(pushData, "StartChargeSeq", order.getStartChargeSeq());
|
|
|
+ putIfBlank(pushData, "StartTime", order.getStartTime());
|
|
|
+ putIfBlank(pushData, "StopReason", parseIntegerOrDefault(order.getStopReason(), 0));
|
|
|
+ putIfBlank(pushData, "TotalElecMoney", defaultDecimal(order.getThirdPartyElecfee()));
|
|
|
+ putIfBlank(pushData, "TotalMoney", defaultDecimal(order.getThirdPartyTotalCost()));
|
|
|
+ putIfBlank(pushData, "TotalPower", defaultDecimal(order.getTotalCharge()));
|
|
|
+ putIfBlank(pushData, "TotalSeviceMoney", defaultDecimal(order.getThirdPartyServerfee()));
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<Map<String, Object>> resolveChargeDetails(Map<String, Object> pushData, ChargeOrderInfo order) throws JsonProcessingException {
|
|
|
+ List<Map<String, Object>> chargeDetails = convertChargeDetails(pushData.get("ChargeDetails"));
|
|
|
+ if (!chargeDetails.isEmpty()) {
|
|
|
+ return chargeDetails;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (StrUtil.isNotBlank(order.getChargeDetails())) {
|
|
|
+ JsonNode chargeDetailsNode = objectMapper.readTree(order.getChargeDetails());
|
|
|
+ if (chargeDetailsNode.isArray()) {
|
|
|
+ chargeDetails = convertChargeDetails(chargeDetailsNode);
|
|
|
+ } else if (chargeDetailsNode.isObject() && chargeDetailsNode.has("ChargeDetails")) {
|
|
|
+ chargeDetails = convertChargeDetails(chargeDetailsNode.get("ChargeDetails"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!chargeDetails.isEmpty()) {
|
|
|
+ return chargeDetails;
|
|
|
+ }
|
|
|
+
|
|
|
+ return buildFallbackChargeDetails(order);
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<Map<String, Object>> convertChargeDetails(Object rawChargeDetails) {
|
|
|
+ if (rawChargeDetails == null) {
|
|
|
+ return new ArrayList<>();
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Map<String, Object>> chargeDetails = new ArrayList<>();
|
|
|
+ if (rawChargeDetails instanceof JsonNode jsonNode && jsonNode.isArray()) {
|
|
|
+ for (JsonNode detailNode : jsonNode) {
|
|
|
+ chargeDetails.add(objectMapper.convertValue(detailNode, LinkedHashMap.class));
|
|
|
+ }
|
|
|
+ return chargeDetails;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (rawChargeDetails instanceof List<?> detailList) {
|
|
|
+ for (Object detail : detailList) {
|
|
|
+ chargeDetails.add(objectMapper.convertValue(detail, LinkedHashMap.class));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return chargeDetails;
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<Map<String, Object>> buildFallbackChargeDetails(ChargeOrderInfo order) {
|
|
|
+ List<Map<String, Object>> chargeDetails = new ArrayList<>();
|
|
|
+ if (order == null) {
|
|
|
+ return chargeDetails;
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> detail = new LinkedHashMap<>();
|
|
|
+ BigDecimal totalPower = defaultDecimal(order.getTotalCharge());
|
|
|
+ BigDecimal totalElecMoney = defaultDecimal(order.getThirdPartyElecfee());
|
|
|
+ BigDecimal totalServiceMoney = defaultDecimal(order.getThirdPartyServerfee());
|
|
|
+
|
|
|
+ detail.put("DetailStartTime", order.getStartTime());
|
|
|
+ detail.put("DetailEndTime", order.getEndTime());
|
|
|
+ detail.put("ItemFlag", resolvePeriodFlag(order));
|
|
|
+ detail.put("ElecPrice", calculateUnitPrice(totalElecMoney, totalPower));
|
|
|
+ detail.put("SevicePrice", calculateUnitPrice(totalServiceMoney, totalPower));
|
|
|
+ detail.put("DetailPower", totalPower);
|
|
|
+ detail.put("DetailElecMoney", totalElecMoney);
|
|
|
+ detail.put("DetailSeviceMoney", totalServiceMoney);
|
|
|
+
|
|
|
+ chargeDetails.add(detail);
|
|
|
+ return chargeDetails;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Integer resolvePeriodFlag(ChargeOrderInfo order) {
|
|
|
+ if (order == null || StrUtil.isBlank(order.getConnectorId())) {
|
|
|
+ return 3;
|
|
|
+ }
|
|
|
+
|
|
|
+ ThirdPartyEquipmentPricePolicy pricePolicy = thirdPartyEquipmentPricePolicyMapper.selectOne(
|
|
|
+ Wrappers.<ThirdPartyEquipmentPricePolicy>lambdaQuery()
|
|
|
+ .eq(ThirdPartyEquipmentPricePolicy::getConnectorId, order.getConnectorId())
|
|
|
+ .eq(ThirdPartyEquipmentPricePolicy::getIsDeleted, 0)
|
|
|
+ .last("LIMIT 1"));
|
|
|
+ if (pricePolicy == null) {
|
|
|
+ return 3;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<ThirdPartyPolicyInfo> policyInfos = thirdPartyPolicyInfoMapper.selectList(
|
|
|
+ Wrappers.<ThirdPartyPolicyInfo>lambdaQuery()
|
|
|
+ .eq(ThirdPartyPolicyInfo::getPricePolicyId, pricePolicy.getId())
|
|
|
+ .eq(ThirdPartyPolicyInfo::getIsDeleted, 0)
|
|
|
+ .orderByAsc(ThirdPartyPolicyInfo::getStartTime));
|
|
|
+ if (policyInfos == null || policyInfos.isEmpty()) {
|
|
|
+ return 3;
|
|
|
+ }
|
|
|
+
|
|
|
+ String chargeStartTime = extractTimePart(order.getStartTime());
|
|
|
+ if (StrUtil.isBlank(chargeStartTime)) {
|
|
|
+ return policyInfos.get(0).getPeriodFlag() != null ? policyInfos.get(0).getPeriodFlag() : 3;
|
|
|
+ }
|
|
|
+
|
|
|
+ ThirdPartyPolicyInfo matchedPolicy = null;
|
|
|
+ for (ThirdPartyPolicyInfo policyInfo : policyInfos) {
|
|
|
+ if (policyInfo.getStartTime() == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (chargeStartTime.compareTo(policyInfo.getStartTime()) >= 0) {
|
|
|
+ matchedPolicy = policyInfo;
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (matchedPolicy == null) {
|
|
|
+ matchedPolicy = policyInfos.get(policyInfos.size() - 1);
|
|
|
+ }
|
|
|
+ return matchedPolicy.getPeriodFlag() != null ? matchedPolicy.getPeriodFlag() : 3;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String extractTimePart(String dateTime) {
|
|
|
+ if (StrUtil.isBlank(dateTime)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
|
|
+ .format(DateTimeFormatter.ofPattern("HHmmss"));
|
|
|
+ } catch (Exception ex) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private BigDecimal calculateUnitPrice(BigDecimal amount, BigDecimal power) {
|
|
|
+ if (power == null || power.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+ return amount.divide(power, 4, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ private BigDecimal defaultDecimal(BigDecimal value) {
|
|
|
+ return value != null ? value : BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void putIfBlank(Map<String, Object> data, String key, Object value) {
|
|
|
+ if (!data.containsKey(key) || isNullLikeValue(data.get(key))) {
|
|
|
+ data.put(key, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private boolean isNullLikeValue(Object value) {
|
|
|
+ if (value == null) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (value instanceof String str) {
|
|
|
+ return StrUtil.isBlank(str) || "null".equalsIgnoreCase(str.trim());
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Integer parseIntegerOrDefault(String value, Integer defaultValue) {
|
|
|
+ if (StrUtil.isBlank(value) || "null".equalsIgnoreCase(value.trim())) {
|
|
|
+ return defaultValue;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return Integer.parseInt(value.trim());
|
|
|
+ } catch (NumberFormatException ex) {
|
|
|
+ return defaultValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private void deductChannelFirmBalance(ChargeOrderInfo order, FirmInfo firmInfo) {
|
|
|
BigDecimal cost = order.getRealCost();
|
|
|
if (cost == null || cost.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
@@ -1467,7 +1672,20 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
for (ChargeOrderInfo order : channelOrders) {
|
|
|
totalCount++;
|
|
|
try {
|
|
|
- compensateChannelOrder(order, null);
|
|
|
+ // 优先从third_party_api_log获取原始推送数据
|
|
|
+ String apiLogData = null;
|
|
|
+ if (order.getStartChargeSeq() != null) {
|
|
|
+ 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) {
|
|
|
+ apiLogData = apiLog.getDecryptedRequestData();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ compensateChannelOrder(order, apiLogData);
|
|
|
successCount++;
|
|
|
log.info("渠道方推送补偿: 订单{}补偿成功", order.getChargeOrderNo());
|
|
|
} catch (Exception e) {
|