package com.jsowell.netty.handler; import com.alibaba.fastjson2.JSONObject; import com.google.common.primitives.Bytes; import com.jsowell.common.constant.Constants; import com.jsowell.common.core.domain.ykc.YKCDataProtocol; import com.jsowell.common.core.domain.ykc.YKCFrameTypeCode; import com.jsowell.common.enums.ykc.CardStatusEnum; import com.jsowell.common.enums.ykc.ReturnCodeEnum; import com.jsowell.common.enums.ykc.StartModeEnum; import com.jsowell.common.exception.BusinessException; import com.jsowell.common.util.BytesUtil; import com.jsowell.common.util.StringUtils; import com.jsowell.common.util.YKCUtils; import com.jsowell.netty.factory.YKCOperateFactory; import com.jsowell.pile.domain.MemberPlateNumberRelation; import com.jsowell.pile.domain.PileAuthCard; import com.jsowell.pile.dto.GenerateOrderDTO; import com.jsowell.pile.service.IMemberBasicInfoService; import com.jsowell.pile.service.IMemberPlateNumberRelationService; import com.jsowell.pile.service.IOrderBasicInfoService; import com.jsowell.pile.service.IPileAuthCardService; import com.jsowell.wxpay.service.WxAppletRemoteService; import io.netty.channel.Channel; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Map; /** * 充电桩主动申请启动充电 0x31 * * 启动充电鉴权结果 * @author JS-ZZA * @date 2022/9/19 14:29 */ @Slf4j @Component public class ConfirmStartChargingRequestHandler extends AbstractHandler{ private final String type = YKCUtils.frameType2Str(YKCFrameTypeCode.REQUEST_START_CHARGING_CODE.getBytes()); @Autowired private IPileAuthCardService pileAuthCardService; @Autowired private IOrderBasicInfoService orderBasicInfoService; @Autowired private IMemberPlateNumberRelationService memberPlateNumberRelationService; @Autowired private WxAppletRemoteService wxAppletRemoteService; @Autowired private IMemberBasicInfoService memberBasicInfoService; @Override public void afterPropertiesSet() throws Exception { YKCOperateFactory.register(type, this); } @Override public byte[] supplyProcess(YKCDataProtocol ykcDataProtocol, Channel channel) { log.info("[===充电桩主动申请启动充电===] param:{}, channel:{}", JSONObject.toJSONString(ykcDataProtocol), channel.toString()); // 获取消息体 byte[] msgBody = ykcDataProtocol.getMsgBody(); int startIndex = 0; int length = 7; // 桩编码 byte[] pileSnByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); String pileSn = BytesUtil.binary(pileSnByteArr, 16); // 保存时间 saveLastTime(pileSn); // 枪号 startIndex += length; length = 1; byte[] connectorNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); String connectorCode = BytesUtil.bcd2Str(connectorNumByteArr); // 启动方式 // 0x01 表示通过刷卡启动充电 // 0x02 表求通过帐号启动充电 (暂不支持) // 0x03 表示vin码启动充电 startIndex += length; byte[] startModeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); String startMode = BytesUtil.bcd2Str(startModeByteArr); // 是否需要密码 0x00 不需要 0x01 需要 startIndex += length; byte[] needPasswordFlagByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); String needPasswordFlag = BytesUtil.bcd2Str(needPasswordFlagByteArr); // 物理卡号 不足 8 位补 0 startIndex += length; length = 8; byte[] cardNumByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); String physicsCard = BytesUtil.binary(cardNumByteArr, 16); log.info("桩号:{}申请充电物理卡号:{}", pileSn, physicsCard); // 输入密码 对用户输入的密码进行16 位MD5 加密,采用小写上传 startIndex += length; length = 16; byte[] inputPasswordByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); // VIN码 startIndex += length; length = 17; byte[] vinCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); String vinCode = BytesUtil.ascii2Str(vinCodeByteArr); log.info("桩号:{}申请充电VIN码:{}", pileSn, vinCode); /** * 刷卡启动充电 */ String logicCard = ""; byte[] authenticationFlagByteArr = Constants.zeroByteArray; // 鉴权成功标识 byte[] accountBalanceByteArr = Constants.zeroByteArray; // 账户余额 String transactionCode = ""; try { if (StringUtils.equals("01", startMode)) { // 查询卡信息 根据传过来的物理卡号查询数据库中此卡信息 PileAuthCard pileAuthCardInfo = pileAuthCardService.selectCardInfoByLogicCard(physicsCard); if (pileAuthCardInfo == null) { // 未查到此卡信息 throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARD_HAS_NO_INFO); } if (StringUtils.isBlank(pileAuthCardInfo.getMemberId())) { // 卡未绑定用户 throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARD_NOT_BIND_USER); } // 判断卡状态 if (!StringUtils.equals(CardStatusEnum.NORMAL.getCode(), pileAuthCardInfo.getStatus())) { return null; } // 刷卡生成订单 刷卡启动充电 GenerateOrderDTO dto = new GenerateOrderDTO(); dto.setPileAuthCardInfo(pileAuthCardInfo); dto.setPileSn(pileSn); dto.setConnectorCode(connectorCode); dto.setStartMode(StartModeEnum.AUTH_CARD.getValue()); dto.setMemberId(pileAuthCardInfo.getMemberId()); Map map = orderBasicInfoService.generateOrderByCard(dto); if (map != null) { transactionCode = (String) map.get("transactionCode"); accountBalanceByteArr = YKCUtils.getPriceByte(String.valueOf(map.get("accountBalance")), 2); // 鉴权成功标识 0x00 失败 0x01 成功 authenticationFlagByteArr = Constants.oneByteArray; }else { throw new BusinessException("", "生成刷卡订单失败"); } } } catch (BusinessException e){ transactionCode = Constants.ILLEGAL_TRANSACTION_CODE; accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8); authenticationFlagByteArr = Constants.zeroByteArray; log.error("刷卡启动充电鉴权 error:{}, {}", e.getCode(), e.getMessage()); }catch (Exception e){ transactionCode = Constants.ILLEGAL_TRANSACTION_CODE; accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8); authenticationFlagByteArr = Constants.zeroByteArray; log.error("刷卡启动充电鉴权 error", e); } try { /** * VIN码启动充电 */ if (StringUtils.equals("03", startMode)) { // 通过vin码查询数据库绑定用户信息 MemberPlateNumberRelation plateInfo = memberPlateNumberRelationService.getMemberPlateInfoByVinCode(vinCode); if (plateInfo == null) { throw new BusinessException("", "未查到绑定用户信息"); } if (!StringUtils.equals("1", plateInfo.getVinStatus())) { // 1- 正常使用 throw new BusinessException("", "vin状态不正确"); } // vin码生成订单 vin启动充电 GenerateOrderDTO dto = new GenerateOrderDTO(); dto.setMemberPlateNumberRelation(plateInfo); dto.setPileSn(pileSn); dto.setConnectorCode(connectorCode); dto.setStartMode(StartModeEnum.VIN_CODE.getValue()); dto.setMemberId(plateInfo.getMemberId()); Map map = orderBasicInfoService.generateOrderByCard(dto); if (map != null) { transactionCode = (String) map.get("transactionCode"); accountBalanceByteArr = YKCUtils.getPriceByte(String.valueOf(map.get("accountBalance")), 2); // 鉴权成功标识 0x00 失败 0x01 成功 authenticationFlagByteArr = Constants.oneByteArray; }else { throw new BusinessException("", "生成vin订单失败"); } } }catch (BusinessException e){ transactionCode = Constants.ILLEGAL_TRANSACTION_CODE; accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8); authenticationFlagByteArr = Constants.zeroByteArray; log.error("VIN码启动充电鉴权 error:{}, {}", e.getCode(), e.getMessage()); }catch (Exception e) { transactionCode = Constants.ILLEGAL_TRANSACTION_CODE; accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8); authenticationFlagByteArr = Constants.zeroByteArray; log.error("VIN码启动充电鉴权 error", e); } // 应答 // 交易流水号 // String transactionCode = IdUtils.generateTransactionCode(pileSn, connectorCode); byte[] serialNumByteArr = BytesUtil.str2Bcd(transactionCode); // 逻辑卡号 // String logicCardNum = "00000000"; // 账户余额 保留两位小数 // MemberVO memberVO = memberBasicInfoService.selectInfoByPhysicsCard(physicsCard); // BigDecimal principalBalance = memberVO.getPrincipalBalance(); // 本金金额 // double accountBalance = principalBalance.add(memberVO.getGiftBalance()).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); // byte[] accountBalanceByteArr = BytesUtil.str2Bcd(String.valueOf(accountBalance)); // 鉴权成功标识 0x00 失败 0x01 成功 // byte[] authenticationFlagByteArr = Constants.oneByteArray; /** * 失败原因 * 0x01 账户不存在 * 0x02 账户冻结 * 0x03 账户余额不足 * 0x04 该卡存在未结账记录 * 0x05 桩停用 * 0x06 该账户不能在此桩上充电 * 0x07 密码错误 * 0x08 电站电容不足 * 0x09 系统中vin 码不存在 * 0x0A 该桩存在未结账记录 * 0x0B 该桩不支持刷卡 */ byte[] defeatReasonByteArr = Constants.zeroByteArray; // 不足位数的值补零 // cardNumByteArr = BytesUtil.checkLengthAndBehindAppendZero(cardNumByteArr, 16); // serialNumByteArr = BytesUtil.checkLengthAndBehindAppendZero(serialNumByteArr, 32); // pileSnByteArr = BytesUtil.checkLengthAndBehindAppendZero(pileSnByteArr, 14); // accountBalanceByteArr = BytesUtil.checkLengthAndBehindAppendZero(accountBalanceByteArr, 8); // 拼装消息体 byte[] msgBodyByteArr = Bytes.concat(serialNumByteArr, pileSnByteArr, connectorNumByteArr, cardNumByteArr, accountBalanceByteArr, authenticationFlagByteArr, defeatReasonByteArr); return getResult(ykcDataProtocol, msgBodyByteArr); } }