| | |
| | | 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.*; |
| | |
| | | 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.*; |
| | |
| | | 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; |
| | |
| | | private IcbcPaymentClient icbcPaymentClient; |
| | | @Resource |
| | | private TChargingOrderShareRecordMapper chargingOrderShareRecordMapper; |
| | | @Resource |
| | | private ChargingOrderSettlementExecutor chargingOrderSettlementExecutor; |
| | | |
| | | @Resource |
| | | private AppCouponClient appCouponClient; |
| | |
| | | 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() + "号枪"); |
| | |
| | | } |
| | | //会员优惠折扣将其计入增加充电时长(增加总充电金额) |
| | | //如果充电总金额未使用完,则需要退回费用=(原金额/总金额)*(总金额-实际充电金额) |
| | | 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(); |
| | | } |
| | | |
| | | |
| | |
| | | @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()) |
| | |
| | | chargingOrder.setRechargePaymentStatus(2); |
| | | chargingOrder.setRechargeSerialNumber(transaction_id); |
| | | chargingOrder.setStatus(2); |
| | | chargingOrder.setPayTime(LocalDateTime.now()); |
| | | chargingOrder.setPayTime(callbackPayTime); |
| | | |
| | | //添加安全检测数据到缓存中,每步安全检测完成后需要更新缓存数据 |
| | | PreChargeCheck preChargeCheck = new PreChargeCheck(); |
| | |
| | | @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()); |
| | |
| | | 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()); |
| | |
| | | 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(); |
| | | } |
| | |
| | | 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) { |