| | |
| | | for (TChargingOrder tChargingOrder : list) { |
| | | MyChargingOrderList myChargingOrderList = new MyChargingOrderList(); |
| | | myChargingOrderList.setId(tChargingOrder.getId().toString()); |
| | | myChargingOrderList.setSiteId(tChargingOrder.getSiteId()); |
| | | myChargingOrderList.setStatus(tChargingOrder.getStatus()); |
| | | Site site = siteClient.getSiteByIds(Arrays.asList(tChargingOrder.getSiteId())).getData().get(0); |
| | | myChargingOrderList.setTitle(site.getName()); |
| | |
| | | for (TChargingOrder tChargingOrder : orderList) { |
| | | MyChargingOrderList myChargingOrderList = new MyChargingOrderList(); |
| | | myChargingOrderList.setId(tChargingOrder.getId().toString()); |
| | | myChargingOrderList.setSiteId(tChargingOrder.getSiteId()); |
| | | myChargingOrderList.setStatus(tChargingOrder.getStatus()); |
| | | Site site = siteClient.getSiteByIds(Arrays.asList(tChargingOrder.getSiteId())).getData().get(0); |
| | | myChargingOrderList.setTitle(site.getName()); |
| | |
| | | BigDecimal rechargeAmount = money(addChargingOrder.getPaymentAmount()); |
| | | TChargingGun tChargingGun = chargingGunClient.getChargingGunById(addChargingOrder.getId()).getData(); |
| | | TChargingPile chargingPile = chargingPileClient.getChargingPileById(tChargingGun.getChargingPileId()).getData(); |
| | | TAppUserCar selectedCar = null; |
| | | if (addChargingOrder.getAppUserCarId() != null) { |
| | | selectedCar = appUserCarClient.getCarById(addChargingOrder.getAppUserCarId().toString()).getData(); |
| | | } |
| | | String selectedVin = selectedCar == null ? null : normalizeVin(selectedCar.getVin()); |
| | | if (Integer.valueOf(1).equals(chargingPile.getVinFlag()) |
| | | && (!StringUtils.hasLength(selectedVin) || !selectedVin.matches("[A-HJ-NPR-Z0-9]{17}"))) { |
| | | return AjaxResult.error("该充电桩需要17位有效车辆VIN,请先完善所选车辆VIN"); |
| | | } |
| | | AppUserWhitelistMatchVO whitelist = appUserWhitelistClient.matchWhitelist(userId, tChargingGun.getSiteId()).getData(); |
| | | boolean whitelistMatched = whitelist != null && Boolean.TRUE.equals(whitelist.getMatched()); |
| | | if (whitelistMatched) { |
| | |
| | | chargingOrder.setOrderClassification(1); |
| | | chargingOrder.setAppUserId(userId); |
| | | chargingOrder.setAppUserCarId(addChargingOrder.getAppUserCarId()); |
| | | if (null != addChargingOrder.getAppUserCarId()) { |
| | | TAppUserCar userCar = appUserCarClient.getCarById(addChargingOrder.getAppUserCarId().toString()).getData(); |
| | | if (null != userCar) { |
| | | chargingOrder.setPlateNum(userCar.getLicensePlate()); |
| | | } |
| | | if (selectedCar != null) { |
| | | chargingOrder.setPlateNum(selectedCar.getLicensePlate()); |
| | | chargingOrder.setExpectedVin(selectedVin); |
| | | } |
| | | chargingOrder.setReservationTime(addChargingOrder.getReservationTime()); |
| | | chargingOrder.setSiteId(tChargingGun.getSiteId()); |
| | | chargingOrder.setChargingPileId(tChargingGun.getChargingPileId()); |
| | | chargingOrder.setChargingGunId(addChargingOrder.getId()); |
| | |
| | | chargingOrder.setTitle("【充电桩充电】" + chargingPile.getNumber() + "号桩/" + tChargingGun.getCode() + "号枪"); |
| | | |
| | | Site site = siteClient.getSiteByIds(Arrays.asList(tChargingGun.getSiteId())).getData().get(0); |
| | | AjaxResult reservationValidation = validateReservation(site, addChargingOrder.getReservationTime()); |
| | | if (reservationValidation != null) { |
| | | return reservationValidation; |
| | | } |
| | | Integer accountingStrategyId = tChargingGun.getAccountingStrategyId(); |
| | | if (null == accountingStrategyId) { |
| | | //查询站点上面的计费策略 |
| | |
| | | preChargeCheck.setInsulationTesting(false); |
| | | preChargeCheck.setSecureConnectionDetection(false); |
| | | preChargeCheck.setStartupSuccess(1); |
| | | preChargeCheck.setAddTime(LocalDateTime.now()); |
| | | preChargeCheck.setStartCommandSent(false); |
| | | preChargeCheck.setAddTime(chargingOrder.getReservationTime() != null ? chargingOrder.getReservationTime() : LocalDateTime.now()); |
| | | String key = "AQJC_" + chargingOrder.getChargingGunId(); |
| | | redisService.setCacheObject(key, preChargeCheck, 24L, TimeUnit.HOURS); |
| | | |
| | |
| | | this.updateById(chargingOrder); |
| | | |
| | | |
| | | TChargingPile chargingPile = chargingPileClient.getChargingPileById(tChargingGun.getChargingPileId()).getData(); |
| | | //调用远程启动充电消息 |
| | | PlatformStartCharging platformStartCharging = new PlatformStartCharging(); |
| | | platformStartCharging.setTransaction_serial_number(chargingOrder.getCode()); |
| | | platformStartCharging.setCharging_pile_code(chargingPile.getCode()); |
| | | platformStartCharging.setCharging_gun_code(tChargingGun.getCode()); |
| | | //使用订单id作为逻辑卡号 |
| | | platformStartCharging.setCard_number(chargingOrder.getId().toString()); |
| | | platformStartCharging.setAccount_balance(account_balance); |
| | | |
| | | log.info(chargingOrder.getCode() + ":-------------------远程调起开始充电请求-------------------" + platformStartCharging.toString()); |
| | | sendMessageClient.platformStartCharging(platformStartCharging); |
| | | |
| | | ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.SECONDS, new LinkedBlockingDeque<>()); |
| | | threadPoolExecutor.execute(()->{ |
| | | //推送成都监管 |
| | | NotificationConnectorChargeStatusVo vo = new NotificationConnectorChargeStatusVo(); |
| | | vo.setOrderCode(chargingOrder.getCode()); |
| | | vo.setChargingGunId(chargingOrder.getChargingGunId()); |
| | | chengDuJianGuanClient.notificationConnectorChargeStatus(vo); |
| | | }); |
| | | |
| | | |
| | | //异步线程检测远程启动的应答结果。如果失败,则需要全额退款 |
| | | Long id = chargingOrder.getId(); |
| | | //执行10分钟的定时任务检测 |
| | | ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); |
| | | scheduler.scheduleAtFixedRate(()->{ |
| | | if(timingDetection(id)){ |
| | | scheduler.shutdown(); |
| | | } |
| | | }, 10, 1, TimeUnit.SECONDS); |
| | | scheduleReservationStart(chargingOrder); |
| | | return AjaxResult.success(); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | private AjaxResult validateReservation(Site site, LocalDateTime reservationTime) { |
| | | if (reservationTime == null) { |
| | | return null; |
| | | } |
| | | if (!Integer.valueOf(1).equals(site.getSupportOrder())) { |
| | | return AjaxResult.error("该电站暂不支持预约充电"); |
| | | } |
| | | if (reservationTime.isBefore(LocalDateTime.now().minusMinutes(1))) { |
| | | return AjaxResult.error("预约时间不能早于当前时间"); |
| | | } |
| | | if (!StringUtils.hasLength(site.getReservationStartTime()) |
| | | || !StringUtils.hasLength(site.getReservationEndTime())) { |
| | | return AjaxResult.error("电站尚未配置预约时段"); |
| | | } |
| | | LocalTime start = LocalTime.parse(site.getReservationStartTime(), DateTimeFormatter.ofPattern("HH:mm")); |
| | | LocalTime end = LocalTime.parse(site.getReservationEndTime(), DateTimeFormatter.ofPattern("HH:mm")); |
| | | if (!isTimeInWindow(LocalTime.now(), start, end) |
| | | || !isTimeInWindow(reservationTime.toLocalTime(), start, end)) { |
| | | return AjaxResult.error("当前时间或预约时间不在允许预约时段内"); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private boolean isTimeInWindow(LocalTime value, LocalTime start, LocalTime end) { |
| | | if (start.equals(end)) { |
| | | return true; |
| | | } |
| | | if (start.isBefore(end)) { |
| | | return !value.isBefore(start) && !value.isAfter(end); |
| | | } |
| | | return !value.isBefore(start) || !value.isAfter(end); |
| | | } |
| | | |
| | | private boolean isSafetyCheckPassed(PreChargeCheck check) { |
| | | return check != null |
| | | && Boolean.TRUE.equals(check.getElectronicLockLock()) |
| | | && Boolean.TRUE.equals(check.getInsulationTesting()) |
| | | && Boolean.TRUE.equals(check.getSecureConnectionDetection()); |
| | | } |
| | | |
| | | private String normalizeVin(String vin) { |
| | | return StringUtils.hasLength(vin) ? vin.replaceAll("\\s+", "").toUpperCase(Locale.ROOT) : null; |
| | | } |
| | | |
| | | private boolean vinMatches(String expectedVin, String actualVin) { |
| | | if (!StringUtils.hasLength(expectedVin) || !StringUtils.hasLength(actualVin)) { |
| | | return false; |
| | | } |
| | | return expectedVin.equals(actualVin) |
| | | || expectedVin.equals(new StringBuilder(actualVin).reverse().toString()); |
| | | } |
| | | |
| | | private void scheduleReservationStart(TChargingOrder chargingOrder) { |
| | | if (chargingOrder.getReservationTime() == null || !chargingOrder.getReservationTime().isAfter(LocalDateTime.now())) { |
| | | return; |
| | | } |
| | | long delay = Math.max(0L, Duration.between(LocalDateTime.now(), chargingOrder.getReservationTime()).toMillis()); |
| | | ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); |
| | | scheduler.schedule(() -> { |
| | | try { |
| | | TChargingOrder latest = this.getById(chargingOrder.getId()); |
| | | if (latest == null || latest.getStatus() != 2) { |
| | | return; |
| | | } |
| | | PreChargeCheck check = redisService.getCacheObject("AQJC_" + latest.getChargingGunId()); |
| | | if (isSafetyCheckPassed(check)) { |
| | | startChargingAfterSafety(latest, check); |
| | | } |
| | | } finally { |
| | | scheduler.shutdown(); |
| | | } |
| | | }, delay, TimeUnit.MILLISECONDS); |
| | | } |
| | | |
| | | private void startChargingAfterSafety(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())) { |
| | | return; |
| | | } |
| | | if (latest.getReservationTime() != null && latest.getReservationTime().isAfter(LocalDateTime.now())) { |
| | | return; |
| | | } |
| | | TChargingGun gun = chargingGunClient.getChargingGunById(latest.getChargingGunId()).getData(); |
| | | TChargingPile pile = chargingPileClient.getChargingPileById(gun.getChargingPileId()).getData(); |
| | | String actualVin = normalizeVin(check.getActualVin()); |
| | | String expectedVin = normalizeVin(latest.getExpectedVin()); |
| | | if (Integer.valueOf(1).equals(pile.getVinFlag()) |
| | | && !vinMatches(expectedVin, actualVin)) { |
| | | check.setStartupSuccess(3); |
| | | check.setFailureCause(9); |
| | | latest.setActualVin(actualVin); |
| | | this.updateById(latest); |
| | | redisService.setCacheObject("AQJC_" + latest.getChargingGunId(), check, 24L, TimeUnit.HOURS); |
| | | refund(latest.getCode()); |
| | | return; |
| | | } |
| | | PlatformStartCharging command = new PlatformStartCharging(); |
| | | command.setTransaction_serial_number(latest.getCode()); |
| | | command.setCharging_pile_code(pile.getCode()); |
| | | command.setCharging_gun_code(gun.getCode()); |
| | | command.setCard_number(latest.getId().toString()); |
| | | command.setAccount_balance(latest.getChargeAmount()); |
| | | check.setStartCommandSent(true); |
| | | latest.setActualVin(actualVin); |
| | | this.updateById(latest); |
| | | redisService.setCacheObject("AQJC_" + latest.getChargingGunId(), check, 24L, TimeUnit.HOURS); |
| | | log.info(latest.getCode() + ":安全检测及VIN校验通过,下发启动充电命令:" + command); |
| | | sendMessageClient.platformStartCharging(command); |
| | | ScheduledExecutorService resultScheduler = Executors.newScheduledThreadPool(1); |
| | | resultScheduler.scheduleAtFixedRate(() -> { |
| | | if (timingDetection(latest.getId())) { |
| | | resultScheduler.shutdown(); |
| | | } |
| | | }, 10, 1, TimeUnit.SECONDS); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | throw new ServiceException("启动充电锁等待被中断"); |
| | | } finally { |
| | | if (lock.isHeldByCurrentThread()) { |
| | | lock.unlock(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 定时检测mongodb数据库数据 |
| | | * |
| | |
| | | TChargingGun chargingGun = chargingGunClient.getChargingGunByCode(code).getData(); |
| | | PreChargeCheck preChargeCheck1 = redisService.getCacheObject("AQJC_" + chargingGun.getId()); |
| | | if (null != preChargeCheck1) { |
| | | preChargeCheck1.setElectronicLockLock(true); |
| | | preChargeCheck1.setInsulationTesting(true); |
| | | preChargeCheck1.setSecureConnectionDetection(securityDetection.getSecure_connection() == 1); |
| | | preChargeCheck1.setElectronicLockLock(Integer.valueOf(1).equals(securityDetection.getElectronic_lock_lock())); |
| | | preChargeCheck1.setInsulationTesting(Integer.valueOf(0).equals(securityDetection.getNsulation_detection())); |
| | | preChargeCheck1.setSecureConnectionDetection(Integer.valueOf(1).equals(securityDetection.getSecure_connection())); |
| | | preChargeCheck1.setActualVin(normalizeVin(securityDetection.getVin())); |
| | | redisService.setCacheObject("AQJC_" + chargingGun.getId(), preChargeCheck1, 24L, TimeUnit.HOURS); |
| | | if (isSafetyCheckPassed(preChargeCheck1)) { |
| | | TChargingOrder pendingOrder = this.getOne(new LambdaQueryWrapper<TChargingOrder>() |
| | | .eq(TChargingOrder::getChargingGunId, chargingGun.getId()) |
| | | .eq(TChargingOrder::getRechargePaymentStatus, 2) |
| | | .eq(TChargingOrder::getStatus, 2) |
| | | .eq(TChargingOrder::getDelFlag, 0) |
| | | .orderByDesc(TChargingOrder::getCreateTime) |
| | | .last("limit 1")); |
| | | if (pendingOrder != null) { |
| | | startChargingAfterSafety(pendingOrder, preChargeCheck1); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | preChargeCheck.setInsulationTesting(false); |
| | | preChargeCheck.setSecureConnectionDetection(false); |
| | | preChargeCheck.setStartupSuccess(1); |
| | | preChargeCheck.setAddTime(LocalDateTime.now()); |
| | | preChargeCheck.setStartCommandSent(false); |
| | | preChargeCheck.setAddTime(chargingOrder.getReservationTime() != null ? chargingOrder.getReservationTime() : LocalDateTime.now()); |
| | | String key = "AQJC_" + chargingOrder.getChargingGunId(); |
| | | redisService.setCacheObject(key, preChargeCheck, 24L, TimeUnit.HOURS); |
| | | |