| | |
| | | chargingOrder.setVipDiscountAmount(discountAmount); |
| | | this.updateById(chargingOrder); |
| | | |
| | | // 支付成功立即下发启动充电指令(恢复 master 时序:桩收到指令后再做安全检测并回启动应答)。 |
| | | // 预约订单不在此处下发,由 startDueReservationOrders 到期后统一下发。 |
| | | if (chargingOrder.getReservationTime() == null) { |
| | | startCharging(chargingOrder, preChargeCheck); |
| | | } |
| | | |
| | | return AjaxResult.success(); |
| | | } |
| | |
| | | + ReservationTimeRangeSupport.describe(ranges) + ")"); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private boolean isSafetyCheckPassed(PreChargeCheck check) { |
| | | return check != null |
| | | && Boolean.TRUE.equals(check.getElectronicLockLock()) |
| | | && Boolean.TRUE.equals(check.getInsulationTesting()) |
| | | && Boolean.TRUE.equals(check.getSecureConnectionDetection()); |
| | | } |
| | | |
| | | /** |
| | |
| | | for (TChargingOrder order : dueOrders) { |
| | | try { |
| | | PreChargeCheck check = redisService.getCacheObject("AQJC_" + order.getChargingGunId()); |
| | | if (isSafetyCheckPassed(check)) { |
| | | startChargingAfterSafety(order, check); |
| | | if (null == check) { |
| | | check = newPreChargeCheck(order); |
| | | } |
| | | // 预约到期后直接下发启动指令,无需等待安全检测通过 |
| | | startCharging(order, check); |
| | | } catch (Exception e) { |
| | | log.error("预约充电到时启动失败,orderCode={}", order.getCode(), e); |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | private void startChargingAfterSafety(TChargingOrder chargingOrder, PreChargeCheck check) { |
| | | private void startCharging(TChargingOrder chargingOrder, PreChargeCheck check) { |
| | | RLock lock = redissonClient.getLock("START_AFTER_SAFETY:" + chargingOrder.getId()); |
| | | try { |
| | | if (!lock.tryLock(1, 10, TimeUnit.SECONDS)) { |
| | | return; |
| | | } |
| | | TChargingOrder latest = this.getById(chargingOrder.getId()); |
| | | if (latest == null || latest.getStatus() != 2 || Boolean.TRUE.equals(check.getStartCommandSent())) { |
| | | // 直接使用传入对象:支付完成/预约到期路径下传入对象已是当前最新状态, |
| | | // 避免读写分离下 this.getById 立即回查读不到刚提交的 status=2 导致指令不下发 |
| | | if (chargingOrder == null || chargingOrder.getStatus() != 2 || Boolean.TRUE.equals(check.getStartCommandSent())) { |
| | | return; |
| | | } |
| | | if (!ReservationOrderSupport.isStartDue(latest.getReservationTime(), LocalDateTime.now())) { |
| | | if (!ReservationOrderSupport.isStartDue(chargingOrder.getReservationTime(), LocalDateTime.now())) { |
| | | return; |
| | | } |
| | | TChargingGun gun = chargingGunClient.getChargingGunById(latest.getChargingGunId()).getData(); |
| | | TChargingGun gun = chargingGunClient.getChargingGunById(chargingOrder.getChargingGunId()).getData(); |
| | | TChargingPile pile = chargingPileClient.getChargingPileById(gun.getChargingPileId()).getData(); |
| | | String actualVin = normalizeVin(check.getActualVin()); |
| | | PlatformStartCharging command = new PlatformStartCharging(); |
| | | command.setTransaction_serial_number(latest.getCode()); |
| | | command.setTransaction_serial_number(chargingOrder.getCode()); |
| | | command.setCharging_pile_code(pile.getCode()); |
| | | command.setCharging_gun_code(gun.getCode()); |
| | | command.setCard_number(latest.getId().toString()); |
| | | command.setAccount_balance(latest.getChargeAmount()); |
| | | latest.setActualVin(actualVin); |
| | | this.updateById(latest); |
| | | log.info(latest.getCode() + ":安全检测通过,下发启动充电命令:" + command); |
| | | command.setCard_number(chargingOrder.getId().toString()); |
| | | command.setAccount_balance(chargingOrder.getChargeAmount()); |
| | | chargingOrder.setActualVin(actualVin); |
| | | this.updateById(chargingOrder); |
| | | log.info(chargingOrder.getCode() + ":下发启动充电命令:" + command); |
| | | try { |
| | | sendMessageClient.platformStartCharging(command); |
| | | } catch (Exception e) { |
| | | // 下发失败不置 startCommandSent:保留后续安全检测上报重试机会,超时订单由兜底任务取消 |
| | | log.error(latest.getCode() + ":启动充电命令下发失败,等待下次安全检测上报重试", e); |
| | | // 下发失败不置 startCommandSent:由启动超时兜底任务取消订单并退款 |
| | | log.error(chargingOrder.getCode() + ":启动充电命令下发失败,交由启动超时兜底任务处理", e); |
| | | return; |
| | | } |
| | | check.setStartCommandSent(true); |
| | | redisService.setCacheObject("AQJC_" + latest.getChargingGunId(), check, 24L, TimeUnit.HOURS); |
| | | redisService.setCacheObject("AQJC_" + chargingOrder.getChargingGunId(), check, 24L, TimeUnit.HOURS); |
| | | ScheduledExecutorService resultScheduler = Executors.newScheduledThreadPool(1); |
| | | resultScheduler.scheduleAtFixedRate(() -> { |
| | | if (timingDetection(latest.getId())) { |
| | | if (timingDetection(chargingOrder.getId())) { |
| | | resultScheduler.shutdown(); |
| | | } |
| | | }, 10, 1, TimeUnit.SECONDS); |
| | |
| | | // 刷新等待基准时间,避免前端等待窗口/超时判断误伤正在推进的安全检测 |
| | | preChargeCheck1.setAddTime(LocalDateTime.now()); |
| | | redisService.setCacheObject(key, preChargeCheck1, 24L, TimeUnit.HOURS); |
| | | if (isSafetyCheckPassed(preChargeCheck1)) { |
| | | TChargingOrder pendingOrder = getPendingStartOrder(chargingGun.getId()); |
| | | if (pendingOrder != null) { |
| | | startChargingAfterSafety(pendingOrder, preChargeCheck1); |
| | | } |
| | | } |
| | | // 启动指令已在支付完成/预约到期时下发,此处仅记录检测结果,不再触发启动 |
| | | } |
| | | |
| | | /** |