mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-05-04 18:10:10 +08:00
update 电单车协议
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package com.jsowell.common.enums.ykc;
|
||||
|
||||
import com.jsowell.common.util.BytesUtil;
|
||||
|
||||
/**
|
||||
* 云快充充电停止原因enum
|
||||
*
|
||||
* @author JS-ZZA
|
||||
* @date 2022/11/4 16:46
|
||||
*/
|
||||
public enum EBikeChargingStopReasonEnum {
|
||||
|
||||
FULL_AUTO_STOP(0x01, "充满自停"),
|
||||
TIME_AUTO_STOP(0x02, "达到最大充电时间"),
|
||||
PRESET_TIME_AUTO_STOP(0x03, "达到预设时间"),
|
||||
PRESET_ELECTRICITY_AUTO_STOP(0x04, "达到预设电量"),
|
||||
USER_PULL_OUT(0x05, "用户拔出"),
|
||||
LOAD_TOO_LARGE(0x06, "负载过大"),
|
||||
SERVER_FORCE_STOP(0x07, "服务器控制停止"),
|
||||
DYNAMIC_OVERLOAD(0x08, "动态过载"),
|
||||
POWER_TOO_SMALL(0x09, "功率过小"),
|
||||
ENVIRONMENT_TEMPERATURE_TOO_HIGH(0x0A, "环境温度过高"),
|
||||
PORT_TEMPERATURE_TOO_HIGH(0x0B, "端口温度过高"),
|
||||
OVER_CURRENT(0x0C, "过流"),
|
||||
USER_PULL_OUT_1(0x0D, "用户拔出-1,可能是插座弹片卡住"),
|
||||
NO_CONTACT(0x0E, "无功率停止,可能是接触不良或保险丝烧断故障"),
|
||||
RELAY_BAD(0x0F, "预检-继电器坏或保险丝断"),
|
||||
WATER_INTRUSION(0x10, "水浸断电"),
|
||||
FIRE_SETTLEMENT_LOCAL_PORT(0x11, "灭火结算(本端口)"),
|
||||
FIRE_SETTLEMENT_NON_LOCAL_PORT(0x12, "灭火结算(非本端口)"),
|
||||
USER_PASSWORD_OPEN_DOOR_SHUTDOWN(0x13, "用户密码开柜断电"),
|
||||
NOT_CLOSE_DOOR(0x14, "未关好柜门"),
|
||||
USER_OPERATION_STOP(0x15, "外部操作停止"),
|
||||
SWIPE_OPERATION_STOP(0x16, "刷卡操作停止"),
|
||||
SERVER_FORCE_STOP_2(0x17, "服务器强制停止(主要用于充电柜强制开柜门)"),
|
||||
FIRE_SYSTEM_TRIGGER_STOP(0x18, "消防系统触发停止"),
|
||||
STORAGE_ERROR(0x19, "存储器错误"),
|
||||
OVER_VOLTAGE(0x1A, "过压"),
|
||||
UNDER_VOLTAGE(0x1B, "欠压"),
|
||||
|
||||
;
|
||||
|
||||
private int code;
|
||||
private String msg;
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
EBikeChargingStopReasonEnum(int code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据code获取停止原因描述
|
||||
*
|
||||
* @param code 编码
|
||||
* @return 停止原因描述
|
||||
*/
|
||||
public static String getMsgByCode(int code) {
|
||||
for (EBikeChargingStopReasonEnum item : EBikeChargingStopReasonEnum.values()) {
|
||||
if (item.getCode() == code) {
|
||||
return item.getMsg();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String stopReason = "6B";
|
||||
byte[] stopReasonByteArr = new byte[]{0x6B};
|
||||
String s = BytesUtil.bin2HexStr(stopReasonByteArr);
|
||||
|
||||
int i = Integer.parseInt(stopReason, 16);
|
||||
String stopReasonMsg = EBikeChargingStopReasonEnum.getMsgByCode(i);
|
||||
System.out.println(stopReasonMsg);
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,30 @@ package com.jsowell.netty.handler.electricbicycles;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.jsowell.common.constant.Constants;
|
||||
import com.jsowell.common.core.domain.ebike.EBikeDataProtocol;
|
||||
import com.jsowell.common.core.redis.RedisCache;
|
||||
import com.jsowell.common.enums.ykc.OrderStatusEnum;
|
||||
import com.jsowell.common.util.StringUtils;
|
||||
import com.jsowell.common.util.YKCUtils;
|
||||
import com.jsowell.common.util.id.IdUtils;
|
||||
import com.jsowell.netty.factory.EBikeOperateFactory;
|
||||
import com.jsowell.pile.domain.OrderBasicInfo;
|
||||
import com.jsowell.pile.domain.ebike.AbsEBikeMessage;
|
||||
import com.jsowell.pile.domain.ebike.EBikeCommandEnum;
|
||||
import com.jsowell.pile.domain.ebike.deviceupload.EBikeMessageCmd03;
|
||||
import com.jsowell.pile.service.OrderBasicInfoService;
|
||||
import com.jsowell.pile.service.PersonalChargingRecordService;
|
||||
import com.jsowell.pile.service.PileBasicInfoService;
|
||||
import com.jsowell.pile.service.PileMerchantInfoService;
|
||||
import com.jsowell.pile.service.programlogic.AbstractProgramLogic;
|
||||
import com.jsowell.pile.service.programlogic.ProgramLogicFactory;
|
||||
import com.jsowell.thirdparty.common.CommonService;
|
||||
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.Date;
|
||||
|
||||
/**
|
||||
* 结算消费信息上传
|
||||
*/
|
||||
@@ -21,6 +36,24 @@ public class SettlementUploadHandler extends AbstractEBikeHandler {
|
||||
// private final String type = EBikeCommandEnum.SETTLEMENT_UPLOAD.getCode();
|
||||
private final String type = YKCUtils.frameType2Str(EBikeCommandEnum.SETTLEMENT_UPLOAD.getBytes());
|
||||
|
||||
@Autowired
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Autowired
|
||||
private OrderBasicInfoService orderBasicInfoService;
|
||||
|
||||
@Autowired
|
||||
private PileMerchantInfoService pileMerchantInfoService;
|
||||
|
||||
@Autowired
|
||||
private CommonService commonService;
|
||||
|
||||
@Autowired
|
||||
private PileBasicInfoService pileBasicInfoService;
|
||||
|
||||
@Autowired
|
||||
private PersonalChargingRecordService personalChargingRecordService;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
EBikeOperateFactory.register(type, this);
|
||||
@@ -42,8 +75,64 @@ public class SettlementUploadHandler extends AbstractEBikeHandler {
|
||||
EBikeMessageCmd03.SettlementInfo settlementInfo = message.getSettlementInfo();
|
||||
log.info("结算消费信息上传:{}", JSON.toJSONString(message));
|
||||
|
||||
String transactionCode = settlementInfo.getOrderNumber();
|
||||
// 处理订单加锁/结算电单车订单
|
||||
String lockKey = "settle_order_" + transactionCode;
|
||||
String uuid = IdUtils.fastUUID();
|
||||
try {
|
||||
// redis锁
|
||||
Boolean isLock = redisCache.lock(lockKey, uuid, 1500);
|
||||
if (isLock) {
|
||||
processOrder(message);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理订单transactionCode:{}, 发生异常", transactionCode, e);
|
||||
} finally {
|
||||
if (uuid.equals(redisCache.getCacheObject(lockKey).toString())) {
|
||||
redisCache.unLock(lockKey);
|
||||
}
|
||||
}
|
||||
|
||||
// 返回结果
|
||||
return getResult(dataProtocol, Constants.zeroByteArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* 收到交易记录 处理订单
|
||||
*/
|
||||
private void processOrder(EBikeMessageCmd03 message) {
|
||||
EBikeMessageCmd03.SettlementInfo settlementInfo = message.getSettlementInfo();
|
||||
String transactionCode = settlementInfo.getOrderNumber();
|
||||
// 根据交易流水号查询订单信息
|
||||
OrderBasicInfo orderBasicInfo = orderBasicInfoService.getOrderInfoByTransactionCode(transactionCode);
|
||||
if (orderBasicInfo != null) {
|
||||
// 平台存在订单
|
||||
String stopReason = settlementInfo.getStopReason();
|
||||
// orderBasicInfo.setReason(data.getStopReasonMsg());
|
||||
// 如果订单状态为 异常,则改为 待结算
|
||||
if (StringUtils.equals(OrderStatusEnum.ABNORMAL.getValue(), orderBasicInfo.getOrderStatus())) {
|
||||
orderBasicInfo.setOrderStatus(OrderStatusEnum.STAY_SETTLEMENT.getValue());
|
||||
}
|
||||
|
||||
// 校验结束时间
|
||||
if (orderBasicInfo.getChargeEndTime().before(orderBasicInfo.getChargeStartTime())) {
|
||||
orderBasicInfo.setChargeEndTime(new Date());
|
||||
}
|
||||
|
||||
orderBasicInfoService.updateOrderBasicInfo(orderBasicInfo);
|
||||
|
||||
// 重新查询订单信息
|
||||
orderBasicInfo = orderBasicInfoService.getOrderInfoByTransactionCode(transactionCode);
|
||||
|
||||
// 结算订单操作
|
||||
try {
|
||||
// 新逻辑
|
||||
String mode = pileMerchantInfoService.getDelayModeByMerchantId(orderBasicInfo.getMerchantId());
|
||||
AbstractProgramLogic orderLogic = ProgramLogicFactory.getProgramLogic(mode);
|
||||
orderLogic.settleOrderForEBike(message, orderBasicInfo);
|
||||
} catch (Exception e) {
|
||||
log.error("结算订单发生异常 orderCode:{}", orderBasicInfo.getOrderCode(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,28 +34,28 @@ public class EBikeMessageCmd03 extends AbsEBikeMessage {
|
||||
|
||||
@Data
|
||||
public static class SettlementInfo {
|
||||
private String chargingDuration; // 充电时长, 单位:"秒"
|
||||
private String maxPower; // 最大功率, 单位:"0.1W"
|
||||
private String consumedEnergy; // 耗电量, 单位:"0.01度"
|
||||
private String portNumber; // 端口号
|
||||
private String startMode; // 在线/离线启动/验证码
|
||||
private String cardNumberOrVerificationCode; // 卡号/验证码
|
||||
private String stopReason; // 停止原因
|
||||
private String orderNumber; // 订单编号
|
||||
private String secondMaxPower; // 第二最大功率
|
||||
private int chargingDuration; // 充电时长, 单位:"秒"
|
||||
private int maxPower; // 最大功率, 单位:"0.1W"
|
||||
private int consumedEnergy; // 耗电量, 单位:"0.01度"
|
||||
private int portNumber; // 端口号
|
||||
private int startMode; // 在线/离线启动/验证码
|
||||
private int cardNumberOrVerificationCode; // 卡号/验证码
|
||||
private int stopReason; // 停止原因
|
||||
private int orderNumber; // 订单编号
|
||||
private int secondMaxPower; // 第二最大功率
|
||||
// private String timestamp; // 时间戳 上发指令当时的时间,有时候不准确,该字段属于调试使用,服务器无需关心此字段
|
||||
// private String placeholderDuration; // 占位时长 充电柜专用,其他设备忽略此字段 表示充满后占用设备的时长,单位为分钟
|
||||
|
||||
public SettlementInfo(byte[] dataBytes) {
|
||||
this.chargingDuration = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 0, 2)) + "";
|
||||
this.maxPower = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 2, 4)) + "";
|
||||
this.consumedEnergy = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 4, 6)) + "";
|
||||
this.portNumber = BytesUtil.bcd2StrLittle(new byte[]{dataBytes[6]});
|
||||
this.startMode = BytesUtil.bcd2StrLittle(new byte[]{dataBytes[7]});
|
||||
this.cardNumberOrVerificationCode = BytesUtil.bcd2StrLittle(Arrays.copyOfRange(dataBytes, 8, 12));
|
||||
this.stopReason = BytesUtil.bcd2StrLittle(new byte[]{dataBytes[12]});
|
||||
this.orderNumber = BytesUtil.bcd2StrLittle(Arrays.copyOfRange(dataBytes, 13, 29));
|
||||
this.secondMaxPower = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 29, 31)) + "";
|
||||
this.chargingDuration = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 0, 2));
|
||||
this.maxPower = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 2, 4));
|
||||
this.consumedEnergy = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 4, 6));
|
||||
this.portNumber = BytesUtil.bytesToIntLittle(new byte[]{dataBytes[6]});
|
||||
this.startMode = BytesUtil.bytesToIntLittle(new byte[]{dataBytes[7]});
|
||||
this.cardNumberOrVerificationCode = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 8, 12));
|
||||
this.stopReason = BytesUtil.bytesToIntLittle(new byte[]{dataBytes[12]});
|
||||
this.orderNumber = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 13, 29));
|
||||
this.secondMaxPower = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 29, 31));
|
||||
// this.timestamp = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 31, 35)) + "";
|
||||
// this.placeholderDuration = BytesUtil.bytesToIntLittle(Arrays.copyOfRange(dataBytes, 35, 37)) + "";
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.jsowell.common.enums.ykc.*;
|
||||
import com.jsowell.common.util.DateUtils;
|
||||
import com.jsowell.common.util.StringUtils;
|
||||
import com.jsowell.pile.domain.*;
|
||||
import com.jsowell.pile.domain.ebike.deviceupload.EBikeMessageCmd03;
|
||||
import com.jsowell.pile.dto.*;
|
||||
import com.jsowell.pile.service.*;
|
||||
import com.jsowell.pile.transaction.service.TransactionService;
|
||||
@@ -141,6 +142,13 @@ public abstract class AbstractProgramLogic implements InitializingBean {
|
||||
*/
|
||||
public abstract void settleOrder(TransactionRecordsData data, OrderBasicInfo orderBasicInfo);
|
||||
|
||||
/**
|
||||
* 电单车结算逻辑
|
||||
* @param message
|
||||
* @param orderBasicInfo
|
||||
*/
|
||||
public abstract void settleOrderForEBike(EBikeMessageCmd03 message, OrderBasicInfo orderBasicInfo);
|
||||
|
||||
/**
|
||||
* 第三方平台结算订单(目前给华为用)
|
||||
*
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.jsowell.common.util.DateUtils;
|
||||
import com.jsowell.common.util.StringUtils;
|
||||
import com.jsowell.common.util.id.SnowflakeIdWorker;
|
||||
import com.jsowell.pile.domain.*;
|
||||
import com.jsowell.pile.domain.ebike.deviceupload.EBikeMessageCmd03;
|
||||
import com.jsowell.pile.dto.*;
|
||||
import com.jsowell.pile.transaction.dto.OrderTransactionDTO;
|
||||
import com.jsowell.pile.vo.uniapp.customer.MemberVO;
|
||||
@@ -470,6 +471,11 @@ public class DelayMerchantProgramLogic extends AbstractProgramLogic {
|
||||
orderBasicInfo.getOrderCode(), orderBasicInfo.getTransactionCode(), JSON.toJSONString(dto));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settleOrderForEBike(EBikeMessageCmd03 message, OrderBasicInfo orderBasicInfo) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三方平台结算订单(目前给华为用)
|
||||
* @param data
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.jsowell.common.util.DateUtils;
|
||||
import com.jsowell.common.util.StringUtils;
|
||||
import com.jsowell.common.util.id.SnowflakeIdWorker;
|
||||
import com.jsowell.pile.domain.*;
|
||||
import com.jsowell.pile.domain.ebike.deviceupload.EBikeMessageCmd03;
|
||||
import com.jsowell.pile.dto.*;
|
||||
import com.jsowell.pile.transaction.dto.OrderTransactionDTO;
|
||||
import com.jsowell.pile.vo.uniapp.customer.MemberVO;
|
||||
@@ -417,6 +418,11 @@ public class NotDelayMerchantProgramLogic extends AbstractProgramLogic {
|
||||
logger.info("结算订单end:{} OrderTransactionDTO:{}", orderBasicInfo.getOrderCode(), JSON.toJSONString(dto));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void settleOrderForEBike(EBikeMessageCmd03 message, OrderBasicInfo orderBasicInfo) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三方平台结算订单(目前给华为用)
|
||||
* @param data
|
||||
|
||||
Reference in New Issue
Block a user