|
@@ -68,6 +68,9 @@ import org.redisson.api.RLock;
|
|
|
import org.redisson.api.RedissonClient;
|
|
import org.redisson.api.RedissonClient;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
|
|
+import com.zsElectric.boot.business.model.entity.FirmAccountLog;
|
|
|
|
|
+import com.zsElectric.boot.common.util.OkHttpUtil;
|
|
|
|
|
+
|
|
|
import static com.zsElectric.boot.business.service.WFTOrderService.USER_FUND_LOCK_KEY;
|
|
import static com.zsElectric.boot.business.service.WFTOrderService.USER_FUND_LOCK_KEY;
|
|
|
import static com.zsElectric.boot.business.service.WFTOrderService.USER_FUND_LOCK_EXPIRE;
|
|
import static com.zsElectric.boot.business.service.WFTOrderService.USER_FUND_LOCK_EXPIRE;
|
|
|
|
|
|
|
@@ -113,6 +116,8 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
private final ObjectMapper objectMapper;
|
|
private final ObjectMapper objectMapper;
|
|
|
private final DictItemService dictItemService;
|
|
private final DictItemService dictItemService;
|
|
|
private final RedissonClient redissonClient;
|
|
private final RedissonClient redissonClient;
|
|
|
|
|
+ private final OkHttpUtil okHttpUtil;
|
|
|
|
|
+ private final FirmAccountLogMapper firmAccountLogMapper;
|
|
|
|
|
|
|
|
//充电订单号前缀
|
|
//充电订单号前缀
|
|
|
private final String ORDER_NO_PREFIX = "CD";
|
|
private final String ORDER_NO_PREFIX = "CD";
|
|
@@ -1124,6 +1129,11 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
orderSettlement(order.getId());
|
|
orderSettlement(order.getId());
|
|
|
log.info("订单{}余额扣减完成", order.getChargeOrderNo());
|
|
log.info("订单{}余额扣减完成", order.getChargeOrderNo());
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 渠道方订单:推送充电订单信息 + 渠道方账户余额扣减
|
|
|
|
|
+ if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)) {
|
|
|
|
|
+ compensateChannelOrder(order, apiLog.getDecryptedRequestData());
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
log.info("订单{}通过API日志处理成功,实际费用: {}", order.getChargeOrderNo(), order.getRealCost());
|
|
log.info("订单{}通过API日志处理成功,实际费用: {}", order.getChargeOrderNo(), order.getRealCost());
|
|
|
return true;
|
|
return true;
|
|
@@ -1296,6 +1306,11 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
orderSettlement(order.getId());
|
|
orderSettlement(order.getId());
|
|
|
log.info("补偿任务: 订单{}余额扣减完成", order.getChargeOrderNo());
|
|
log.info("补偿任务: 订单{}余额扣减完成", order.getChargeOrderNo());
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 渠道方订单:推送充电订单信息 + 渠道方账户余额扣减
|
|
|
|
|
+ if (Objects.equals(order.getOrderType(), SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)) {
|
|
|
|
|
+ compensateChannelOrder(order, null);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
successCount++;
|
|
successCount++;
|
|
|
chargeStatusCount++;
|
|
chargeStatusCount++;
|
|
@@ -1316,4 +1331,158 @@ public class ChargeOrderInfoServiceImpl extends ServiceImpl<ChargeOrderInfoMappe
|
|
|
return result;
|
|
return result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 渠道方订单补偿:推送充电订单信息给渠道方 + 渠道方账户余额扣减
|
|
|
|
|
+ * 推送失败只记日志,不回滚补偿
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param order 补偿完成的订单
|
|
|
|
|
+ * @param apiLogData API日志原始数据(可为null,则从订单字段构建推送数据)
|
|
|
|
|
+ */
|
|
|
|
|
+ private void compensateChannelOrder(ChargeOrderInfo order, String apiLogData) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ FirmInfo firmInfo = firmInfoMapper.selectById(order.getFirmId());
|
|
|
|
|
+ if (firmInfo == null) {
|
|
|
|
|
+ log.warn("补偿任务: 订单{}找不到渠道方信息,firmId: {}", order.getChargeOrderNo(), order.getFirmId());
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 推送充电订单信息给渠道方
|
|
|
|
|
+ pushChargeOrderInfoToChannel(order, firmInfo, apiLogData);
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 渠道方账户余额扣减
|
|
|
|
|
+ deductChannelFirmBalance(order, firmInfo);
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("补偿任务: 渠道方订单{}补偿处理异常: {}", order.getChargeOrderNo(), e.getMessage(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 推送充电订单信息给渠道方(参考 /notification_charge_order_info 接口推送格式)
|
|
|
|
|
+ * 失败只记日志,不影响补偿结果
|
|
|
|
|
+ */
|
|
|
|
|
+ private void pushChargeOrderInfoToChannel(ChargeOrderInfo order, FirmInfo firmInfo, String apiLogData) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 构建推送数据
|
|
|
|
|
+ Map<String, Object> pushData;
|
|
|
|
|
+ if (apiLogData != null) {
|
|
|
|
|
+ // 使用API日志原始数据
|
|
|
|
|
+ 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.put("chargeOrderNo", order.getChargeOrderNo());
|
|
|
|
|
+
|
|
|
|
|
+ String url = firmInfo.getChannelUrl() + "/notification_charge_order_info";
|
|
|
|
|
+ String requestBody = com.alibaba.fastjson2.JSONObject.toJSONString(pushData);
|
|
|
|
|
+
|
|
|
|
|
+ int maxRetries = 3;
|
|
|
|
|
+ int retryIntervalMs = 5000;
|
|
|
|
|
+ for (int attempt = 1; attempt <= maxRetries; attempt++) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ JsonNode response = okHttpUtil.doPostJson(url, requestBody, null);
|
|
|
|
|
+ log.info("补偿任务: 渠道方推送充电订单信息成功 - chargeOrderNo: {}, firmId: {}, response: {}",
|
|
|
|
|
+ order.getChargeOrderNo(), order.getFirmId(), response);
|
|
|
|
|
+ return;
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("补偿任务: 渠道方推送充电订单信息失败(第{}次) - chargeOrderNo: {}, firmId: {}, url: {}, 错误: {}",
|
|
|
|
|
+ attempt, order.getChargeOrderNo(), order.getFirmId(), url, e.getMessage(), e);
|
|
|
|
|
+ if (attempt < maxRetries) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Thread.sleep(retryIntervalMs);
|
|
|
|
|
+ } catch (InterruptedException ie) {
|
|
|
|
|
+ Thread.currentThread().interrupt();
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("补偿任务: 构建渠道方推送数据失败 - chargeOrderNo: {}, 错误: {}", order.getChargeOrderNo(), e.getMessage(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 渠道方账户余额扣减 + 记录资金流水
|
|
|
|
|
+ */
|
|
|
|
|
+ private void deductChannelFirmBalance(ChargeOrderInfo order, FirmInfo firmInfo) {
|
|
|
|
|
+ BigDecimal cost = order.getRealCost();
|
|
|
|
|
+ if (cost == null || cost.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
|
|
+ log.info("补偿任务: 订单{}实际费用为0,跳过渠道方余额扣减", order.getChargeOrderNo());
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 记录资金流水
|
|
|
|
|
+ FirmAccountLog accountLog = new FirmAccountLog();
|
|
|
|
|
+ accountLog.setFirmId(firmInfo.getId());
|
|
|
|
|
+ accountLog.setFirmType(firmInfo.getFirmType());
|
|
|
|
|
+ accountLog.setEventDesc("渠道方充电订单下账(补偿)");
|
|
|
|
|
+ accountLog.setSerialNo(order.getChargeOrderNo());
|
|
|
|
|
+ accountLog.setIncomeType(2);
|
|
|
|
|
+ accountLog.setBeforeChange(firmInfo.getBalance());
|
|
|
|
|
+ accountLog.setAfterChange(firmInfo.getBalance().subtract(cost));
|
|
|
|
|
+ accountLog.setMoneyChange(cost);
|
|
|
|
|
+ firmAccountLogMapper.insert(accountLog);
|
|
|
|
|
+
|
|
|
|
|
+ // 渠道方账户余额修改
|
|
|
|
|
+ firmInfo.setBalance(firmInfo.getBalance().subtract(cost));
|
|
|
|
|
+ firmInfoMapper.updateById(firmInfo);
|
|
|
|
|
+ log.info("补偿任务: 订单{}渠道方余额扣减完成,扣减金额: {}, 扣减后余额: {}",
|
|
|
|
|
+ order.getChargeOrderNo(), cost, firmInfo.getBalance());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public String compensateChannelOrderPush() {
|
|
|
|
|
+ log.info("开始执行渠道方订单推送补偿...");
|
|
|
|
|
+
|
|
|
|
|
+ // 查询已完成(status=3)、备注为"通过补偿修复处理"的渠道方订单
|
|
|
|
|
+ List<ChargeOrderInfo> channelOrders = this.list(Wrappers.<ChargeOrderInfo>lambdaQuery()
|
|
|
|
|
+ .eq(ChargeOrderInfo::getStatus, 3)
|
|
|
|
|
+ .eq(ChargeOrderInfo::getOrderType, SystemConstants.CHARGE_ORDER_TYPE_CHANNEL)
|
|
|
|
|
+ .eq(ChargeOrderInfo::getRemark, "通过补偿修复处理")
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (channelOrders.isEmpty()) {
|
|
|
|
|
+ log.info("渠道方推送补偿: 没有找到需要补偿的渠道方订单");
|
|
|
|
|
+ return "没有找到需要补偿的渠道方订单";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ log.info("渠道方推送补偿: 找到{}个需要补偿的渠道方订单", channelOrders.size());
|
|
|
|
|
+
|
|
|
|
|
+ int totalCount = 0;
|
|
|
|
|
+ int successCount = 0;
|
|
|
|
|
+ List<String> failedOrders = new ArrayList<>();
|
|
|
|
|
+
|
|
|
|
|
+ for (ChargeOrderInfo order : channelOrders) {
|
|
|
|
|
+ totalCount++;
|
|
|
|
|
+ try {
|
|
|
|
|
+ compensateChannelOrder(order, null);
|
|
|
|
|
+ successCount++;
|
|
|
|
|
+ log.info("渠道方推送补偿: 订单{}补偿成功", order.getChargeOrderNo());
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("渠道方推送补偿: 订单{}补偿失败: {}", order.getChargeOrderNo(), e.getMessage(), e);
|
|
|
|
|
+ failedOrders.add(order.getChargeOrderNo());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ String result = String.format("渠道方推送补偿完成!总计: %d, 成功: %d, 失败: %d",
|
|
|
|
|
+ totalCount, successCount, failedOrders.size());
|
|
|
|
|
+ if (!failedOrders.isEmpty()) {
|
|
|
|
|
+ result += ", 失败订单: " + String.join(",", failedOrders);
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info(result);
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
}
|
|
}
|