package com.jsowell.thirdparty.huawei; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.google.common.collect.Maps; import com.jsowell.common.constant.CacheConstants; import com.jsowell.common.constant.Constants; import com.jsowell.common.core.domain.ykc.RealTimeMonitorData; import com.jsowell.common.core.domain.ykc.TransactionRecordsData; import com.jsowell.common.core.redis.RedisCache; import com.jsowell.common.enums.thirdparty.ThirdPartyOperatorIdEnum; import com.jsowell.common.enums.thirdparty.ThirdPlatformTypeEnum; import com.jsowell.common.enums.thirdparty.huawei.StartFailedReasonEnum; import com.jsowell.common.enums.thirdparty.huawei.StopFailedReasonEnum; import com.jsowell.common.enums.ykc.OrderStatusEnum; import com.jsowell.common.enums.ykc.PileConnectorDataBaseStatusEnum; import com.jsowell.common.enums.ykc.StartModeEnum; import com.jsowell.common.util.DateUtils; import com.jsowell.common.util.StringUtils; import com.jsowell.common.util.Threads; import com.jsowell.common.util.YKCUtils; import com.jsowell.common.util.spring.SpringUtils; import com.jsowell.pile.domain.*; import com.jsowell.pile.domain.huawei.HWStationInfo; import com.jsowell.pile.domain.huawei.HWStationStatusInfo; import com.jsowell.pile.dto.GenerateOrderDTO; import com.jsowell.pile.dto.ThirdPartyCommonStartChargeDTO; import com.jsowell.pile.dto.huawei.*; import com.jsowell.pile.service.*; import com.jsowell.pile.service.programlogic.AbstractProgramLogic; import com.jsowell.pile.service.programlogic.ProgramLogicFactory; import com.jsowell.pile.thirdparty.CommonParamsDTO; import com.jsowell.pile.vo.huawei.QueryChargeStatusVO; import com.jsowell.pile.vo.huawei.QueryEquipAuthVO; import com.jsowell.pile.vo.huawei.QueryStartChargeVO; import com.jsowell.pile.vo.uniapp.customer.BillingPriceVO; import com.jsowell.pile.vo.web.PileStationVO; import com.jsowell.thirdparty.lianlian.common.CommonResult; import com.jsowell.thirdparty.lianlian.domain.ConnectorStatusInfo; import com.jsowell.thirdparty.lianlian.service.LianLianService; import com.jsowell.thirdparty.platform.util.Cryptos; import com.jsowell.thirdparty.platform.util.Encodes; import com.jsowell.thirdparty.platform.util.GBSignUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.math.RoundingMode; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * 华为Service * * @author Lemon * @Date 2024/1/19 14:10:02 */ @Service @Slf4j public class HuaweiServiceV2 { // 引入线程池 private ThreadPoolTaskExecutor executor = SpringUtils.getBean("threadPoolTaskExecutor"); @Autowired private LianLianService lianLianService; @Autowired private PileStationInfoService pileStationInfoService; @Autowired private PileConnectorInfoService pileConnectorInfoService; @Autowired private PileBasicInfoService pileBasicInfoService; @Autowired private ThirdPartySettingInfoService thirdPartySettingInfoService; @Autowired private ThirdPartyPlatformConfigService thirdPartyPlatformConfigService; @Autowired private PileBillingTemplateService pileBillingTemplateService; @Autowired private PileMerchantInfoService pileMerchantInfoService; @Autowired private OrderBasicInfoService orderBasicInfoService; @Autowired private MemberPlateNumberRelationService memberPlateNumberRelationService; @Autowired private IThirdpartySnRelationService thirdpartySnRelationService; @Autowired private RedisCache redisCache; /** * 获取华为 Token * @return */ public String getHuaWeiToken() { String operatorId = Constants.OPERATORID_JIANG_SU; String redisKey = CacheConstants.HUAWEI_GET_TOKEN + operatorId; // 先查缓存 String cacheToken = redisCache.getCacheObject(redisKey); if (StringUtils.isNotBlank(cacheToken)) { return cacheToken; } // 通过华为的type查询出密钥配置 ThirdPartySettingInfo info = new ThirdPartySettingInfo(); info.setType(ThirdPlatformTypeEnum.HUA_WEI.getTypeCode()); ThirdPartySettingInfo settingInfo = thirdPartySettingInfoService.selectSettingInfo(info); String operatorSecret = settingInfo.getOperatorSecret(); String dataSecret = settingInfo.getDataSecret(); String dataSecretIv = settingInfo.getDataSecretIv(); String signSecret = settingInfo.getSignSecret(); String urlAddress = settingInfo.getUrlAddress(); String requestUrl = urlAddress + "query_token"; // 拼装参数 JSONObject jsonObject = new JSONObject(); jsonObject.put("OperatorID", operatorId); jsonObject.put("OperatorSecret", operatorSecret); // 加密 byte[] encryptText = Cryptos.aesEncrypt(jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8), dataSecret.getBytes(), dataSecretIv.getBytes()); String strData = Encodes.encodeBase64(encryptText); Map request = new LinkedHashMap<>(); request.put("OperatorID", Constants.OPERATORID_JIANG_SU); request.put("Data", strData); request.put("TimeStamp", DateUtils.parseDateToStr(DateUtils.YYYYMMDDHHMMSS, new Date())); request.put("Seq", "0001"); // 生成签名 String sig = GBSignUtils.sign(request, signSecret); request.put("Sig", sig); String tokenRequest = JSON.toJSONString(request); // 向华为发送请求 String response = HttpUtil.post(requestUrl, tokenRequest); CommonResult commonResult = JSONObject.parseObject(response, CommonResult.class); if (commonResult.getRet() != 0) { return commonResult.getMsg(); } // 解密data byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64((String) commonResult.getData()), dataSecret.getBytes(), dataSecretIv.getBytes()); String dataStr = new String(plainText, StandardCharsets.UTF_8); // Map resultMap = (Map) JSON.parse(dataStr); JSONObject resultJson = JSONObject.parseObject(dataStr); int succStat = resultJson.getInteger("SuccStat"); if (succStat != 0) { return resultJson.getString("FailReason"); } String token = resultJson.getString("AccessToken"); int tokenAvailableTime = resultJson.getInteger("TokenAvailableTime"); // 凭证有效期,单位秒 // 存入缓存 redisCache.setCacheObject(redisKey, token, tokenAvailableTime, TimeUnit.SECONDS); return token; } public Map generateToken(CommonParamsDTO dto) throws UnsupportedEncodingException { return lianLianService.generateToken(dto); } public Map checkoutSign(CommonParamsDTO dto) { return lianLianService.checkoutSign(dto); } /** * 平台充电设备编码同步 * * notification_operation_system_info * * @param stationId * @return */ public String notificationOperationSystemInfo(String stationId) { String requestName = "notification_operation_system_info"; List equipmentLogicInfos = new ArrayList<>(); // 通过站点id查询站点信息 PileStationVO stationInfo = pileStationInfoService.getStationInfo(stationId); if (stationInfo == null) { return null; } HWStationInfo hwStationInfo = HWStationInfo.builder() .stationId(stationInfo.getId()) .stationName(stationInfo.getStationName()) .build(); // 查询桩列表 equipmentLogicInfos = getPileListV2(stationId); hwStationInfo.setEquipmentInfoNum(equipmentLogicInfos.size()); hwStationInfo.setEquipmentLogicInfos(equipmentLogicInfos); String jsonString = JSON.toJSONString(hwStationInfo); // 获取令牌 String token = getHuaWeiToken(); // 发送请求 // String result = HttpRequestUtil.sendPost(token, jsonString, url, dataSecret, dataSecretIv, operatorId, signSecret); String result = sendMsg2HuaWei(jsonString, token, requestName); return result; } /** * 设备接口状态查询 * * query_station_status * * @param stationIds * @return */ public Map queryStationStatus(List stationIds) { Map resultMap = new LinkedHashMap<>(); String requestName = "query_station_status"; // 拼装参数 JSONObject jsonObject = new JSONObject(); jsonObject.put("StationIDs", stationIds); String jsonString = jsonObject.toJSONString(); // 向华为发送请求 // 获取令牌 String token = getHuaWeiToken(); // 发送请求 String result = sendMsg2HuaWei(jsonString, token, requestName); // 转换成 StationStatus 对象 JSONObject jsonStationStatus = JSONObject.parseObject(result); if (jsonStationStatus == null) { return null; } // 先转成 jsonArray JSONArray stationStatusInfos = jsonStationStatus.getJSONArray("StationStatusInfos"); // 转成对应的 List List hwStationStatusInfos = stationStatusInfos.toList(HWStationStatusInfo.class); for (HWStationStatusInfo hwStationStatusInfo : hwStationStatusInfos) { String stationId = hwStationStatusInfo.getStationId(); List connectorStatusInfos = hwStationStatusInfo.getConnectorStatusInfos(); // 获取对应的枪口状态 for (HWStationStatusInfo.ConnectorStatusInfo connectorStatusInfo : connectorStatusInfos) { String connectorId = connectorStatusInfo.getConnectorId(); String status = connectorStatusInfo.getStatus(); String pileSn = StringUtils.substring(connectorId, 0, 14); // 修改对应枪口状态 pileConnectorInfoService.updateConnectorStatus(connectorId, status); // 将对应枪口的订单存入map resultMap.put(connectorId, status); if (!StringUtils.equals(Constants.ZERO, status)) { setPileAlive(pileSn); } } } return resultMap; } /** * 接收设备接口状态变化推送 * 需在Controller传入operatorId * * @param connectorStatusInfo * @return */ public Map receiveNotificationStationStatus(ConnectorStatusInfo connectorStatusInfo) { String pileConnectorCode = connectorStatusInfo.getConnectorID(); Integer status = connectorStatusInfo.getStatus(); // String pileSn = StringUtils.substring(pileConnectorCode, 0, 14); String pileSn = YKCUtils.getPileSn(pileConnectorCode); if (status != 0) { setPileAlive(pileSn); } ThirdPartyPlatformConfig configInfo = thirdPartyPlatformConfigService.getInfoByOperatorId(connectorStatusInfo.getOperatorId()); if (configInfo == null) { return null; } // 将枪口状态改为对应的状态 pileConnectorInfoService.updateConnectorStatus(pileConnectorCode, String.valueOf(status)); // 构造返回参数 JSONObject jsonObject = new JSONObject(); jsonObject.put("Status", 0); Map resultMap = getResultMap(jsonObject); return resultMap; } /** * 请求设备认证 * @param connectorId * @return */ public QueryEquipAuthVO queryEquipAuth(String connectorId) { String requestName = "query_equip_auth"; // 生成设备认证流水号(格式“运营商ID + 唯一编号”(<=27字符)) // 生成唯一编号(用时间戳表示) long currentTimeMillis = System.currentTimeMillis(); String equipAuthSeq = Constants.OPERATORID_JIANG_SU + currentTimeMillis; // 拼装参数 JSONObject jsonObject = new JSONObject(); jsonObject.put("EquipAuthSeq", equipAuthSeq); jsonObject.put("ConnectorID", connectorId); String jsonString = jsonObject.toJSONString(); // 向华为发送请求 // 获取令牌 String token = getHuaWeiToken(); // 发送请求 String result = sendMsg2HuaWei(jsonString, token, requestName); if (result == null) { return null; } // 转换成 StationStatus 对象 QueryEquipAuthVO queryEquipAuthVO = JSON.parseObject(result, QueryEquipAuthVO.class); String connectorID = queryEquipAuthVO.getConnectorID(); String pileSn = StringUtils.substring(connectorID, 0, 14); setPileAlive(pileSn); return queryEquipAuthVO; } /** * 请求计费策略 * @param dto * @return */ public Map requestEquipBusinessPolicy(RequestEquipBusinessPolicyDTO dto) { String pileConnectorCode = dto.getConnectorID(); String equipBizSeq = dto.getEquipBizSeq(); // 根据枪口号查询计费模板,并返回信息 ThirdPartyPlatformConfig configInfo = thirdPartyPlatformConfigService.getInfoByOperatorId(dto.getOperatorId()); if (configInfo == null) { return null; } // 截取桩号 // String pileSn = StringUtils.substring(pileConnectorCode, 0, 14); String pileSn = YKCUtils.getPileSn(pileConnectorCode); // 查询该桩的站点id PileBasicInfo pileBasicInfo = pileBasicInfoService.selectPileBasicInfoBySN(pileSn); // 根据桩号查询正在使用的计费模板 List billingPriceVOList = pileBillingTemplateService.queryBillingPrice(String.valueOf(pileBasicInfo.getStationId())); JSONObject resultJson = new JSONObject(); resultJson.put("EquipBizSeq", equipBizSeq); resultJson.put("ConnectorID", pileConnectorCode); if (CollectionUtils.isEmpty(billingPriceVOList)) { // 为空说明未查到该枪口的计费模板 resultJson.put("SuccStat", 1); resultJson.put("FailReason", 1); }else { // 延时 500ms,异步调用 下发计费策略 接口 CompletableFuture.runAsync(() -> { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } String result = deliverEquipBusinessPolicy(equipBizSeq, pileConnectorCode); log.info("华为 异步调用 下发计费策略 接口 result:{}", result); }, executor); resultJson.put("SuccStat", 0); resultJson.put("FailReason", 0); } // 加密 Map resultMap = Maps.newLinkedHashMap(); // 加密数据 byte[] encryptText = Cryptos.aesEncrypt(resultJson.toJSONString().getBytes(), configInfo.getDataSecret().getBytes(), configInfo.getDataSecretIv().getBytes()); String encryptData = Encodes.encodeBase64(encryptText); resultMap.put("Data", encryptData); // 生成sig String resultSign = GBSignUtils.sign(resultMap, configInfo.getSignSecret()); resultMap.put("Sig", resultSign); return resultMap; } /** * 下发计费策略 * @param equipBizSeq 策略下发流水号 * @param pileConnectorCode 枪口号 * @return */ public String deliverEquipBusinessPolicy(String equipBizSeq, String pileConnectorCode) { String requestName = "deliver_equip_business_policy"; DeliverEquipBusinessDTO params = new DeliverEquipBusinessDTO(); // 充电业务策略信息 List chargePolicyInfos = new ArrayList<>(); DeliverEquipBusinessDTO.ChargePolicyInfo chargePolicyInfo = new DeliverEquipBusinessDTO.ChargePolicyInfo(); // 业务策略信息体 List pricePolicyInfos = new ArrayList<>(); DeliverEquipBusinessDTO.ChargePolicyInfo.PricePolicyInfo pricePolicyInfo = new DeliverEquipBusinessDTO.ChargePolicyInfo.PricePolicyInfo(); // 计费信息 List policyInfoList = new ArrayList<>(); DeliverEquipBusinessDTO.ChargePolicyInfo.PricePolicyInfo.PolicyInfo policyInfo = null; // 截取桩号 // String pileSn = StringUtils.substring(pileConnectorCode, 0, 14); String pileSn = YKCUtils.getPileSn(pileConnectorCode); // 查询该桩的站点id PileBasicInfo pileBasicInfo = pileBasicInfoService.selectPileBasicInfoBySN(pileSn); String stationId = String.valueOf(pileBasicInfo.getStationId()); // 获取运营商组织结构代码 // MerchantInfoVO merchantInfoVO = pileMerchantInfoService.getMerchantInfoVO(String.valueOf(pileBasicInfo.getMerchantId())); // String organizationCode = merchantInfoVO.getOrganizationCode(); // 通过站点id查询相关配置信息 // ThirdPartyStationRelation relation = new ThirdPartyStationRelation(); // relation.setStationId(Long.parseLong(stationId)); // ThirdPartyStationRelationVO relationInfo = thirdPartyStationRelationService.selectRelationInfo(relation); // if (relationInfo == null) { // return null; // } // 根据站点id查询正在使用的计费模板 List billingPriceVOList = pileBillingTemplateService.queryBillingPrice(stationId); if (CollectionUtils.isEmpty(billingPriceVOList)) { return null; } for (BillingPriceVO billingPriceVO : billingPriceVOList) { // 将时段开始时间、电费、服务费信息进行封装 policyInfo = new DeliverEquipBusinessDTO.ChargePolicyInfo.PricePolicyInfo.PolicyInfo(); String startTime = billingPriceVO.getStartTime() + ":00"; // 00:00:00 格式 // 需要将中间的冒号去掉,改为 000000 格式 String replace = StringUtils.replace(startTime, ":", ""); policyInfo.setStartTime(replace); policyInfo.setElecPrice(new BigDecimal(billingPriceVO.getElectricityPrice()).setScale(4, RoundingMode.DOWN)); policyInfo.setSevicePrice(new BigDecimal(billingPriceVO.getServicePrice()).setScale(4, RoundingMode.DOWN)); policyInfoList.add(policyInfo); } BillingPriceVO billingPriceVO = billingPriceVOList.get(0); // String equipmentOwnerId = ""; // if (StringUtils.isNotBlank(organizationCode) && organizationCode.length() == 18) { // equipmentOwnerId = StringUtils.substring(organizationCode, organizationCode.length() - 10, organizationCode.length() - 1); // }else { // equipmentOwnerId = Constants.OPERATORID_JIANG_SU; // } // 封装参数 pricePolicyInfo.setEquipBizID(Constants.OPERATORID_JIANG_SU + billingPriceVO.getTemplateCode()); // 计费策略ID pricePolicyInfo.setValidStat(1); // 执行状态 String replaceStartTime = StringUtils.replace(billingPriceVO.getPublishTime(), ":", ""); pricePolicyInfo.setValidStartTime(replaceStartTime); // 生效时间 pricePolicyInfo.setValidEndTime("2099-12-31 235959"); // 失效时间 pricePolicyInfo.setSumPeriod(policyInfoList.size()); // 时段数 pricePolicyInfo.setPolicyInfos(policyInfoList); pricePolicyInfos.add(pricePolicyInfo); chargePolicyInfo.setConnectorID(pileConnectorCode); chargePolicyInfo.setPricePolicyInfos(pricePolicyInfos); chargePolicyInfos.add(chargePolicyInfo); params.setEquipBizSeq(equipBizSeq); params.setSumChargePolicyInfos(pricePolicyInfos.size()); params.setChargePolicyInfos(chargePolicyInfos); String jsonString = JSON.toJSONString(params); // 向华为发送请求 // 获取令牌 String token = getHuaWeiToken(); // 发送请求 String result = sendMsg2HuaWei(jsonString, token, requestName); if (result == null) { return null; } // 转换成 DeliverEquipBusinessPolicyVO 对象 // DeliverEquipBusinessPolicyVO vo = JSON.parseObject(result, DeliverEquipBusinessPolicyVO.class); return result; } /** * 请求启动充电 * 只需传枪口号、充电金额、支付方式即可 * @param dto * @return QueryStartChargeVO */ public QueryStartChargeVO queryStartCharge(HWQueryStartChargeDTO dto) { String pileConnectorCode = dto.getConnectorID(); BigDecimal chargeAmount = dto.getMoneyLimit(); String payMode = dto.getPayMode(); String orderCode = dto.getStartChargeSeq(); String requestName = "query_start_charge"; // String startChargeSeq = orderCode; // QueryStartChargeDTO startChargeDTO = new QueryStartChargeDTO(); // startChargeDTO.setOperatorId(ThirdPartyOperatorIdEnum.HUA_WEI.getOperatorId()); // startChargeDTO.setStartChargeSeq(orderCode); // startChargeDTO.setConnectorID(pileConnectorCode); // startChargeDTO.setAccountBalance(chargeAmount); // startChargeDTO.setPayMode(dto.getPayMode()); // Map map = orderBasicInfoService.generateOrderForThirdParty(startChargeDTO); // if (map == null) { // log.error("华为平台生成订单 error"); // throw new BusinessException(ReturnCodeEnum.CODE_GENERATE_ORDER_ERROR); // } // 拼装参数 JSONObject jsonObject = new JSONObject(); jsonObject.put("StartChargeSeq", orderCode); jsonObject.put("ConnectorID", pileConnectorCode); jsonObject.put("MoneyLimit", chargeAmount); String jsonString = jsonObject.toJSONString(); // 向华为发送请求 // 获取令牌 String token = getHuaWeiToken(); // 发送请求 String result = sendMsg2HuaWei(jsonString, token, requestName); if (result == null) { return null; } // 转换成 QueryStartChargeVO 对象 QueryStartChargeVO vo = JSON.parseObject(result, QueryStartChargeVO.class); return vo; } /** * 接收启动充电结果 */ public Map receiveStartChargeResult(ReceiveStartChargeResultDTO dto) { String startChargeSeq = dto.getStartChargeSeq(); Integer startChargeSeqStat = dto.getStartChargeSeqStat(); // 充电订单状态 Integer failReason = dto.getFailReason(); String startTime = dto.getStartTime(); String connectorID = dto.getConnectorID(); String pileSn = StringUtils.substring(connectorID, 0, 14); setPileAlive(pileSn); // 根据订单号查询订单信息 OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByOrderCode(startChargeSeq); // 判断订单状态 if (startChargeSeqStat == Constants.two) { // 充电中 orderBasicInfo.setOrderStatus(OrderStatusEnum.IN_THE_CHARGING.getValue()); // 设置开始时间 orderBasicInfo.setChargeStartTime(DateUtils.parseDate(startTime)); // 设置启动平台类型 orderBasicInfo.setThirdPartyType(ThirdPlatformTypeEnum.HUA_WEI.getTypeCode()); orderBasicInfoService.updateOrderBasicInfo(orderBasicInfo); } if (failReason != 0) { // 启动失败, 将失败原因换成中文 String reason = StartFailedReasonEnum.getReasonByCode(failReason); // 给用户退款(执行0x33中启动失败的操作流程) orderBasicInfoService.chargingPileFailedToStart(orderBasicInfo.getTransactionCode(), reason); } // 构建返回参数 JSONObject jsonObject = new JSONObject(); jsonObject.put("StartChargeSeq", startChargeSeq); jsonObject.put("SuccStat", 0); jsonObject.put("FailReason", 0); Map resultMap = getResultMap(jsonObject); return resultMap; } /** * 查询充电状态 * @param startChargeSeq 订单号 */ public QueryChargeStatusVO queryChargeStatus(String startChargeSeq) { String requestName = "query_equip_charge_status"; // 拼装参数 JSONObject jsonObject = new JSONObject(); jsonObject.put("StartChargeSeq", startChargeSeq); String jsonString = jsonObject.toJSONString(); // 向华为发送请求 // 获取令牌 String token = getHuaWeiToken(); // 发送请求 String result = sendMsg2HuaWei(jsonString, token, requestName); if (result == null) { return null; } // 转换成 QueryChargeStatusVO 对象 QueryChargeStatusVO vo = JSON.parseObject(result, QueryChargeStatusVO.class); Integer connectorStatus = vo.getConnectorStatus(); String connectorID = vo.getConnectorID(); String pileSn = StringUtils.substring(connectorID, 0, 14); if (connectorStatus != 0) { setPileAlive(pileSn); } return vo; } /** * 设置桩上次连接时间 * @param pileSn */ private void setPileAlive(String pileSn) { // 设置桩上次连接时间 String redisKey = CacheConstants.PILE_LAST_CONNECTION + pileSn; redisCache.setCacheObject(redisKey, DateUtils.getDateTime(), CacheConstants.cache_expire_time_1d); } /** * 接收华为所推送的设备充电状态 * @param dto */ public Map receiveEquipChargeStatus(ReceiveEquipChargeStatusDTO dto) { String startChargeSeq = dto.getStartChargeSeq(); // 订单号 String startTime = dto.getStartTime(); String endTime = dto.getEndTime(); String connectorID = dto.getConnectorID(); Integer connectorStatus = dto.getConnectorStatus(); String pileSn = StringUtils.substring(connectorID, 0, 14); if (connectorStatus != 0) { setPileAlive(pileSn); } // 计算充电时间(单位:分钟) long sumChargingTime = DateUtils.intervalTime(startTime, endTime); // 通过订单号查询交易流水号 OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByOrderCode(startChargeSeq); if (orderBasicInfo == null) { return null; } String orderStatus = orderBasicInfo.getOrderStatus(); if (!StringUtils.equals(OrderStatusEnum.IN_THE_CHARGING.getValue(), orderStatus)) { // 如果查出订单状态不为充电中,将订单改状态改为充电中 orderBasicInfo.setOrderStatus(OrderStatusEnum.IN_THE_CHARGING.getValue()); orderBasicInfoService.updateOrderBasicInfo(orderBasicInfo); } // 将源数据存储至缓存 String redisKey = CacheConstants.HUA_WEI_REAL_TIME_INFO_BY_ORDER_CODE + startChargeSeq; String jsonMsg = JSON.toJSONString(dto); // 在同一分钟内,只保留最后一条实时数据 redisCache.hset(redisKey, DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:00", new Date()), jsonMsg); // 封装成实时数据对象 RealTimeMonitorData data = RealTimeMonitorData.builder() .transactionCode(orderBasicInfo.getTransactionCode()) .pileSn(orderBasicInfo.getPileSn()) .connectorCode(orderBasicInfo.getConnectorCode()) .connectorStatus(String.valueOf(connectorStatus)) .pileConnectorCode(orderBasicInfo.getPileConnectorCode()) .outputVoltage(String.valueOf(dto.getVoltageA())) .outputCurrent(String.valueOf(dto.getCurrentA())) .SOC(String.valueOf(dto.getSoc())) .sumChargingTime(String.valueOf(sumChargingTime)) .chargingDegree(String.valueOf(dto.getTotalPower())) .chargingAmount(String.valueOf(dto.getTotalMoney())) .build(); // 将实时数据信息保存至缓存 pileBasicInfoService.saveRealTimeMonitorData2Redis(data); // 构建返回参数 JSONObject jsonObject = new JSONObject(); jsonObject.put("StartChargeSeq", startChargeSeq); jsonObject.put("SuccStat", 0); Map resultMap = getResultMap(jsonObject); return resultMap; } /** * 请求停止充电 * @param startChargeSeq */ public QueryStartChargeVO queryStopCharge(String startChargeSeq) { String requestName = "query_stop_charge"; // 通过订单号查询订单信息 OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByOrderCode(startChargeSeq); if(orderBasicInfo == null) { return null; } JSONObject jsonObject = new JSONObject(); jsonObject.put("StartChargeSeq", startChargeSeq); jsonObject.put("ConnectorID", orderBasicInfo.getPileConnectorCode()); String jsonString = jsonObject.toJSONString(); // 向华为发送请求 // 获取令牌 String token = getHuaWeiToken(); // 发送请求 String result = sendMsg2HuaWei(jsonString, token, requestName); if (result == null) { return null; } // 转换成 QueryStartChargeVO 对象 QueryStartChargeVO vo = JSON.parseObject(result, QueryStartChargeVO.class); String connectorID = vo.getConnectorID(); String pileSn = StringUtils.substring(connectorID, 0, 14); setPileAlive(pileSn); return vo; } /** * 接收华为所推送的停止充电结果 * @param vo * @return */ public Map receiveStopChargeResult(ReceiveStopChargeResultVO vo) { String startChargeSeq = vo.getStartChargeSeq(); Integer startChargeSeqStat = vo.getStartChargeSeqStat(); Integer succStat = vo.getSuccStat(); Integer failReasonCode = vo.getFailReason(); String connectorID = vo.getConnectorID(); String pileSn = StringUtils.substring(connectorID, 0, 14); setPileAlive(pileSn); OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByOrderCode(startChargeSeq); Date date = new Date(); if (orderBasicInfo == null) { return null; } if (succStat == Constants.zero) { // 成功标识为 0-成功,修改订单状态为 2-待结算,具体的订单金额等详情金额,从所推送的订单信息中取 orderBasicInfo.setOrderStatus(OrderStatusEnum.STAY_SETTLEMENT.getValue()); orderBasicInfo.setChargeEndTime(date); }else { // 若成功标识为失败,则将失败原因记录存库 String reason = StopFailedReasonEnum.getReasonByCode(failReasonCode); orderBasicInfo.setReason(reason); } // 统一修改订单 orderBasicInfoService.updateOrderBasicInfo(orderBasicInfo); // 回复华为消息 JSONObject jsonObject = new JSONObject(); jsonObject.put("StartChargeSeq", startChargeSeq); jsonObject.put("SuccStat", 0); jsonObject.put("FailReason", 0); Map resultMap = getResultMap(jsonObject); return resultMap; } /** * 接收订单信息 * @param dto * @return */ public Map receiveOrderInfo(ReceiveOrderInfoDTO dto) { String startChargeSeq = dto.getStartChargeSeq(); List chargeDetails = dto.getChargeDetails(); String pileConnectorCode = dto.getConnectorID(); // String pileSn = StringUtils.substring(pileConnectorCode, 0, 14); String pileSn = YKCUtils.getPileSn(pileConnectorCode); setPileAlive(pileSn); // 将源数据存缓存 String redisKey = CacheConstants.HUA_WEI_ORDER_INFO_BY_ORDER_CODE + startChargeSeq; redisCache.setCacheObject(redisKey, dto); // // 截取桩号 // String pileSn = StringUtils.substring(pileConnectorCode, 0, 14); // // 查询该桩的站点id // PileBasicInfo pileBasicInfo = pileBasicInfoService.selectPileBasicInfoBySN(pileSn); // String stationId = String.valueOf(pileBasicInfo.getStationId()); // // 根据站点id查询正在使用的计费模板 // List billingPriceVOList = pileBillingTemplateService.queryBillingPrice(stationId); // if (CollectionUtils.isEmpty(billingPriceVOList)) { // return null; // } // 查出订单基本信息和详情 OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByOrderCode(startChargeSeq); // OrderDetail orderDetail = orderBasicInfoService.getOrderDetailByOrderCode(startChargeSeq); // 结算订单 TransactionRecordsData data = TransactionRecordsData.builder() .transactionCode(orderBasicInfo.getTransactionCode()) .pileSn(orderBasicInfo.getPileSn()) .connectorCode(orderBasicInfo.getConnectorCode()) .consumptionAmount(String.valueOf(dto.getTotalMoney())) // 订单总金额 .stopReasonMsg(String.valueOf(dto.getStopReason())) // 停止原因 .totalElectricity(String.valueOf(dto.getTotalPower())) // 总用电量 .totalElectricityAmount(String.valueOf(dto.getTotalElecMoney())) // 总电费 .totalServiceAmount(String.valueOf(dto.getTotalSeviceMoney())) // 总服务费 .build(); if (StringUtils.equals(StartModeEnum.VIN_CODE.getValue(), orderBasicInfo.getStartMode())) { // 将交易记录中的交易标识 05 传入实时数据对象,用于结算订单后解锁 vin 状态 data.setTransactionIdentifier("05"); } // 异步结算订单 CompletableFuture.runAsync(() -> { try { String mode = pileMerchantInfoService.getDelayModeByMerchantId(orderBasicInfo.getMerchantId()); AbstractProgramLogic orderLogic = ProgramLogicFactory.getProgramLogic(mode); orderLogic.settleOrderForThirdParty(data, orderBasicInfo); } catch (Exception e) { log.error("异步结算华为订单 error", e); } }, executor); // orderBasicInfo.setChargeStartTime(DateUtils.parseDate(dto.getStartTime())); // orderBasicInfo.setChargeEndTime(DateUtils.parseDate(dto.getEndTime())); // orderBasicInfo.setOrderStatus(OrderStatusEnum.ORDER_COMPLETE.getValue()); // 订单状态改为订单完成 // orderBasicInfo.setReason(String.valueOf(dto.getStopReason())); // TODO 新建停止原因枚举 // // orderDetail.setTotalUsedElectricity(dto.getTotalPower()); // orderDetail.setTotalElectricityAmount(dto.getTotalElecMoney()); // orderDetail.setTotalServiceAmount(dto.getTotalSeviceMoney()); // orderDetail.setTotalOrderAmount(dto.getTotalMoney()); // if (CollectionUtils.isNotEmpty(chargeDetails)) { // for (BillingPriceVO billingPriceVO : billingPriceVOList) { // for (QueryChargeStatusVO.ChargeDetail chargeDetail : chargeDetails) { // if (StringUtils.equals(chargeDetail.getDetailStartTime(), billingPriceVO.getStartTime())) { // // 开始时间相等,则为同一时间段,将该时段的消费金额、用电量存入数据库 // // // } // } // } // } // 通过事务修改订单信息 // OrderTransactionDTO transactionDTO = OrderTransactionDTO.builder() // .orderBasicInfo(orderBasicInfo) // .orderDetail(orderDetail) // .build(); // transactionService.doUpdateOrder(transactionDTO); // 构建返回参数 JSONObject jsonObject = new JSONObject(); jsonObject.put("StartChargeSeq", startChargeSeq); jsonObject.put("ConnectorID", pileConnectorCode); jsonObject.put("ConfirmResult", 0); Map resultMap = getResultMap(jsonObject); return resultMap; } /** * VIN启动充电 * @param dto * @return * @throws Exception */ public Map vinStartCharge(VinStartChargeDTO dto) throws Exception { ThirdPartyPlatformConfig configInfo = thirdPartyPlatformConfigService.getInfoByOperatorId(dto.getOperatorId()); if (configInfo == null) { return null; } int succStat = Constants.one; // 操作结果 int failReason = Constants.one; // 失败原因 JSONObject jsonObject = new JSONObject(); String vinCode = dto.getVin(); String pileConnectorCode = dto.getConnectorID(); // 截取桩号、枪口号 // String pileSn = StringUtils.substring(pileConnectorCode, 0, pileConnectorCode.length() - 2); String pileSn = YKCUtils.getPileSn(pileConnectorCode); // String connectorCode = StringUtils.substring(pileConnectorCode, pileConnectorCode.length() - 2, pileConnectorCode.length()); String connectorCode = YKCUtils.getConnectorCode(pileConnectorCode); // 根据vin查询小程序平台用户信息 MemberPlateNumberRelation basicInfo = memberPlateNumberRelationService.getMemberPlateInfoByVinCode(vinCode); if (basicInfo == null) { // 该用户未注册 jsonObject.put("SuccStat", succStat); jsonObject.put("FailReason", failReason); Map resultMap = getResultMap(jsonObject); return resultMap; }else { // 生成订单,并启动充电 GenerateOrderDTO generateOrderDTO = new GenerateOrderDTO(); generateOrderDTO.setMemberPlateNumberRelation(basicInfo); generateOrderDTO.setPileSn(pileSn); generateOrderDTO.setConnectorCode(connectorCode); generateOrderDTO.setStartMode(StartModeEnum.VIN_CODE.getValue()); generateOrderDTO.setMemberId(basicInfo.getMemberId()); generateOrderDTO.setStartSoc(String.valueOf(dto.getSoc())); Map map = orderBasicInfoService.generateOrderByCard(generateOrderDTO); if (map != null) { // 鉴权成功 succStat = Constants.zero; failReason = Constants.zero; } jsonObject.put("SuccStat", succStat); jsonObject.put("FailReason", failReason); Map resultMap = getResultMap(jsonObject); return resultMap; } } /** * 下发计费策略响应 * @param dto * @return */ public Map receiveDeliverEquipBusinessPolicyResult(DeliverBusinessPolicyResponseDTO dto) { List chargePolicyInfoRets = dto.getChargePolicyInfoRets(); // 将下发失败的进行筛选、收集 List failedList = chargePolicyInfoRets.stream() .filter(x -> x.getSuccStat() == Constants.one) // 1-失败 .collect(Collectors.toList()); for (DeliverBusinessPolicyResponseDTO.ChargePolicyInfoRet chargePolicyInfoRet : failedList) { log.error("华为下发计费策略响应, 枪口:{} 下发计费策略失败, 失败原因:{}", chargePolicyInfoRet.getConnectorID(), chargePolicyInfoRet.getFailReason()); // TODO 重新下发 } JSONObject jsonObject = new JSONObject(); jsonObject.put("SuccStat", 0); jsonObject.put("FailReason", 0); Map resultMap = getResultMap(jsonObject); return resultMap; } /** * 华为启动充电流程(用于 CommonService) * @param dto * @return */ public String startChargeFlow(ThirdPartyCommonStartChargeDTO dto) { String thirdPartyType = dto.getThirdPartyType(); List stationIds = dto.getStationIds(); String pileConnectorCode = dto.getPileConnectorCode(); BigDecimal chargeAmount = dto.getChargeAmount(); String payMode = dto.getPayMode(); String label = ThirdPlatformTypeEnum.getTypeLabelByTypeCode(thirdPartyType); // query_station_status 查询站点枪口详情 Map map = queryStationStatus(stationIds); String status = map.get(pileConnectorCode); // 判断枪口状态 if (!StringUtils.equals(PileConnectorDataBaseStatusEnum.OCCUPIED_NOT_CHARGED.getValue(), status)) { log.error(label + "判断枪口状态 error, 枪口状态为:{}", status); } // query_equip_auth 请求设备认证 QueryEquipAuthVO vo = queryEquipAuth(pileConnectorCode); Integer succStat = vo.getSuccStat(); if (succStat != Constants.zero) { log.error(label + "请求设备认证 error, {}", vo.getFailReason()); } // query_start_charge 请求启动充电 HWQueryStartChargeDTO chargeDTO = new HWQueryStartChargeDTO(); chargeDTO.setConnectorID(pileConnectorCode); chargeDTO.setMoneyLimit(chargeAmount); chargeDTO.setPayMode(payMode); chargeDTO.setStartChargeSeq(dto.getOrderCode()); QueryStartChargeVO startChargeVO = queryStartCharge(chargeDTO); if (startChargeVO.getSuccStat() != Constants.zero) { log.error(label + "请求启动充电 error, {}", startChargeVO.getFailReason()); } String startChargeSeq = startChargeVO.getStartChargeSeq(); // 充电订单号 // Threads.sleep(5000); // query_equip_charge_status 查询设备充电状态 QueryChargeStatusVO chargeStatusVO = new QueryChargeStatusVO(); for (int i = 1; i <= 10; i ++) { // 循环 10 次,每次延时5s,查询充电状态 Threads.sleep(5000); chargeStatusVO = queryChargeStatus(startChargeSeq); if (chargeStatusVO != null) { break; } } if (chargeStatusVO == null) { return null; } if (chargeStatusVO.getConnectorStatus() == 3) { // 充电中, 返回充电订单号 return chargeStatusVO.getStartChargeSeq(); } return null; } /** * 获取华为配置信息 * @return */ private ThirdPartySettingInfo getHuaWeiSettingInfo() { // 通过华为的type查询出密钥配置 ThirdPartySettingInfo info = new ThirdPartySettingInfo(); info.setType(ThirdPlatformTypeEnum.HUA_WEI.getTypeCode()); ThirdPartySettingInfo settingInfo = thirdPartySettingInfoService.selectSettingInfo(info); return settingInfo; } /** * 向华为发送请求 * @param jsonString 封装好的json请求参数 * @param token 从华为平台请求到的令牌 * @param requestName 请求接口名称 * @return 请求结果 */ private String sendMsg2HuaWei(String jsonString, String token, String requestName) { log.info("向华为发送请求 jsonString:{}, token:{}, requestName:{}", jsonString, token, requestName); ThirdPartySettingInfo settingInfo = getHuaWeiSettingInfo(); if (settingInfo == null) { return null; } //加密 byte[] encryptText = Cryptos.aesEncrypt(jsonString.getBytes(), settingInfo.getDataSecret().getBytes(), settingInfo.getDataSecretIv().getBytes()); String encryptData = Encodes.encodeBase64(encryptText); Map params = Maps.newLinkedHashMap(); params.put("OperatorID", settingInfo.getOperatorId()); params.put("Data", encryptData); params.put("TimeStamp", DateUtils.parseDateToStr(DateUtils.YYYYMMDDHHMMSS, new Date())); params.put("Seq", "001"); String sign = GBSignUtils.sign(params, settingInfo.getSignSecret()); params.put("Sig", sign); String postData = JSON.toJSONString(params); // 请求url String requestUrl = settingInfo.getUrlAddress() + requestName; String hutoolRequest = HttpRequest.post(requestUrl) .header("Authorization", "Bearer " + token) .body(postData).execute().body(); log.info("华为发送请求 接收到返回数据:{}", hutoolRequest); if (StringUtils.isBlank(hutoolRequest)) { return null; } Map map = (Map) JSON.parse(hutoolRequest); int ret = (int) map.get("Ret"); String resultMsg = (String) map.get("Msg"); if (ret != 0) { // 表示请求有异常 log.error("华为发送请求 error:{}, 源数据:{}", resultMsg, jsonString); return null; } String rData = (String) map.get("Data"); // 解密 byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64(rData), settingInfo.getDataSecret().getBytes(), settingInfo.getDataSecretIv().getBytes()); String plainData = new String(plainText, StandardCharsets.UTF_8); return plainData; } /** * 将需要发送至华为的返回参数加密返回 * @param jsonObject * @return */ private Map getResultMap(JSONObject jsonObject) { log.info("加密华为数据 jsonObject:{}", jsonObject.toJSONString()); String operatorId = ThirdPartyOperatorIdEnum.HUA_WEI.getOperatorId(); ThirdPartyPlatformConfig platformConfig = thirdPartyPlatformConfigService.getInfoByOperatorId(operatorId); if (platformConfig == null) { return null; } Map resultMap = Maps.newLinkedHashMap(); // 加密数据 byte[] encryptText = Cryptos.aesEncrypt(jsonObject.toJSONString().getBytes(), platformConfig.getDataSecret().getBytes(), platformConfig.getDataSecretIv().getBytes()); String encryptData = Encodes.encodeBase64(encryptText); resultMap.put("Data", encryptData); // 生成sig String resultSign = GBSignUtils.sign(resultMap, platformConfig.getSignSecret()); resultMap.put("Sig", resultSign); return resultMap; } private List getPileListV2(String stationId) { List equipmentLogicInfos = new ArrayList<>(); HWStationInfo .EquipmentLogicInfo equipmentLogicInfo = null; // 根据站点 id 查询第三方平台对应 sn 关系表 ThirdpartySnRelation snRelation = ThirdpartySnRelation.builder() .stationId(stationId) .build(); List snRelations = thirdpartySnRelationService.selectThirdpartySnRelationList(snRelation); if (CollectionUtils.isEmpty(snRelations)) { return new ArrayList<>(); } for (ThirdpartySnRelation relation : snRelations) { String pileSn = relation.getPileSn(); equipmentLogicInfo = HWStationInfo.EquipmentLogicInfo.builder() .equipmentId(pileSn) // .equipmentType() .chargeHostESN(relation.getThirdpartyPileSn()) .build(); // 获取枪口信息 List connectorInfoList = getConnectorInfoList(pileSn); if (CollectionUtils.isEmpty(connectorInfoList)) { continue; } equipmentLogicInfo.setConnectorInfoNum(connectorInfoList.size()); equipmentLogicInfo.setConnectorInfos(connectorInfoList); equipmentLogicInfos.add(equipmentLogicInfo); } return equipmentLogicInfos; } /** * 获取桩列表 * @param stationId * @return */ private List getPileList(String stationId) { List equipmentLogicInfos = new ArrayList<>(); HWStationInfo .EquipmentLogicInfo equipmentLogicInfo = null; List pileBasicInfos = pileBasicInfoService.getPileListByStationId(stationId); if (CollectionUtils.isEmpty(pileBasicInfos)) { return new ArrayList<>(); } for (PileBasicInfo pileBasicInfo : pileBasicInfos) { String pileSn = pileBasicInfo.getSn(); equipmentLogicInfo = HWStationInfo.EquipmentLogicInfo.builder() .equipmentId(pileSn) // .equipmentType() .chargeHostESN(pileSn) .build(); // 获取枪口信息 List connectorInfoList = getConnectorInfoList(pileSn); if (CollectionUtils.isEmpty(connectorInfoList)) { continue; } equipmentLogicInfo.setConnectorInfoNum(connectorInfoList.size()); equipmentLogicInfo.setConnectorInfos(connectorInfoList); equipmentLogicInfos.add(equipmentLogicInfo); } return equipmentLogicInfos; } /** * 获取枪口列表 * @param pileSn * @return */ private List getConnectorInfoList(String pileSn) { List connectorInfoList = new ArrayList<>(); HWStationInfo.EquipmentLogicInfo .ConnectorInfo connectorInfo = null; List pileConnectorInfos = pileConnectorInfoService.selectPileConnectorInfoList(pileSn); if (CollectionUtils.isEmpty(pileConnectorInfos)) { return new ArrayList<>(); } int connectorNumber = 0; for (PileConnectorInfo pileConnectorInfo : pileConnectorInfos) { connectorNumber += 1; connectorInfo = HWStationInfo.EquipmentLogicInfo.ConnectorInfo.builder() .connectorID(pileConnectorInfo.getPileConnectorCode()) .connectorNumber(connectorNumber) .build(); connectorInfoList.add(connectorInfo); } return connectorInfoList; } }