From e9573b3ef2689bfb59a61264b600d4262de8f2d4 Mon Sep 17 00:00:00 2001 From: Lemon Date: Mon, 16 Jun 2025 15:59:44 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=200xA1=E5=B9=B6?= =?UTF-8?q?=E5=85=85=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/ykc/YKCFrameTypeCode.java | 2 + .../common/enums/ykc/OrderTypeEnum.java | 37 +++++ .../common/enums/ykc/ReturnCodeEnum.java | 2 + .../PileApplyMergeChargeHandler.java | 145 ++++++++++++++++++ .../jsowell/pile/domain/OrderBasicInfo.java | 15 ++ .../jsowell/pile/dto/GenerateOrderDTO.java | 20 +++ .../pile/dto/VerifyMergeChargeOrderDTO.java | 47 ++++++ .../pile/service/OrderBasicInfoService.java | 7 + .../impl/OrderBasicInfoServiceImpl.java | 63 ++++++++ .../mapper/pile/MemberWalletInfoMapper.xml | 5 +- .../mapper/pile/OrderBasicInfoMapper.xml | 114 +++++++++++++- 11 files changed, 452 insertions(+), 5 deletions(-) create mode 100644 jsowell-common/src/main/java/com/jsowell/common/enums/ykc/OrderTypeEnum.java create mode 100644 jsowell-netty/src/main/java/com/jsowell/netty/handler/yunkuaichong/PileApplyMergeChargeHandler.java create mode 100644 jsowell-pile/src/main/java/com/jsowell/pile/dto/VerifyMergeChargeOrderDTO.java diff --git a/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java b/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java index 0c4d2dd29..d5e5b8a2d 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java +++ b/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java @@ -104,6 +104,8 @@ public enum YKCFrameTypeCode { UPLOAD_PILE_FAULT_RECORD_CODE(0xDB, "上传桩端故障记录"), + PILE_APPLY_MERGE_CHARGE_CODE(0xA1, "充电桩主动申请并充充电"), + // 自定义FrameType PILE_LOG_OUT(9999, "充电桩退出"), diff --git a/jsowell-common/src/main/java/com/jsowell/common/enums/ykc/OrderTypeEnum.java b/jsowell-common/src/main/java/com/jsowell/common/enums/ykc/OrderTypeEnum.java new file mode 100644 index 000000000..aeecc47be --- /dev/null +++ b/jsowell-common/src/main/java/com/jsowell/common/enums/ykc/OrderTypeEnum.java @@ -0,0 +1,37 @@ +package com.jsowell.common.enums.ykc; + +/** + * 订单类型enum + * + * @author Lemon + * @Date 2025/6/16 13:59:20 + */ +public enum OrderTypeEnum { + NORMAL_ORDER("1", "普通订单"), + MERGE_CHARGE_ORDER("2", "并充订单"), + ; + private String value; + + private String lable; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String getLable() { + return lable; + } + + public void setLable(String lable) { + this.lable = lable; + } + + OrderTypeEnum(String value, String lable) { + this.value = value; + this.lable = lable; + } +} diff --git a/jsowell-common/src/main/java/com/jsowell/common/enums/ykc/ReturnCodeEnum.java b/jsowell-common/src/main/java/com/jsowell/common/enums/ykc/ReturnCodeEnum.java index e09c83d96..e50545b62 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/enums/ykc/ReturnCodeEnum.java +++ b/jsowell-common/src/main/java/com/jsowell/common/enums/ykc/ReturnCodeEnum.java @@ -226,6 +226,8 @@ public enum ReturnCodeEnum { CODE_SELECT_INFO_IS_NULL("00700001", "查询信息为空!"), CODE_THIS_VIN_HAS_BEEN_BINDING("00700002", "该vin已被绑定,请检查!"), + + CODE_THIS_VIN_INFO_IS_NULL("007000003", "未查到该vin信息!"), ; private String value; diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/handler/yunkuaichong/PileApplyMergeChargeHandler.java b/jsowell-netty/src/main/java/com/jsowell/netty/handler/yunkuaichong/PileApplyMergeChargeHandler.java new file mode 100644 index 000000000..fe172ea31 --- /dev/null +++ b/jsowell-netty/src/main/java/com/jsowell/netty/handler/yunkuaichong/PileApplyMergeChargeHandler.java @@ -0,0 +1,145 @@ +package com.jsowell.netty.handler.yunkuaichong; + +import com.google.common.primitives.Bytes; +import com.jsowell.common.core.domain.ykc.YKCDataProtocol; +import com.jsowell.common.core.domain.ykc.YKCFrameTypeCode; +import com.jsowell.common.util.BytesUtil; +import com.jsowell.common.util.YKCUtils; +import com.jsowell.netty.factory.YKCOperateFactory; +import com.jsowell.pile.dto.VerifyMergeChargeOrderDTO; +import com.jsowell.pile.service.OrderBasicInfoService; +import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 0xA1 充电桩主动申请并充充电 + * + * @author Lemon + * @Date 2025/6/12 11:37:36 + */ +@Slf4j +@Component +public class PileApplyMergeChargeHandler extends AbstractYkcHandler{ + private final String type = YKCUtils.frameType2Str(YKCFrameTypeCode.PILE_APPLY_MERGE_CHARGE_CODE.getBytes()); + + @Autowired + private OrderBasicInfoService orderBasicInfoService; + + + @Override + public void afterPropertiesSet() throws Exception { + YKCOperateFactory.register(type, this); + } + + @Override + public byte[] supplyProcess(YKCDataProtocol ykcDataProtocol, ChannelHandlerContext channel) { + + // 获取消息体 + byte[] msgBody = ykcDataProtocol.getMsgBody(); + + int startIndex = 0; + int length = 7; + + // 桩编号 + byte[] pileSnByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String pileSn = BytesUtil.binary(pileSnByteArr, 16); + + // 保存时间 + saveLastTimeAndCheckChannel(pileSn, channel); + + // 枪号 + 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); + + // 输入密码 对用户输入的密码进行16 位MD5 加密,采用小写上传 + startIndex += length; + length = 16; + byte[] inputPasswordByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String inputPasswordHexStr = BytesUtil.bin2HexStr(inputPasswordByteArr); + + // VIN码 + startIndex += length; + length = 17; + byte[] vinCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String vinCode = BytesUtil.ascii2StrLittle(vinCodeByteArr); + + // 主辅枪标记 + // 0x00 主枪 + // 0x01 辅枪 + startIndex += length; + length = 1; + byte[] connectorMarkByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String connectorMark = BytesUtil.bcd2Str(connectorMarkByteArr); + + // 并充序号 + // 由桩生成:年月日时分秒,多个枪并充时上送并充序号一致,表示为同一次并充操作 + startIndex += length; + length = 6; + byte[] mergeChargeNumberByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String mergeChargeNumber = BytesUtil.bcd2Str(mergeChargeNumberByteArr); + + // 鉴权方法(返回交易流水号、账户余额、鉴权成功标识) + String pileConnectorCode = pileSn + connectorCode; + VerifyMergeChargeOrderDTO dto = VerifyMergeChargeOrderDTO.builder() + .pileSn(pileSn) + .connectorCode(connectorCode) + .pileConnectorCode(pileConnectorCode) + .startMode(startMode) + .physicsCard(physicsCard) + .vinCode(vinCode) + .connectorMark(connectorMark) + .mergeChargeNumber(mergeChargeNumber) + .build(); + + try { + Map map = orderBasicInfoService.verifyMergeChargeOrder(dto); + + } catch (Exception e) { + log.error("桩号:{}, 并充订单鉴权失败, ", pileSn, e); + } + + String transactionCode = ""; + String accountAmount = ""; + String verifyFlag = ""; + + // 应答 + // 交易流水号 + // 桩编号 + // 枪号 + // 逻辑卡号 + // 账户余额 + // 鉴权成功标志 + // 失败原因 + // 并充序号 + byte[] msgBodyByteArr = Bytes.concat(BytesUtil.str2Bcd(transactionCode), pileSnByteArr, connectorNumByteArr, cardNumByteArr, + BytesUtil.str2Bcd(accountAmount), BytesUtil.str2Bcd(verifyFlag), mergeChargeNumberByteArr); + + + return getResult(ykcDataProtocol, msgBodyByteArr); + } +} diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/domain/OrderBasicInfo.java b/jsowell-pile/src/main/java/com/jsowell/pile/domain/OrderBasicInfo.java index 6ab778acf..654e1ce0f 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/domain/OrderBasicInfo.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/domain/OrderBasicInfo.java @@ -35,6 +35,21 @@ public class OrderBasicInfo { */ private String orderStatus; + /** + * 订单类型(1-普通订单;2-并充订单) + */ + private String orderType; + + /** + * 并充订单序号 + */ + private String mergeChargeNumber; + + /** + * 主枪枪编号 + */ + private String mainConnectorCode; + /** * 会员id */ diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/dto/GenerateOrderDTO.java b/jsowell-pile/src/main/java/com/jsowell/pile/dto/GenerateOrderDTO.java index 21c50f5fa..83041f79e 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/dto/GenerateOrderDTO.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/dto/GenerateOrderDTO.java @@ -88,6 +88,26 @@ public class GenerateOrderDTO extends BasicPileDTO{ */ private MemberPlateNumberRelation MemberPlateNumberRelation; + /** + * 鉴权成功标识 + */ + private boolean verifyFlag; + + /** + * 订单类型(1-普通订单;2-并充订单) + */ + private String orderType; + + /** + * 并充序号(并充启动时有值) + */ + private String mergeChargeNumber; + + /** + * 主枪枪编码(并充启动时有值) + */ + private String mainConnectorCode; + /** * 车牌号码 */ diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/dto/VerifyMergeChargeOrderDTO.java b/jsowell-pile/src/main/java/com/jsowell/pile/dto/VerifyMergeChargeOrderDTO.java new file mode 100644 index 000000000..194f31edf --- /dev/null +++ b/jsowell-pile/src/main/java/com/jsowell/pile/dto/VerifyMergeChargeOrderDTO.java @@ -0,0 +1,47 @@ +package com.jsowell.pile.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 鉴权并充订单DTO + * + * @author Lemon + * @Date 2025/6/12 14:32:38 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class VerifyMergeChargeOrderDTO { + // 桩编号 + private String pileSn; + + // 枪号 + private String connectorCode; + + // 枪口编号 + private String pileConnectorCode; + + // 启动方式 + // 0x01 表示通过刷卡启动充电 + // 0x03 表示vin码启动充电 + private String startMode; + + // 物理卡号 + private String physicsCard; + + // vin + private String vinCode; + + // 主辅枪标记 + // 0x00 主枪 + // 0x01 辅枪 + private String connectorMark; + + // 并充序号 + // 由桩生成:年月日时分秒,多个枪并充时上送并充序号一致,表示为同一次并充操作 + private String mergeChargeNumber; +} diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/OrderBasicInfoService.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/OrderBasicInfoService.java index 74dad65f5..ae7f93b07 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/OrderBasicInfoService.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/OrderBasicInfoService.java @@ -566,4 +566,11 @@ public interface OrderBasicInfoService{ * @param dto */ void setOrderSupplementAmount(OrderSupplementAmountDTO dto); + + /** + * 鉴权并充订单 + * @param dto + * @return + */ + Map verifyMergeChargeOrder(VerifyMergeChargeOrderDTO dto) throws Exception; } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java index 28d210d10..8164a74c8 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java @@ -4542,6 +4542,7 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService { .orderCode(orderCode) .transactionCode(transactionCode) .orderStatus(OrderStatusEnum.NOT_START.getValue()) + .orderType(OrderTypeEnum.NORMAL_ORDER.getValue()) // 订单类型(1-普通订单;2-并充订单) .memberId(dto.getMemberId()) .stationId(stationId) .merchantId(merchantId) @@ -4558,6 +4559,18 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService { .settleAmount(BigDecimal.ZERO) .startType(dto.getStartType()) .build(); + if (StringUtils.equals(OrderTypeEnum.MERGE_CHARGE_ORDER.getValue(), dto.getOrderType())) { + // 并充订单 + orderBasicInfo.setOrderType(dto.getOrderType()); + if (StringUtils.isNotBlank(dto.getMergeChargeNumber())) { + // 并充订单序号 + orderBasicInfo.setMergeChargeNumber(dto.getMergeChargeNumber()); + } + if (StringUtils.isNotBlank(dto.getMainConnectorCode())) { + // 主枪枪编号 + orderBasicInfo.setMainConnectorCode(dto.getMainConnectorCode()); + } + } if (StringUtils.equals(dto.getStartMode(), StartModeEnum.AUTH_CARD.getValue())) { // 鉴权卡启动 orderBasicInfo.setLogicCard(dto.getPileAuthCardInfo().getLogicCard()); @@ -5122,5 +5135,55 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService { logger.info("设置订单待补缴金额, orderCode:{}, supplementAmount:{}, 备注:{}", dto.getOrderCode(), dto.getSupplementAmount(), dto.getRemark()); } + /** + * 鉴权并充订单 + * @param dto + * @return + */ + @Override + public Map verifyMergeChargeOrder(VerifyMergeChargeOrderDTO dto) throws Exception { + Map map = new LinkedHashMap<>(); + + GenerateOrderDTO generateOrderDTO = new GenerateOrderDTO(); + generateOrderDTO.setPileSn(dto.getPileSn()); + generateOrderDTO.setConnectorCode(dto.getConnectorCode()); + generateOrderDTO.setMergeChargeNumber(dto.getMergeChargeNumber()); + + // 判断是否为主枪 + if (StringUtils.equals(Constants.DOUBLE_ZERO, dto.getConnectorMark())) { + // 主枪 + generateOrderDTO.setMainConnectorCode(dto.getPileConnectorCode()); + } + // 区分是卡还是vin充电 + String startMode = dto.getStartMode(); + if (StringUtils.equals(Constants.ZERO_ONE, startMode)) { + // 刷卡鉴权 + // 根据卡号查询用户信息 + String physicsCard = dto.getPhysicsCard(); + PileAuthCard pileAuthCardInfo = pileAuthCardService.selectCardInfoByLogicCard(physicsCard); + if (pileAuthCardInfo == null) { + // 未查到此卡信息 + throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARD_HAS_NO_INFO); + } + generateOrderDTO.setPileAuthCardInfo(pileAuthCardInfo); + generateOrderDTO.setStartMode(StartModeEnum.AUTH_CARD.getValue()); + generateOrderDTO.setMemberId(pileAuthCardInfo.getMemberId()); + }else if (StringUtils.equals(Constants.ZERO_THREE, startMode)) { + // vin鉴权 + // 根据vin查询绑定用户信息 + String vinCode = dto.getVinCode(); + MemberPlateNumberRelation memberInfo = memberPlateNumberRelationService.getMemberPlateInfoByVinCode(vinCode); + if (memberInfo == null) { + throw new BusinessException(ReturnCodeEnum.CODE_THIS_VIN_INFO_IS_NULL); + } + generateOrderDTO.setMemberPlateNumberRelation(memberInfo); + generateOrderDTO.setStartMode(StartModeEnum.VIN_CODE.getValue()); + generateOrderDTO.setMemberId(memberInfo.getMemberId()); + } + // 鉴权通过,生成订单启动充电 + map = generateOrderByCard(generateOrderDTO); + + return map; + } } diff --git a/jsowell-pile/src/main/resources/mapper/pile/MemberWalletInfoMapper.xml b/jsowell-pile/src/main/resources/mapper/pile/MemberWalletInfoMapper.xml index 374a621dd..b0944611e 100644 --- a/jsowell-pile/src/main/resources/mapper/pile/MemberWalletInfoMapper.xml +++ b/jsowell-pile/src/main/resources/mapper/pile/MemberWalletInfoMapper.xml @@ -182,7 +182,10 @@ from member_wallet_info where del_flag = '0' and member_id = #{memberId,jdbcType=INTEGER} - and merchant_id = #{merchantId,jdbcType=VARCHAR} + + and merchant_id = #{merchantId,jdbcType=VARCHAR} + + From 26d5b1064ed6e55fb0afddafcd25f2dc2ad73dd9 Mon Sep 17 00:00:00 2001 From: Lemon Date: Thu, 19 Jun 2025 16:46:23 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=200xA3=E8=BF=90?= =?UTF-8?q?=E8=90=A5=E5=B9=B3=E5=8F=B0=E4=B8=BB=E5=8A=A8=E4=B8=8B=E5=8F=91?= =?UTF-8?q?=E5=B9=B6=E5=85=85=E5=90=AF=E5=8A=A8=E5=85=85=E7=94=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/domain/ykc/YKCFrameTypeCode.java | 4 +- ...AnswerPlatformStartMergeChargeHandler.java | 110 ++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 jsowell-netty/src/main/java/com/jsowell/netty/handler/yunkuaichong/AnswerPlatformStartMergeChargeHandler.java diff --git a/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java b/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java index fc993d9d5..db36233b8 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java +++ b/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java @@ -105,9 +105,11 @@ public enum YKCFrameTypeCode { UPLOAD_PILE_FAULT_RECORD_CODE(0xDB, "上传桩端故障记录"), PILE_APPLY_MERGE_CHARGE_CODE(0xA1, "充电桩主动申请并充充电"), - CONFIRM_MERGE_CHARGE_CODE(0xA2, "运营平台确认并充启动充电"), + PLATFORM_START_MERGE_CHARGE_CODE(0xA4, "运营平台远程控制并充启机"), + ANSWER_PLATFORM_START_MERGE_CODE(0xA3, "远程并充启机命令回复"), + // 自定义FrameType PILE_LOG_OUT(9999, "充电桩退出"), diff --git a/jsowell-netty/src/main/java/com/jsowell/netty/handler/yunkuaichong/AnswerPlatformStartMergeChargeHandler.java b/jsowell-netty/src/main/java/com/jsowell/netty/handler/yunkuaichong/AnswerPlatformStartMergeChargeHandler.java new file mode 100644 index 000000000..4f95b8a16 --- /dev/null +++ b/jsowell-netty/src/main/java/com/jsowell/netty/handler/yunkuaichong/AnswerPlatformStartMergeChargeHandler.java @@ -0,0 +1,110 @@ +package com.jsowell.netty.handler.yunkuaichong; + +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.ChargingFailedReasonEnum; +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.service.OrderBasicInfoService; +import io.netty.channel.ChannelHandlerContext; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * 0xA3 远程并充启机命令回复 + * + * @author Lemon + * @Date 2025/6/19 15:40:15 + */ +@Slf4j +@Component +public class AnswerPlatformStartMergeChargeHandler extends AbstractYkcHandler { + private final String type = YKCUtils.frameType2Str(YKCFrameTypeCode.ANSWER_PLATFORM_START_MERGE_CODE.getBytes()); + + @Autowired + private OrderBasicInfoService orderBasicInfoService; + + @Override + public void afterPropertiesSet() throws Exception { + YKCOperateFactory.register(type, this); + } + + @Override + public byte[] supplyProcess(YKCDataProtocol ykcDataProtocol, ChannelHandlerContext channel) { + // 获取消息体 + byte[] msgBody = ykcDataProtocol.getMsgBody(); + + int startIndex = 0; + int length = 16; + + // 交易流水号 + byte[] transactionCodeByte = BytesUtil.copyBytes(msgBody, startIndex, length); + String transactionCode = BytesUtil.bcd2Str(transactionCodeByte); + + // 桩编码 + startIndex += length; + length = 7; + byte[] pileSnByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String pileSn = BytesUtil.bcd2Str(pileSnByteArr); + + // 保存时间 + saveLastTimeAndCheckChannel(pileSn, channel); + + // 枪号 + startIndex += length; + length = 1; + byte[] connectorCodeByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String connectorCode = BytesUtil.bcd2Str(connectorCodeByteArr); + + // 启动结果 0x00失败 0x01成功 + startIndex += length; + byte[] startResultByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String startResult = BytesUtil.bcd2Str(startResultByteArr); + + /** + * 失败原因 + * + * 桩在收到启充命令后,检测到未插枪则发送 0x33 报文回复充电失败。 + * 若在 60 秒(以收到 0x34 时间开始计算)内检测到枪重新连接,则补送 0x33 成功报文;超时或者离线等其他异常,桩不启充、不补发 0x33 报文 + * 0x00 无 + * 0x01 设备编号不匹配 + * 0x02 枪已在充电 + * 0x03 设备故障 + * 0x04 设备离线 + * 0x05 未插枪 + */ + startIndex += length; + byte[] failedReasonByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String failedReason = BytesUtil.bin2HexStr(failedReasonByteArr); + String failedReasonMsg = ChargingFailedReasonEnum.getMsgByCode(Integer.parseInt(failedReason, 16)); + + // 主辅枪标记 + // 0x00 主枪 + // 0x01 辅枪 + startIndex += length; + length = 1; + byte[] connectorMarkByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String connectorMark = BytesUtil.bcd2Str(connectorMarkByteArr); + + // 并充序号 + // 由桩生成:年月日时分秒,多个枪并充时上送并充序号一致,表示为同一次并充操作 + startIndex += length; + length = 6; + byte[] mergeChargeNumberByteArr = BytesUtil.copyBytes(msgBody, startIndex, length); + String mergeChargeNumber = BytesUtil.bcd2Str(mergeChargeNumberByteArr); + + if (StringUtils.equals(startResult, Constants.DOUBLE_ZERO)) { + // 启动失败 2025年4月2日16点39分修改逻辑:启动失败后不退款, 使用支付完成未启动定时任务退款 + // orderBasicInfoService.chargingPileFailedToStart(transactionCode, failedReasonMsg); + } else { + // 启动成功 + orderBasicInfoService.chargingPileStartedSuccessfully(transactionCode); + } + + return null; + } +} From c5187d1657fc9ea6d3d2243a9d5c40919eeb3de7 Mon Sep 17 00:00:00 2001 From: Lemon Date: Fri, 20 Jun 2025 13:28:42 +0800 Subject: [PATCH 5/7] =?UTF-8?q?update=20=20=E6=96=B0=E5=A2=9E=20=E4=B8=BB?= =?UTF-8?q?=E5=8A=A8=E5=8F=91=E9=80=81=E5=90=AF=E5=8A=A8=E5=B9=B6=E5=85=85?= =?UTF-8?q?=E5=85=85=E7=94=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jsowell-admin/src/test/java/PaymentTestController.java | 8 ++++---- .../jsowell/common/core/domain/ykc/YKCFrameTypeCode.java | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jsowell-admin/src/test/java/PaymentTestController.java b/jsowell-admin/src/test/java/PaymentTestController.java index 62420797f..59f4815f2 100644 --- a/jsowell-admin/src/test/java/PaymentTestController.java +++ b/jsowell-admin/src/test/java/PaymentTestController.java @@ -215,12 +215,12 @@ public class PaymentTestController { */ @Test public void withdraw() { - String merchantId = "349"; + String merchantId = "87"; String orderNo = "drawcash_" + merchantId + "_" + System.currentTimeMillis(); - BigDecimal cashAmt = new BigDecimal("256.47"); - String adapayMemberId = "ACM88073310"; + BigDecimal cashAmt = new BigDecimal("2013.81"); + String adapayMemberId = "AM67987250"; // String adapayAppId = "app_d0c80cb1-ffc8-48cb-a030-fe9bec823aaa"; // 固定参数, 汇付配置的万车充小程序appId - String settleAccountId = "0744607938214272"; + String settleAccountId = "0600303988488384"; String wechatAppId = wechatAppId1; try { adapayService.createDrawcashRequest(orderNo, cashAmt, adapayMemberId, adapayAppId, settleAccountId, wechatAppId); diff --git a/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java b/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java index db36233b8..9557c05a3 100644 --- a/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java +++ b/jsowell-common/src/main/java/com/jsowell/common/core/domain/ykc/YKCFrameTypeCode.java @@ -271,6 +271,8 @@ public enum YKCFrameTypeCode { // 下发二维码 REMOTE_ISSUE_QRCODE(REMOTE_ISSUE_QRCODE_CODE.getCode(), REMOTE_ISSUE_QRCODE_ANSWER_CODE.getCode()), + START_MERGE_CHARGE_CODE(PLATFORM_START_MERGE_CHARGE_CODE.getCode(), ANSWER_PLATFORM_START_MERGE_CODE.getCode()), + // 查询工作参数 QUERY_PILE_WORK_PARAMS(QUERY_PILE_WORK_PARAMS_CODE.getCode(), QUERY_PILE_WORK_PARAMS_ANSWER_CODE.getCode()), From d892f2d7b2171954cfc6a6af6e1515e6782f75dd Mon Sep 17 00:00:00 2001 From: Lemon Date: Mon, 23 Jun 2025 15:02:06 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E7=BB=93=E7=AE=97=E8=B4=A6=E6=88=B7=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pile/AdapayMemberController.java | 24 +++++++++++++++---- .../adapay/dto/AdapayMemberInfoDTO.java | 3 +++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/jsowell-admin/src/main/java/com/jsowell/web/controller/pile/AdapayMemberController.java b/jsowell-admin/src/main/java/com/jsowell/web/controller/pile/AdapayMemberController.java index 0aa6677a7..e42909c2a 100644 --- a/jsowell-admin/src/main/java/com/jsowell/web/controller/pile/AdapayMemberController.java +++ b/jsowell-admin/src/main/java/com/jsowell/web/controller/pile/AdapayMemberController.java @@ -6,6 +6,7 @@ import com.jsowell.adapay.dto.*; import com.jsowell.adapay.service.AdapayService; import com.jsowell.adapay.vo.AdapayAccountBalanceVO; import com.jsowell.common.annotation.Log; +import com.jsowell.common.constant.Constants; import com.jsowell.common.core.controller.BaseController; import com.jsowell.common.core.domain.AjaxResult; import com.jsowell.common.core.page.PageResponse; @@ -15,10 +16,7 @@ import com.jsowell.common.exception.BusinessException; import com.jsowell.common.util.StringUtils; import com.jsowell.pile.service.ClearingWithdrawInfoService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.Map; @@ -201,4 +199,22 @@ public class AdapayMemberController extends BaseController { } return result; } + + /** + * 删除结算账户 + * @param dto + * @return + */ + @PostMapping("/deleteSettleAccount") + public AjaxResult deleteSettleAccount(@RequestBody AdapayMemberInfoDTO dto) { + AjaxResult result = null; + try { + adapayService.createDeleteSettleAccountRequest(dto.getAdapayMemberId(), dto.getSettleAccountId(), Constants.DEFAULT_APP_ID); + result = AjaxResult.success(); + } catch (Exception e) { + logger.error("删除结算账户 error,", e); + result = AjaxResult.error(); + } + return result; + } } diff --git a/jsowell-pile/src/main/java/com/jsowell/adapay/dto/AdapayMemberInfoDTO.java b/jsowell-pile/src/main/java/com/jsowell/adapay/dto/AdapayMemberInfoDTO.java index 9ece25015..f9443cc41 100644 --- a/jsowell-pile/src/main/java/com/jsowell/adapay/dto/AdapayMemberInfoDTO.java +++ b/jsowell-pile/src/main/java/com/jsowell/adapay/dto/AdapayMemberInfoDTO.java @@ -21,6 +21,9 @@ public class AdapayMemberInfoDTO { private String adapayMemberId; + // 结算账户id + private String settleAccountId; + //////////下面是创建结算账户参数/////////// // 银行卡号 private String cardId; From 1e178d68904999347fcc8d08b08a954ef6497781 Mon Sep 17 00:00:00 2001 From: Lemon Date: Wed, 25 Jun 2025 15:37:29 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E7=BB=93=E7=AE=97=E8=B4=A6=E6=88=B7=E3=80=81=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=BB=93=E7=AE=97=E8=B4=A6=E6=88=B7=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pile/AdapayMemberController.java | 22 ++++++++- .../jsowell/adapay/service/AdapayService.java | 49 +++++++++++++++++++ .../mapper/AdapayMemberAccountMapper.java | 13 +++++ .../service/AdapayMemberAccountService.java | 13 +++++ .../impl/AdapayMemberAccountServiceImpl.java | 14 ++++++ .../mapper/pile/AdapayMemberAccountMapper.xml | 16 ++++++ 6 files changed, 126 insertions(+), 1 deletion(-) diff --git a/jsowell-admin/src/main/java/com/jsowell/web/controller/pile/AdapayMemberController.java b/jsowell-admin/src/main/java/com/jsowell/web/controller/pile/AdapayMemberController.java index e42909c2a..0796ccaf4 100644 --- a/jsowell-admin/src/main/java/com/jsowell/web/controller/pile/AdapayMemberController.java +++ b/jsowell-admin/src/main/java/com/jsowell/web/controller/pile/AdapayMemberController.java @@ -209,7 +209,8 @@ public class AdapayMemberController extends BaseController { public AjaxResult deleteSettleAccount(@RequestBody AdapayMemberInfoDTO dto) { AjaxResult result = null; try { - adapayService.createDeleteSettleAccountRequest(dto.getAdapayMemberId(), dto.getSettleAccountId(), Constants.DEFAULT_APP_ID); + // 新写删除方法 + adapayService.deleteSettleAccount(dto); result = AjaxResult.success(); } catch (Exception e) { logger.error("删除结算账户 error,", e); @@ -217,4 +218,23 @@ public class AdapayMemberController extends BaseController { } return result; } + + + /** + * 在仅删除结算账户后,重新创建新的结算账户 + * 注:使用原 member_id 重新创建结算账户对象,且必须与原身份证和银行卡户名保持一致 + * @param dto + * @return + */ + @PostMapping("createBankAccount") + public AjaxResult createBankAccount(@RequestBody SettleAccountDTO dto) { + AjaxResult result = null; + try { + adapayService.createBankAccount(dto); + } catch (Exception e) { + logger.error("重新创建结算账户 error, ", e); + result = AjaxResult.error(); + } + return result; + } } diff --git a/jsowell-pile/src/main/java/com/jsowell/adapay/service/AdapayService.java b/jsowell-pile/src/main/java/com/jsowell/adapay/service/AdapayService.java index 018f8268a..a612d0662 100644 --- a/jsowell-pile/src/main/java/com/jsowell/adapay/service/AdapayService.java +++ b/jsowell-pile/src/main/java/com/jsowell/adapay/service/AdapayService.java @@ -1517,4 +1517,53 @@ public class AdapayService { return totalSplitAmount; } + + /** + * 创建结算账户 + * @param dto + * @throws BaseAdaPayException + */ + public void createBankAccount(SettleAccountDTO dto) throws BaseAdaPayException { + // 根据运营商id 查出现有的adapayMemberId + String merchantId = dto.getMerchantId(); + // 新写一个查询方法,查询最近一条的记录(因为之前已经删除过数据,使用原查询方法查不到数据) + AdapayMemberAccount adapayMemberAccount = adapayMemberAccountService.selectRecentInfoByMerchantId(merchantId); + if (adapayMemberAccount == null) { + return; + } + String adapayMemberId = adapayMemberAccount.getAdapayMemberId(); + // 查询该商户的wxAppId + String wxAppId = pileMerchantInfoService.queryAppIdByMerchantId(merchantId); + // 创建结算账户请求 + Map settleAccount = this.createSettleAccountRequest(dto, adapayMemberId, wxAppId); + + // 保存结果 + if (settleAccount == null || StringUtils.equals((String) settleAccount.get("status"), "failed")) { + String errorMsg = settleAccount == null ? "创建汇付结算账户失败" : (String) settleAccount.get("error_msg"); + throw new BusinessException("00500001", errorMsg); + } + + String settleAccountId = (String) settleAccount.get("id"); + // 保存到数据库 + adapayMemberAccount = new AdapayMemberAccount(); + adapayMemberAccount.setMerchantId(dto.getMerchantId()); + adapayMemberAccount.setAdapayMemberId(adapayMemberId); + adapayMemberAccount.setSettleAccountId(settleAccountId); + adapayMemberAccount.setStatus(Constants.ONE); + adapayMemberAccountService.insertAdapayMemberAccount(adapayMemberAccount); + } + + /** + * 删除结算账户(先删除汇付的结算账户,再逻辑删除数据库) + * @param dto + * @throws BaseAdaPayException + */ + public void deleteSettleAccount(AdapayMemberInfoDTO dto) throws BaseAdaPayException { + // 查询appId + String wechatAppId = pileMerchantInfoService.queryAppIdByMerchantId(dto.getMerchantId()); + // 1、新建删除请求 2、如果成功,再将数据库中的记录删除 + this.createDeleteSettleAccountRequest(dto.getAdapayMemberId(), dto.getSettleAccountId(), wechatAppId); + // 删除数据库中的记录 + adapayMemberAccountService.deleteAccountByMerchantId(dto.getMerchantId()); + } } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/mapper/AdapayMemberAccountMapper.java b/jsowell-pile/src/main/java/com/jsowell/pile/mapper/AdapayMemberAccountMapper.java index d26e43d2a..287536d67 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/mapper/AdapayMemberAccountMapper.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/mapper/AdapayMemberAccountMapper.java @@ -119,4 +119,17 @@ public interface AdapayMemberAccountMapper { void updateAdapayMemberAccountByMemberId(AdapayMemberAccount adapayMemberAccount); AdapayMemberAccount selectByMemberId(String memberId); + + /** + * 通过运营商id删除账户信息 + * @param merchantId + */ + void deleteAccountByMerchantId(String merchantId); + + /** + * 根据运营商id查询最近一条的信息 + * @param merchantId + * @return + */ + AdapayMemberAccount selectRecentInfoByMerchantId(String merchantId); } \ No newline at end of file diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/AdapayMemberAccountService.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/AdapayMemberAccountService.java index ed756b9ab..19bf9576d 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/AdapayMemberAccountService.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/AdapayMemberAccountService.java @@ -109,4 +109,17 @@ public interface AdapayMemberAccountService { * @return */ String selectMerchantNameByAdapayMemberId(String adapayMemberId); + + /** + * 根据运营商id删除记录 + * @param merchantId + */ + void deleteAccountByMerchantId(String merchantId); + + /** + * 根据运营商Id查询最近一条的信息 + * @param merchantId + * @return + */ + AdapayMemberAccount selectRecentInfoByMerchantId(String merchantId); } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/AdapayMemberAccountServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/AdapayMemberAccountServiceImpl.java index 8f8815aa3..17b51de3a 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/AdapayMemberAccountServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/AdapayMemberAccountServiceImpl.java @@ -259,5 +259,19 @@ public class AdapayMemberAccountServiceImpl implements AdapayMemberAccountServic return pileMerchantInfo.getMerchantName(); } + @Override + public void deleteAccountByMerchantId(String merchantId) { + adapayMemberAccountMapper.deleteAccountByMerchantId(merchantId); + } + + /** + * 根据运营商id查询最近一条的信息 + * @param merchantId + * @return + */ + @Override + public AdapayMemberAccount selectRecentInfoByMerchantId(String merchantId) { + return adapayMemberAccountMapper.selectRecentInfoByMerchantId(merchantId); + } } diff --git a/jsowell-pile/src/main/resources/mapper/pile/AdapayMemberAccountMapper.xml b/jsowell-pile/src/main/resources/mapper/pile/AdapayMemberAccountMapper.xml index 47ef0b5a9..3a6e96999 100644 --- a/jsowell-pile/src/main/resources/mapper/pile/AdapayMemberAccountMapper.xml +++ b/jsowell-pile/src/main/resources/mapper/pile/AdapayMemberAccountMapper.xml @@ -528,4 +528,20 @@ where del_flag = '0' and adapay_member_id = #{memberId,jdbcType=VARCHAR} + + + update + adapay_member_account + set del_flag = '0' + where merchant_id = #{merchantId,jdbcType=VARCHAR} + + + \ No newline at end of file