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..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 @@ -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,42 @@ public class AdapayMemberController extends BaseController { } return result; } + + /** + * 删除结算账户 + * @param dto + * @return + */ + @PostMapping("/deleteSettleAccount") + public AjaxResult deleteSettleAccount(@RequestBody AdapayMemberInfoDTO dto) { + AjaxResult result = null; + try { + // 新写删除方法 + adapayService.deleteSettleAccount(dto); + result = AjaxResult.success(); + } catch (Exception e) { + logger.error("删除结算账户 error,", e); + result = AjaxResult.error(); + } + 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-admin/src/test/java/PaymentTestController.java b/jsowell-admin/src/test/java/PaymentTestController.java index f29d8a03f..59f4815f2 100644 --- a/jsowell-admin/src/test/java/PaymentTestController.java +++ b/jsowell-admin/src/test/java/PaymentTestController.java @@ -211,15 +211,16 @@ public class PaymentTestController { /** * 提现方法 + * */ @Test public void withdraw() { - String merchantId = "349"; + String merchantId = "87"; String orderNo = "drawcash_" + merchantId + "_" + System.currentTimeMillis(); - BigDecimal cashAmt = new BigDecimal("560.17"); - 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 0c4d2dd29..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 @@ -104,6 +104,12 @@ 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, "充电桩退出"), @@ -160,6 +166,8 @@ public enum YKCFrameTypeCode { // 充电桩请求开始充电 START_CHARGING(REQUEST_START_CHARGING_CODE.getCode(), CONFIRM_START_CHARGING_CODE.getCode()), + START_MERGE_CHARGE(PILE_APPLY_MERGE_CHARGE_CODE.getCode(), CONFIRM_MERGE_CHARGE_CODE.getCode()), + // 交易记录 TRANSACTION_RECORDS(TRANSACTION_RECORDS_CODE.getCode(), TRANSACTION_RECORDS_CONFIRM_CODE.getCode()), TRANSACTION_RECORDS_V13(TRANSACTION_RECORDS_OLD_VERSION_CODE.getCode(), TRANSACTION_RECORDS_CONFIRM_CODE.getCode()), @@ -263,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()), 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/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; + } +} 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..fd1e56d9c --- /dev/null +++ b/jsowell-netty/src/main/java/com/jsowell/netty/handler/yunkuaichong/PileApplyMergeChargeHandler.java @@ -0,0 +1,153 @@ +package com.jsowell.netty.handler.yunkuaichong; + +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.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.LinkedHashMap; +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(); + + Map map = new LinkedHashMap<>(); + + String transactionCode = Constants.ILLEGAL_TRANSACTION_CODE; + byte[] authenticationFlagByteArr = Constants.zeroByteArray; // 鉴权成功标识 + byte[] accountBalanceByteArr = Constants.zeroByteArray; // 账户余额 + try { + map = orderBasicInfoService.verifyMergeChargeOrder(dto); + log.info("桩号:{}, 并充订单鉴权成功, 结果map:{}", pileSn, map); + } catch (Exception e) { + log.error("桩号:{}, 并充订单鉴权失败, ", pileSn, e); + } + if (map != null) { + transactionCode = (String) map.get("transactionCode"); + accountBalanceByteArr = YKCUtils.getPriceByte(String.valueOf(map.get("accountBalance")), 2); + authenticationFlagByteArr = Constants.oneByteArray; + } + + // 应答 + // 交易流水号 + // 桩编号 + // 枪号 + // 逻辑卡号 + // 账户余额 + // 鉴权成功标志 + // 失败原因 + // 并充序号 + byte[] defeatReasonByteArr = Constants.zeroByteArray; // 失败原因 + byte[] msgBodyByteArr = Bytes.concat(BytesUtil.str2Bcd(transactionCode), pileSnByteArr, connectorNumByteArr, cardNumByteArr, + accountBalanceByteArr, authenticationFlagByteArr, defeatReasonByteArr, mergeChargeNumberByteArr); + + return getResult(ykcDataProtocol, msgBodyByteArr); + } +} 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; 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/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/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/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/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/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java index 2d4e8c253..89dfdc78d 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 @@ -4558,6 +4558,12 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService { */ @Override public OrderBasicInfo saveOrderForEV(GenerateOrderDTO dto) throws ParseException { + String pileConnectorCode = dto.getPileSn() + dto.getConnectorCode(); + // 先根据枪口号查询是否有未启动的并充订单 + OrderBasicInfo orderBasicInfo = selectNotStartMergeOrder(pileConnectorCode); + if (orderBasicInfo != null) { + return orderBasicInfo; + } String orderCode = generateNewOrderCode(); String transactionCode = dto.getTransactionCode(); if (StringUtils.isBlank(transactionCode)) { @@ -4574,16 +4580,17 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService { String merchantId = pileStationInfo != null ? String.valueOf(pileStationInfo.getMerchantId()) : ""; String plateNumber = dto.getPlateNumber() != null ? dto.getPlateNumber() : ""; // 订单基本信息 - OrderBasicInfo orderBasicInfo = OrderBasicInfo.builder() + orderBasicInfo = OrderBasicInfo.builder() .orderCode(orderCode) .transactionCode(transactionCode) .orderStatus(OrderStatusEnum.NOT_START.getValue()) + .orderType(OrderTypeEnum.NORMAL_ORDER.getValue()) // 订单类型(1-普通订单;2-并充订单) .memberId(dto.getMemberId()) .stationId(stationId) .merchantId(merchantId) .pileSn(dto.getPileSn()) .connectorCode(dto.getConnectorCode()) - .pileConnectorCode(dto.getPileSn() + dto.getConnectorCode()) + .pileConnectorCode(pileConnectorCode) .startMode(dto.getStartMode()) .payStatus(Constants.ZERO) // .payAmount(dto.getChargeAmount()) // 支付完成后填入支付金额 @@ -4594,6 +4601,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()); @@ -4668,6 +4687,19 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService { return orderBasicInfo; } + /** + * 查询未启动的并充订单 + * @param pileConnectorCode + * @return + */ + private OrderBasicInfo selectNotStartMergeOrder(String pileConnectorCode) { + OrderBasicInfo orderBasicInfo = new OrderBasicInfo(); + orderBasicInfo.setOrderType(OrderTypeEnum.MERGE_CHARGE_ORDER.getValue()); + orderBasicInfo.setOrderStatus(OrderStatusEnum.NOT_START.getValue()); + orderBasicInfo.setPileConnectorCode(pileConnectorCode); + return getOrderBasicInfo(orderBasicInfo); + } + /** * 保存电单车订单信息 * @param dto @@ -5158,5 +5190,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/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 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} + +