From 6fc77feef6337bc478423efad5de91fa520b4990 Mon Sep 17 00:00:00 2001
From: longz <longzhaoz@qq.com>
Date: 星期一, 13 七月 2026 21:01:40 +0800
Subject: [PATCH] 支付分账测试相关
---
ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java | 443 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 420 insertions(+), 23 deletions(-)
diff --git a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
index c72ad45..f1b0083 100644
--- a/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
+++ b/ruoyi-service/ruoyi-order/src/main/java/com/ruoyi/order/service/impl/TChargingOrderServiceImpl.java
@@ -5,6 +5,7 @@
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.account.api.feignClient.*;
@@ -61,6 +62,8 @@
import com.ruoyi.order.util.mongodb.service.TransactionRecordService;
import com.ruoyi.order.util.mongodb.service.UploadRealTimeMonitoringDataService;
import com.ruoyi.order.vo.EndOfChargePageInfo;
+import com.ruoyi.order.vo.ChargingSimulationVO;
+import com.ruoyi.order.vo.IcbcAdminSubOrderVO;
import com.ruoyi.order.vo.OrderCountByDate;
import com.ruoyi.order.vo.StatisticsOfBatteryVO;
import com.ruoyi.other.api.domain.*;
@@ -77,6 +80,7 @@
import com.ruoyi.payment.api.vo.*;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.feignClient.SysUserClient;
+import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
@@ -155,6 +159,8 @@
private IcbcPaymentClient icbcPaymentClient;
@Resource
private TChargingOrderShareRecordMapper chargingOrderShareRecordMapper;
+ @Resource
+ private ChargingOrderSettlementExecutor chargingOrderSettlementExecutor;
@Resource
private AppCouponClient appCouponClient;
@@ -817,7 +823,7 @@
chargingOrder.setWhitelistServiceRefundAmount(BigDecimal.ZERO);
chargingOrder.setVipDiscountAmount(BigDecimal.ZERO);
chargingOrder.setOrderSource(1);
- if (thirdPayAmount.compareTo(BigDecimal.ZERO) > 0) {
+ if (thirdPayAmount.compareTo(BigDecimal.ZERO) > 0 && Integer.valueOf(1).equals(addChargingOrder.getPaymentType())) {
chargingOrder.setSourceName("ICBC");
}
chargingOrder.setTitle("【充电桩充电】" + chargingPile.getNumber() + "号桩/" + tChargingGun.getCode() + "号枪");
@@ -880,21 +886,371 @@
}
//会员优惠折扣将其计入增加充电时长(增加总充电金额)
//如果充电总金额未使用完,则需要退回费用=(原金额/总金额)*(总金额-实际充电金额)
- IcbcPaymentReq req = new IcbcPaymentReq();
- req.setOutTradeNo(chargingOrder.getCode());
- req.setAmount(thirdPayAmount);
- req.setSubject("充电充值");
- req.setBody("充电充值");
- req.setPaymentType(addChargingOrder.getPaymentType());
- req.setNotifyUrl("/payment/icbc/callBack");
- req.setReturnUrl(addChargingOrder.getReturnUrl());
- req.setOpenId(Integer.valueOf(1).equals(addChargingOrder.getPaymentType()) ? appUser.getWxOpenid() : appUser.getAliOpenid());
- req.setProfitSharing(buildIcbcProfitSharing(site));
- IcbcPaymentResp data = icbcPaymentClient.payment(req).getData();
- if (isIcbcPaymentCreated(data)) {
- return AjaxResult.success(data);
+ if (Integer.valueOf(1).equals(addChargingOrder.getPaymentType())) {
+ IcbcPaymentReq req = new IcbcPaymentReq();
+ req.setOutTradeNo(chargingOrder.getCode());
+ req.setAmount(thirdPayAmount);
+ req.setSubject("充电充值");
+ req.setBody("充电充值");
+ req.setPaymentType(1);
+ req.setNotifyUrl("/payment/icbc/callBack");
+ req.setReturnUrl(addChargingOrder.getReturnUrl());
+ req.setOpenId(appUser.getWxOpenid());
+ req.setProfitSharing(buildIcbcProfitSharing(site));
+ IcbcPaymentResp data = icbcPaymentClient.payment(req).getData();
+ if (isIcbcPaymentCreated(data)) {
+ if (StringUtils.hasLength(data.getTradeNo())) {
+ chargingOrder.setRechargeSerialNumber(data.getTradeNo());
+ this.updateById(chargingOrder);
+ }
+ return AjaxResult.success(data);
+ }
+ throw new RuntimeException("调起工行支付失败");
}
- throw new RuntimeException("调起工行支付失败");
+ if (Integer.valueOf(2).equals(addChargingOrder.getPaymentType())) {
+ AliPaymentReq req = new AliPaymentReq();
+ req.setOutTradeNo(chargingOrder.getCode());
+ req.setTotalAmount(thirdPayAmount.toString());
+ req.setSubject("充电充值");
+ req.setBuyerOpenId(appUser.getAliOpenid());
+ req.setBody("充电充值");
+ req.setNotifyUrl("/payment/ali/callBack");
+ AliPaymentResp data = aliPaymentClient.payment(req).getData();
+ if (data != null) {
+ return AjaxResult.success(data);
+ }
+ throw new RuntimeException("调起支付宝支付失败");
+ }
+ if (Integer.valueOf(3).equals(addChargingOrder.getPaymentType())) {
+ AliPaymentReq req = new AliPaymentReq();
+ req.setOutTradeNo(chargingOrder.getCode());
+ req.setTotalAmount(thirdPayAmount.toString());
+ req.setSubject("充电充值");
+ req.setBuyerOpenId(appUser.getAliOpenid());
+ req.setBody("充电充值");
+ req.setNotifyUrl("/payment/aliH5/callBack");
+ req.setReturnUrl(addChargingOrder.getReturnUrl());
+ String data = h5AliPaymentClient.payment(req).getData();
+ if (StringUtils.hasLength(data)) {
+ return AjaxResult.success("操作成功", data);
+ }
+ }
+ throw new RuntimeException("无效的支付方式");
+ }
+
+ @Override
+ public ChargingSimulationVO getCurrentSimulationOrder(Integer gunId) {
+ if (gunId == null) {
+ throw new ServiceException("充电枪不能为空");
+ }
+ Long userId = tokenService.getLoginUserApplet().getUserId();
+ return buildSimulationVO(findSimulationOrder(userId, gunId));
+ }
+
+ @Override
+ public ChargingSimulationVO completeSimulation(ChargingSimulationReq request) {
+ if (request == null || request.getGunId() == null) {
+ throw new ServiceException("充电枪不能为空");
+ }
+ Long userId = tokenService.getLoginUserApplet().getUserId();
+ TChargingOrder order = findSimulationOrder(userId, request.getGunId());
+ List<UploadRealTimeMonitoringData> monitoringData = uploadRealTimeMonitoringDataService.getDataByOrderCode(order.getCode());
+ if (monitoringData != null && !monitoringData.isEmpty()) {
+ throw new ServiceException("订单已存在真实充电监控数据,禁止模拟结算");
+ }
+ BigDecimal electricityFee = money(request.getElectricityFee());
+ BigDecimal serviceFee = money(request.getServiceFee());
+ BigDecimal simulationTotal = electricityFee.add(serviceFee).setScale(2, RoundingMode.HALF_UP);
+ BigDecimal availableAmount = money(order.getChargeAmount()).compareTo(BigDecimal.ZERO) > 0
+ ? money(order.getChargeAmount()) : money(order.getRechargeAmount());
+ if (simulationTotal.compareTo(availableAmount) > 0) {
+ throw new ServiceException("模拟消费金额不能超过订单可消费金额" + availableAmount.toPlainString() + "元");
+ }
+
+ List<AccountingStrategyDetailOrder> tariffs = accountingStrategyDetailOrderService.list(
+ new LambdaQueryWrapper<AccountingStrategyDetailOrder>()
+ .eq(AccountingStrategyDetailOrder::getChargingOrderId, order.getId())
+ .orderByAsc(AccountingStrategyDetailOrder::getStartTime));
+ ChargingSimulationSupport.PreparedSimulation prepared;
+ try {
+ prepared = ChargingSimulationSupport.prepare(order.getCode(), tariffs, electricityFee, serviceFee, LocalDateTime.now());
+ } catch (IllegalArgumentException e) {
+ throw new ServiceException(e.getMessage());
+ }
+ accountingStrategyDetailOrderService.updateById(prepared.getTariff());
+
+ TChargingGun gun = chargingGunClient.getChargingGunById(order.getChargingGunId()).getData();
+ TChargingPile pile = chargingPileClient.getChargingPileById(order.getChargingPileId()).getData();
+ TransactionRecordMessageVO record = prepared.getRecord();
+ record.setCharging_gun_code(gun == null ? null : gun.getCode());
+ record.setCharging_pile_code(pile == null ? null : pile.getCode());
+ if (Integer.valueOf(2).equals(order.getStatus())) {
+ TChargingOrder charging = new TChargingOrder();
+ charging.setId(order.getId());
+ charging.setStatus(3);
+ charging.setStartTime(LocalDateTime.now().minusSeconds(1));
+ this.updateById(charging);
+ }
+ R settlement = chargingOrderSettlementExecutor.settle(record);
+ if (R.isError(settlement)) {
+ throw new ServiceException(StringUtils.hasLength(settlement.getMsg()) ? settlement.getMsg() : "模拟结算失败");
+ }
+ return buildSimulationVO(this.getById(order.getId()));
+ }
+
+ private TChargingOrder findSimulationOrder(Long userId, Integer gunId) {
+ TChargingOrder order = this.getOne(new LambdaQueryWrapper<TChargingOrder>()
+ .eq(TChargingOrder::getAppUserId, userId)
+ .eq(TChargingOrder::getChargingGunId, gunId)
+ .eq(TChargingOrder::getSourceName, "ICBC")
+ .eq(TChargingOrder::getRechargePaymentStatus, 2)
+ .in(TChargingOrder::getStatus, Arrays.asList(2, 3, 4))
+ .eq(TChargingOrder::getDelFlag, 0)
+ .isNull(TChargingOrder::getRefundStatus)
+ .orderByDesc(TChargingOrder::getId)
+ .last("limit 1"));
+ if (order == null) {
+ throw new ServiceException("当前枪没有属于你的可模拟ICBC已支付订单");
+ }
+ return order;
+ }
+
+ private ChargingSimulationVO buildSimulationVO(TChargingOrder order) {
+ ChargingSimulationVO result = new ChargingSimulationVO();
+ result.setOrderId(order.getId());
+ result.setOrderCode(order.getCode());
+ result.setOrderStatus(order.getStatus());
+ result.setRechargeAmount(order.getRechargeAmount());
+ result.setChargeAmount(order.getChargeAmount());
+ result.setElectricityFee(order.getElectrovalence());
+ result.setServiceFee(order.getServiceCharge());
+ result.setPaymentAmount(order.getPaymentAmount());
+ result.setRefundAmount(order.getRefundAmount());
+ result.setRefundStatus(order.getRefundStatus());
+ result.setIcbcOrderId(order.getRechargeSerialNumber());
+ TChargingOrderShareRecord shareRecord = chargingOrderShareRecordMapper.selectOne(
+ new LambdaQueryWrapper<TChargingOrderShareRecord>()
+ .eq(TChargingOrderShareRecord::getChargingOrderId, order.getId())
+ .eq(TChargingOrderShareRecord::getPayChannel, "ICBC")
+ .eq(TChargingOrderShareRecord::getDelFlag, false)
+ .orderByDesc(TChargingOrderShareRecord::getId)
+ .last("limit 1"));
+ if (shareRecord != null) {
+ result.setShareAmount(shareRecord.getShareAmount());
+ result.setShareStatus(shareRecord.getOnlineShareStatus());
+ result.setSubOrderId(shareRecord.getSubOrderId());
+ result.setSubOrderSeq(shareRecord.getSubOrderSeq());
+ result.setSubOrderTrxid(shareRecord.getSubOrderTrxid());
+ }
+ return result;
+ }
+
+ @Override
+ public IcbcPaymentResp queryIcbcAdminPayment(String orderCode) {
+ TChargingOrder order = loadIcbcAdminOrder(orderCode);
+ return requireFeignData(icbcPaymentClient.query(order.getCode()), "工行支付查询失败");
+ }
+
+ @Override
+ public IcbcRefundResp refundIcbcAdminPayment(IcbcAdminFundOperationReq request) {
+ if (request == null) {
+ throw new ServiceException("请求参数不能为空");
+ }
+ TChargingOrder order = loadIcbcAdminOrder(request.getOrderCode());
+ BigDecimal amount;
+ try {
+ amount = IcbcAdminFundOperationSupport.requireAmount(request.getAmount());
+ } catch (IllegalArgumentException e) {
+ throw new ServiceException(e.getMessage());
+ }
+ BigDecimal paidAmount = money(order.getThirdPayAmount()).compareTo(BigDecimal.ZERO) > 0
+ ? money(order.getThirdPayAmount()) : money(order.getRechargeAmount());
+ if (amount.compareTo(paidAmount) > 0) {
+ throw new ServiceException("退款金额不能超过订单第三方支付金额" + paidAmount.toPlainString() + "元");
+ }
+ RLock lock = redissonClient.getLock("icbcAdminFund:order:" + order.getCode());
+ if (!lock.tryLock()) {
+ throw new ServiceException("该订单正在执行工行资金操作,请勿重复提交");
+ }
+ try {
+ IcbcPaymentResp payment = requireFeignData(icbcPaymentClient.query(order.getCode()), "工行支付查询失败");
+ String orderId = extractIcbcOrderId(payment);
+ order.setRechargeSerialNumber(orderId);
+ RBucket<String> pendingRefund = redissonClient.getBucket("icbcAdminFund:pending:main:" + order.getCode());
+ String generatedRefundNo = "ICBCADMINREFUND" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
+ String pendingValue = pendingRefund.get();
+ boolean reusingPending = StringUtils.hasLength(pendingValue);
+ String refundNo;
+ try {
+ refundNo = IcbcAdminFundOperationSupport.resolveRefundNo(pendingValue, amount, generatedRefundNo);
+ } catch (IllegalArgumentException e) {
+ throw new ServiceException(e.getMessage());
+ }
+ IcbcRefundReq refundRequest = IcbcAdminFundOperationSupport.buildRefundRequest(order, amount, refundNo);
+ if (!reusingPending) {
+ pendingRefund.set(IcbcAdminFundOperationSupport.buildPendingRefundValue(refundNo, amount));
+ }
+ IcbcRefundResp response = requireFeignData(icbcPaymentClient.refund(refundRequest), "工行退款调用失败");
+ if (IcbcAdminFundOperationSupport.shouldClearPendingRefund(
+ reusingPending, response.getStatus(), isDefinitiveIcbcResponse(response.getRawResponse()))) {
+ pendingRefund.delete();
+ }
+ return response;
+ } finally {
+ if (lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ }
+ }
+ }
+
+ @Override
+ public List<IcbcAdminSubOrderVO> queryIcbcAdminSubOrders(String orderCode) {
+ TChargingOrder order = loadIcbcAdminOrder(orderCode);
+ List<TChargingOrderShareRecord> records = chargingOrderShareRecordMapper.selectList(
+ new LambdaQueryWrapper<TChargingOrderShareRecord>()
+ .eq(TChargingOrderShareRecord::getChargingOrderId, order.getId())
+ .eq(TChargingOrderShareRecord::getPayChannel, "ICBC")
+ .eq(TChargingOrderShareRecord::getDelFlag, false)
+ .orderByAsc(TChargingOrderShareRecord::getId));
+ List<IcbcAdminSubOrderVO> result = new ArrayList<>();
+ for (TChargingOrderShareRecord record : records) {
+ IcbcAdminSubOrderVO item = buildIcbcAdminSubOrderVO(record);
+ try {
+ IcbcSubOrderQueryReq query = IcbcAdminFundOperationSupport.buildSubOrderQueryRequest(order, record);
+ item.applyQuery(requireFeignData(icbcPaymentClient.querySubOrder(query), "工行子订单查询失败"));
+ } catch (Exception e) {
+ item.setQueryStatus("FAIL");
+ item.setErrorMessage(e.getMessage());
+ }
+ result.add(item);
+ }
+ return result;
+ }
+
+ @Override
+ public IcbcSubOrderRefundResp refundIcbcAdminSubOrder(IcbcAdminFundOperationReq request) {
+ if (request == null || request.getShareRecordId() == null) {
+ throw new ServiceException("请选择需要退款的分账子订单");
+ }
+ TChargingOrder order = loadIcbcAdminOrder(request.getOrderCode());
+ TChargingOrderShareRecord shareRecord = chargingOrderShareRecordMapper.selectById(request.getShareRecordId());
+ if (shareRecord == null || !order.getId().equals(shareRecord.getChargingOrderId())) {
+ throw new ServiceException("分账记录不属于当前订单");
+ }
+ BigDecimal amount;
+ try {
+ amount = IcbcAdminFundOperationSupport.requireAmount(request.getAmount());
+ } catch (IllegalArgumentException e) {
+ throw new ServiceException(e.getMessage());
+ }
+ if (shareRecord.getShareAmount() != null && amount.compareTo(shareRecord.getShareAmount()) > 0) {
+ throw new ServiceException("分账退款金额不能超过分账金额" + shareRecord.getShareAmount().toPlainString() + "元");
+ }
+ RLock lock = redissonClient.getLock("icbcAdminFund:order:" + order.getCode());
+ if (!lock.tryLock()) {
+ throw new ServiceException("该分账子订单正在退款,请勿重复提交");
+ }
+ try {
+ String suffix = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
+ RBucket<String> pendingRefund = redissonClient.getBucket("icbcAdminFund:pending:sub:" + shareRecord.getId());
+ String generatedToken = "ICBCSUBREFUND" + suffix + ":ICBCSUBREFUNDNO" + suffix;
+ String pendingValue = pendingRefund.get();
+ boolean reusingPending = StringUtils.hasLength(pendingValue);
+ String operationToken;
+ try {
+ operationToken = IcbcAdminFundOperationSupport.resolveRefundNo(pendingValue, amount, generatedToken);
+ } catch (IllegalArgumentException e) {
+ throw new ServiceException(e.getMessage());
+ }
+ String[] refundNumbers = operationToken.split(":", 2);
+ if (refundNumbers.length != 2) {
+ throw new ServiceException("工行分账退款幂等记录格式错误");
+ }
+ IcbcSubOrderRefundReq refundRequest;
+ try {
+ refundRequest = IcbcAdminFundOperationSupport.buildSubOrderRefundRequest(
+ order, shareRecord, amount, refundNumbers[0], refundNumbers[1]);
+ } catch (IllegalArgumentException e) {
+ throw new ServiceException(e.getMessage());
+ }
+ if (!reusingPending) {
+ pendingRefund.set(IcbcAdminFundOperationSupport.buildPendingRefundValue(operationToken, amount));
+ }
+ IcbcSubOrderRefundResp response = requireFeignData(
+ icbcPaymentClient.refundSubOrder(refundRequest), "工行分账退款调用失败");
+ if (IcbcAdminFundOperationSupport.shouldClearPendingRefund(
+ reusingPending, response.getStatus(), isDefinitiveIcbcResponse(response.getRawResponse()))) {
+ pendingRefund.delete();
+ }
+ return response;
+ } finally {
+ if (lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ }
+ }
+ }
+
+ private TChargingOrder loadIcbcAdminOrder(String orderCode) {
+ if (!StringUtils.hasLength(orderCode)) {
+ throw new ServiceException("订单号不能为空");
+ }
+ TChargingOrder order = this.getOne(new LambdaQueryWrapper<TChargingOrder>()
+ .eq(TChargingOrder::getCode, orderCode)
+ .eq(TChargingOrder::getDelFlag, 0)
+ .last("limit 1"));
+ try {
+ IcbcAdminFundOperationSupport.validateOrder(order);
+ } catch (IllegalArgumentException e) {
+ throw new ServiceException(e.getMessage());
+ }
+ return order;
+ }
+
+ private String extractIcbcOrderId(IcbcPaymentResp payment) {
+ try {
+ JSONObject response = JSON.parseObject(payment.getRawResponse());
+ String orderId = response == null ? null : response.getString("order_id");
+ if (StringUtils.hasLength(orderId)) {
+ return orderId;
+ }
+ } catch (Exception ignored) {
+ }
+ throw new ServiceException("工行支付查询未返回真实order_id,禁止退款");
+ }
+
+ private boolean isDefinitiveIcbcResponse(String rawResponse) {
+ if (!StringUtils.hasLength(rawResponse)) {
+ return false;
+ }
+ try {
+ JSONObject response = JSON.parseObject(rawResponse);
+ return response != null && (response.containsKey("returnCode") || response.containsKey("return_code"));
+ } catch (Exception ignored) {
+ return false;
+ }
+ }
+
+ private IcbcAdminSubOrderVO buildIcbcAdminSubOrderVO(TChargingOrderShareRecord record) {
+ IcbcAdminSubOrderVO item = new IcbcAdminSubOrderVO();
+ item.setShareRecordId(record.getId());
+ item.setOrderCode(record.getChargingOrderCode());
+ item.setShareAmount(record.getShareAmount());
+ item.setOnlineShareStatus(record.getOnlineShareStatus());
+ item.setSubOrderId(record.getSubOrderId());
+ item.setSubMerId(record.getSubMerId());
+ item.setSubMerPrtclNo(record.getSubMerPrtclNo());
+ item.setOriTrxDate(record.getOriTrxDate());
+ item.setBankOrderId(record.getIcbcOrderId());
+ item.setSubOrderSeq(record.getSubOrderSeq());
+ item.setSubOrderTrxid(record.getSubOrderTrxid());
+ return item;
+ }
+
+ private <T> T requireFeignData(R<T> result, String message) {
+ if (result == null || R.isError(result) || result.getData() == null) {
+ throw new ServiceException(result != null && StringUtils.hasLength(result.getMsg()) ? result.getMsg() : message);
+ }
+ return result.getData();
}
@@ -911,7 +1267,26 @@
@Override
public AjaxResult chargingOrderCallback(Integer paymentType, String out_trade_no, String transaction_id, String attach) {
TChargingOrder chargingOrder = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getCode, out_trade_no));
+ if (chargingOrder == null) {
+ return AjaxResult.error("支付回调订单不存在");
+ }
if (chargingOrder.getRechargePaymentStatus() == 2) {
+ if (isIcbcOrder(chargingOrder) && StringUtils.hasLength(transaction_id)
+ && !transaction_id.equals(chargingOrder.getRechargeSerialNumber())) {
+ chargingOrder.setRechargeSerialNumber(transaction_id);
+ this.updateById(chargingOrder);
+ }
+ return AjaxResult.success();
+ }
+ LocalDateTime callbackPayTime = LocalDateTime.now();
+ int claimed = this.baseMapper.update(null, new LambdaUpdateWrapper<TChargingOrder>()
+ .eq(TChargingOrder::getId, chargingOrder.getId())
+ .eq(TChargingOrder::getRechargePaymentStatus, 1)
+ .set(TChargingOrder::getRechargePaymentStatus, 2)
+ .set(TChargingOrder::getRechargeSerialNumber, transaction_id)
+ .set(TChargingOrder::getStatus, 2)
+ .set(TChargingOrder::getPayTime, callbackPayTime));
+ if (claimed == 0) {
return AjaxResult.success();
}
if (isBalancePayMode(chargingOrder.getPayMethod())
@@ -927,7 +1302,7 @@
chargingOrder.setRechargePaymentStatus(2);
chargingOrder.setRechargeSerialNumber(transaction_id);
chargingOrder.setStatus(2);
- chargingOrder.setPayTime(LocalDateTime.now());
+ chargingOrder.setPayTime(callbackPayTime);
//添加安全检测数据到缓存中,每步安全检测完成后需要更新缓存数据
PreChargeCheck preChargeCheck = new PreChargeCheck();
@@ -3183,15 +3558,19 @@
@Transactional
public R endChargeBillingCharge(TransactionRecordMessageVO vo) {
RLock lock = redissonClient.getLock("endOrder:" + vo.getTransaction_serial_number());
+ boolean locked = false;
try {
- boolean tryLock = lock.tryLock(60, 60, TimeUnit.SECONDS);
+ locked = lock.tryLock(60, 60, TimeUnit.SECONDS);
+ if (!locked) {
+ return R.fail("订单正在结算,请勿重复操作");
+ }
//添加redis缓存数据,过期时间,用于防止处理缓慢且硬件重复发送报文导致的重复退款
Boolean hasKey = redisService.hasKey("END_ORDER:" + vo.getTransaction_serial_number());
if(hasKey){
return R.fail("不能重复退款");
}
redisService.setCacheObject("END_ORDER:" + vo.getTransaction_serial_number(), System.currentTimeMillis() + "", 10L, TimeUnit.MINUTES);
- if(tryLock){
+ if(locked){
TChargingOrder chargingOrder = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getCode, vo.getTransaction_serial_number()));
if (null == chargingOrder) {
log.error("订单不存在,订单号:{}", vo.getTransaction_serial_number());
@@ -3683,8 +4062,15 @@
this.updateById(chargingOrder);
triggerChargingOrderShare(chargingOrder);
} else if (isIcbcOrder(chargingOrder)) {
- refundByIcbcAndFinish(chargingOrder, chargingOrderRefund, thirdRefundAmount, "充电完成退款", false,
- refundAmount, balanceRefundAmount);
+ boolean refundSuccess = refundByIcbcAndFinish(chargingOrder, chargingOrderRefund, thirdRefundAmount,
+ "充电完成退款", false, refundAmount, balanceRefundAmount);
+ if (!refundSuccess) {
+ chargingOrderRefund.setRefundStatus(1);
+ chargingOrderRefundService.save(chargingOrderRefund);
+ chargingOrder.setRefundStatus(1);
+ this.updateById(chargingOrder);
+ throw new ServiceException("工行退款失败,结算未完成,请检查支付流水后重试退款");
+ }
} else if (1 == rechargePaymentType) {
WxPaymentRefundModel model = new WxPaymentRefundModel();
model.setOut_trade_no(chargingOrder.getCode());
@@ -3827,9 +4213,12 @@
chargingMessageClient.pushOrderStatus(chargingOrderVo);
}
} catch (Exception e) {
- e.printStackTrace();
+ log.error("充电订单结算失败,订单号:{}", vo == null ? null : vo.getTransaction_serial_number(), e);
+ return R.fail("充电订单结算失败:" + firstNotBlank(e.getMessage(), "未知异常"));
} finally {
- lock.unlock();
+ if (locked && lock.isHeldByCurrentThread()) {
+ lock.unlock();
+ }
}
return R.ok();
}
@@ -6131,7 +6520,15 @@
if (resp == null || !StringUtils.hasLength(resp.getStatus())) {
return false;
}
- return "SUCCESS".equals(resp.getStatus());
+ if (!"SUCCESS".equals(resp.getStatus()) || !StringUtils.hasLength(resp.getPayData())) {
+ return false;
+ }
+ try {
+ JSONObject payData = JSON.parseObject(resp.getPayData());
+ return StringUtils.hasLength(payData.getString("wxDataPackage")) || StringUtils.hasLength(payData.getString("package"));
+ } catch (Exception e) {
+ return false;
+ }
}
private void triggerChargingOrderShare(TChargingOrder chargingOrder, Site site) {
--
Gitblit v1.7.1