mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-07-04 14:08:01 +08:00
bugfix 羽信预约充电独立逻辑
补齐 0xB2 协议字段,新增羽信预约 DTO、service 和接口。 羽信预约改为先确认桩端成功再落库,取消/删除前先取消桩端预约。 原预约逻辑不再兼容羽信主板,保持旧链路独立。
This commit is contained in:
@@ -17,6 +17,7 @@ import com.jsowell.pile.service.PileBasicInfoService;
|
|||||||
import com.jsowell.pile.service.PileFirmwareInfoService;
|
import com.jsowell.pile.service.PileFirmwareInfoService;
|
||||||
import com.jsowell.pile.service.PileMerchantInfoService;
|
import com.jsowell.pile.service.PileMerchantInfoService;
|
||||||
import com.jsowell.pile.service.PileReservationInfoService;
|
import com.jsowell.pile.service.PileReservationInfoService;
|
||||||
|
import com.jsowell.pile.service.YuxinReservationChargingService;
|
||||||
import com.jsowell.pile.vo.PileReservationInfoVO;
|
import com.jsowell.pile.vo.PileReservationInfoVO;
|
||||||
import com.jsowell.pile.vo.uniapp.customer.PersonPileConnectorSumInfoVO;
|
import com.jsowell.pile.vo.uniapp.customer.PersonPileConnectorSumInfoVO;
|
||||||
import com.jsowell.pile.vo.uniapp.customer.PersonPileRealTimeVO;
|
import com.jsowell.pile.vo.uniapp.customer.PersonPileRealTimeVO;
|
||||||
@@ -55,6 +56,9 @@ public class PersonPileController extends BaseController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private PileReservationInfoService pileReservationInfoService;
|
private PileReservationInfoService pileReservationInfoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private YuxinReservationChargingService yuxinReservationChargingService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PileFirmwareInfoService pileFirmwareInfoService;
|
private PileFirmwareInfoService pileFirmwareInfoService;
|
||||||
|
|
||||||
@@ -508,6 +512,125 @@ public class PersonPileController extends BaseController {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 羽信主板添加预约充电
|
||||||
|
* http://localhost:8080/uniapp/personalPile/yuxin/createReserved
|
||||||
|
*/
|
||||||
|
@PostMapping("/yuxin/createReserved")
|
||||||
|
public RestApiResponse<?> createYuxinReserved(HttpServletRequest request, @RequestBody YuxinReservationChargingDTO dto) {
|
||||||
|
RestApiResponse<?> response = null;
|
||||||
|
try {
|
||||||
|
String memberId = getMemberIdByAuthorization(request);
|
||||||
|
dto.setMemberId(memberId);
|
||||||
|
int reservedId = yuxinReservationChargingService.createReservation(dto);
|
||||||
|
response = new RestApiResponse<>(ImmutableMap.of("reservedId", reservedId));
|
||||||
|
} catch (BusinessException e) {
|
||||||
|
logger.error("羽信添加预约充电error, params:{}", dto, e);
|
||||||
|
response = new RestApiResponse<>(e.getCode(), e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("羽信添加预约充电error, params:{}", dto, e);
|
||||||
|
response = new RestApiResponse<>(ReturnCodeEnum.CODE_CREATE_RESERVED_ERROR);
|
||||||
|
}
|
||||||
|
logger.info("羽信添加预约充电params:{}, result:{}", dto, response);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 羽信主板修改预约充电
|
||||||
|
* http://localhost:8080/uniapp/personalPile/yuxin/updateReservation
|
||||||
|
*/
|
||||||
|
@PostMapping("/yuxin/updateReservation")
|
||||||
|
public RestApiResponse<?> updateYuxinReservation(HttpServletRequest request, @RequestBody YuxinReservationChargingDTO dto) {
|
||||||
|
RestApiResponse<?> response = null;
|
||||||
|
try {
|
||||||
|
String memberId = getMemberIdByAuthorization(request);
|
||||||
|
dto.setMemberId(memberId);
|
||||||
|
int i = yuxinReservationChargingService.updateReservation(dto);
|
||||||
|
if (i > 0) {
|
||||||
|
response = new RestApiResponse<>();
|
||||||
|
} else {
|
||||||
|
response = new RestApiResponse<>(ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_ERROR.getValue(), ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_ERROR.getLabel() + ": 充电桩返回修改失败");
|
||||||
|
}
|
||||||
|
} catch (BusinessException e) {
|
||||||
|
logger.error("羽信修改预约充电error, params:{}", dto, e);
|
||||||
|
response = new RestApiResponse<>(e.getCode(), e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("羽信修改预约充电error, params:{}", dto, e);
|
||||||
|
response = new RestApiResponse<>(ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
logger.info("羽信修改预约充电params:{}, result:{}", dto, response);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 羽信主板取消预约充电
|
||||||
|
* http://localhost:8080/uniapp/personalPile/yuxin/cancelReservation
|
||||||
|
*/
|
||||||
|
@PostMapping("/yuxin/cancelReservation")
|
||||||
|
public RestApiResponse<?> cancelYuxinReservation(HttpServletRequest request, @RequestBody YuxinReservationChargingDTO dto) {
|
||||||
|
RestApiResponse<?> response = null;
|
||||||
|
try {
|
||||||
|
String memberId = getMemberIdByAuthorization(request);
|
||||||
|
dto.setMemberId(memberId);
|
||||||
|
yuxinReservationChargingService.cancelReservation(dto);
|
||||||
|
response = new RestApiResponse<>();
|
||||||
|
} catch (BusinessException e) {
|
||||||
|
logger.error("羽信取消预约充电error, params:{}", dto, e);
|
||||||
|
response = new RestApiResponse<>(e.getCode(), e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("羽信取消预约充电error, params:{}", dto, e);
|
||||||
|
response = new RestApiResponse<>(ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
logger.info("羽信取消预约充电params:{}, result:{}", dto, response);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 羽信主板删除预约
|
||||||
|
* http://localhost:8080/uniapp/personalPile/yuxin/deleteReservation
|
||||||
|
*/
|
||||||
|
@PostMapping("/yuxin/deleteReservation")
|
||||||
|
public RestApiResponse<?> deleteYuxinReservation(HttpServletRequest request, @RequestBody YuxinReservationChargingDTO dto) {
|
||||||
|
RestApiResponse<?> response = null;
|
||||||
|
try {
|
||||||
|
String memberId = getMemberIdByAuthorization(request);
|
||||||
|
dto.setMemberId(memberId);
|
||||||
|
yuxinReservationChargingService.deleteReservation(dto);
|
||||||
|
response = new RestApiResponse<>();
|
||||||
|
} catch (BusinessException e) {
|
||||||
|
logger.error("羽信删除预约error, params:{}", dto, e);
|
||||||
|
response = new RestApiResponse<>(e.getCode(), e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("羽信删除预约error, params:{}", dto, e);
|
||||||
|
response = new RestApiResponse<>(ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
logger.info("羽信删除预约params:{}, result:{}", dto, response);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 羽信主板查询预约信息
|
||||||
|
* http://localhost:8080/uniapp/personalPile/yuxin/queryReservationInfo
|
||||||
|
*/
|
||||||
|
@PostMapping("/yuxin/queryReservationInfo")
|
||||||
|
public RestApiResponse<?> queryYuxinReservationInfo(HttpServletRequest request, @RequestBody YuxinReservationChargingDTO dto) {
|
||||||
|
RestApiResponse<?> response = null;
|
||||||
|
try {
|
||||||
|
String memberId = getMemberIdByAuthorization(request);
|
||||||
|
dto.setMemberId(memberId);
|
||||||
|
PileReservationInfoVO vo = yuxinReservationChargingService.queryReservationInfo(dto);
|
||||||
|
response = new RestApiResponse<>(vo);
|
||||||
|
} catch (BusinessException e) {
|
||||||
|
logger.error("羽信查询预约状态error, params:{}", dto, e);
|
||||||
|
response = new RestApiResponse<>(e.getCode(), e.getMessage());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("羽信查询预约状态error, params:{}", dto, e);
|
||||||
|
response = new RestApiResponse<>(ReturnCodeEnum.CODE_QUERY_RESERVATION_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
logger.info("羽信查询预约状态params:{}, result:{}", dto, JSON.toJSONString(response));
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存蓝牙充电记录
|
* 保存蓝牙充电记录
|
||||||
* http://localhost:8080/uniapp/personalPile/saveBluetoothChargingRecord
|
* http://localhost:8080/uniapp/personalPile/saveBluetoothChargingRecord
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package com.jsowell.pile.domain.ykcCommond;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 羽信预约充电0xB2指令
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class YuxinReservationChargingCommand {
|
||||||
|
/**
|
||||||
|
* 交易流水号
|
||||||
|
*/
|
||||||
|
private String transactionCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充电桩编号
|
||||||
|
*/
|
||||||
|
private String pileSn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 枪号: 0-所有枪, 1-1号枪
|
||||||
|
*/
|
||||||
|
private String connectorCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 账户余额, 单位元, 保留2位小数
|
||||||
|
*/
|
||||||
|
private BigDecimal accountBalance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预约类型: 00-立即预约; 01-取消预约
|
||||||
|
*/
|
||||||
|
private String reservationType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充电策略: 0-充满为止; 1-时间控制; 2-金额控制; 3-电量控制
|
||||||
|
*/
|
||||||
|
private Integer chargingStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充电参数, 根据充电策略表示电量/时间/金额
|
||||||
|
*/
|
||||||
|
private BigDecimal chargingParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统当前时间, CP56Time2a格式
|
||||||
|
*/
|
||||||
|
private Date systemTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预约/定时启动时间, CP56Time2a格式
|
||||||
|
*/
|
||||||
|
private Date reservedStartTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预约超时时间, 单位分钟
|
||||||
|
*/
|
||||||
|
private Integer reservationTimeout;
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package com.jsowell.pile.dto;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 羽信预约充电业务入参
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class YuxinReservationChargingDTO {
|
||||||
|
/**
|
||||||
|
* 会员id
|
||||||
|
*/
|
||||||
|
private String memberId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预约id
|
||||||
|
*/
|
||||||
|
private String reservedId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充电桩编号
|
||||||
|
*/
|
||||||
|
private String pileSn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充电桩枪口编号
|
||||||
|
*/
|
||||||
|
private String pileConnectorCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间 hh:mm:ss
|
||||||
|
*/
|
||||||
|
private String startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束时间 hh:mm:ss
|
||||||
|
*/
|
||||||
|
private String endTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充电策略: 0-充满为止; 1-时间控制; 2-金额控制; 3-电量控制
|
||||||
|
*/
|
||||||
|
private Integer chargingStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 充电参数, 默认0
|
||||||
|
*/
|
||||||
|
private BigDecimal chargingParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预约超时时间, 单位分钟; 不传则按开始/结束时间计算
|
||||||
|
*/
|
||||||
|
private Integer reservationTimeout;
|
||||||
|
|
||||||
|
private Integer pageNo;
|
||||||
|
|
||||||
|
private Integer pageSize;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this, ToStringStyle.JSON_STYLE)
|
||||||
|
.append("memberId", memberId)
|
||||||
|
.append("reservedId", reservedId)
|
||||||
|
.append("pileSn", pileSn)
|
||||||
|
.append("pileConnectorCode", pileConnectorCode)
|
||||||
|
.append("startTime", startTime)
|
||||||
|
.append("endTime", endTime)
|
||||||
|
.append("chargingStrategy", chargingStrategy)
|
||||||
|
.append("chargingParam", chargingParam)
|
||||||
|
.append("reservationTimeout", reservationTimeout)
|
||||||
|
.append("pageNo", pageNo)
|
||||||
|
.append("pageSize", pageSize)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -514,8 +514,21 @@ public class PileRemoteService {
|
|||||||
* @return result: 1-成功; 0-失败
|
* @return result: 1-成功; 0-失败
|
||||||
*/
|
*/
|
||||||
public String reservationCharging(ReservationChargingCommand command) {
|
public String reservationCharging(ReservationChargingCommand command) {
|
||||||
String result = "0";
|
|
||||||
byte[] bytes = ykcPushCommandService.pushReservationChargingCommand(command);
|
byte[] bytes = ykcPushCommandService.pushReservationChargingCommand(command);
|
||||||
|
return parseReservationChargingResponse(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 羽信预约充电指令
|
||||||
|
* @return result: 1-成功; 0-失败
|
||||||
|
*/
|
||||||
|
public String yuxinReservationCharging(YuxinReservationChargingCommand command) {
|
||||||
|
byte[] bytes = ykcPushCommandService.pushYuxinReservationChargingCommand(command);
|
||||||
|
return parseReservationChargingResponse(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String parseReservationChargingResponse(byte[] bytes) {
|
||||||
|
String result = "0";
|
||||||
// 解析结果
|
// 解析结果
|
||||||
if (Objects.isNull(bytes)) {
|
if (Objects.isNull(bytes)) {
|
||||||
result = "0";
|
result = "0";
|
||||||
|
|||||||
@@ -86,6 +86,11 @@ public interface YKCPushCommandService {
|
|||||||
*/
|
*/
|
||||||
byte[] pushReservationChargingCommand(ReservationChargingCommand command);
|
byte[] pushReservationChargingCommand(ReservationChargingCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送羽信预约充电命令
|
||||||
|
*/
|
||||||
|
byte[] pushYuxinReservationChargingCommand(YuxinReservationChargingCommand command);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送并充充电指令
|
* 发送并充充电指令
|
||||||
* @param command
|
* @param command
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.jsowell.pile.service;
|
||||||
|
|
||||||
|
import com.jsowell.pile.dto.YuxinReservationChargingDTO;
|
||||||
|
import com.jsowell.pile.vo.PileReservationInfoVO;
|
||||||
|
|
||||||
|
public interface YuxinReservationChargingService {
|
||||||
|
|
||||||
|
int createReservation(YuxinReservationChargingDTO dto);
|
||||||
|
|
||||||
|
int updateReservation(YuxinReservationChargingDTO dto);
|
||||||
|
|
||||||
|
void cancelReservation(YuxinReservationChargingDTO dto);
|
||||||
|
|
||||||
|
void deleteReservation(YuxinReservationChargingDTO dto);
|
||||||
|
|
||||||
|
PileReservationInfoVO queryReservationInfo(YuxinReservationChargingDTO dto);
|
||||||
|
}
|
||||||
@@ -9,14 +9,11 @@ import com.jsowell.common.constant.Constants;
|
|||||||
import com.jsowell.common.core.page.PageResponse;
|
import com.jsowell.common.core.page.PageResponse;
|
||||||
import com.jsowell.common.core.redis.RedisCache;
|
import com.jsowell.common.core.redis.RedisCache;
|
||||||
import com.jsowell.common.enums.DelFlagEnum;
|
import com.jsowell.common.enums.DelFlagEnum;
|
||||||
import com.jsowell.common.enums.ykc.PileMainboardManufacturerEnum;
|
|
||||||
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
|
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
|
||||||
import com.jsowell.common.exception.BusinessException;
|
import com.jsowell.common.exception.BusinessException;
|
||||||
import com.jsowell.common.util.DateUtils;
|
import com.jsowell.common.util.DateUtils;
|
||||||
import com.jsowell.common.util.PileProgramVersionUtils;
|
|
||||||
import com.jsowell.common.util.StringUtils;
|
import com.jsowell.common.util.StringUtils;
|
||||||
import com.jsowell.common.util.YKCUtils;
|
import com.jsowell.common.util.YKCUtils;
|
||||||
import com.jsowell.pile.domain.PileBasicInfo;
|
|
||||||
import com.jsowell.pile.domain.PileMemberRelation;
|
import com.jsowell.pile.domain.PileMemberRelation;
|
||||||
import com.jsowell.pile.domain.PileReservationInfo;
|
import com.jsowell.pile.domain.PileReservationInfo;
|
||||||
import com.jsowell.pile.domain.ykcCommond.ReservationChargingCommand;
|
import com.jsowell.pile.domain.ykcCommond.ReservationChargingCommand;
|
||||||
@@ -312,8 +309,7 @@ public class PileReservationInfoServiceImpl implements PileReservationInfoServic
|
|||||||
@Override
|
@Override
|
||||||
public int createReservation(CreateReservedDTO dto) {
|
public int createReservation(CreateReservedDTO dto) {
|
||||||
PileReservationInfo reservedInfo = selectByPileConnectorCode(dto.getPileConnectorCode());
|
PileReservationInfo reservedInfo = selectByPileConnectorCode(dto.getPileConnectorCode());
|
||||||
PileReservationInfo oldReservationInfo = reservedInfo == null ? null : copyReservationInfo(reservedInfo);
|
boolean activeBeforeUpdate = reservedInfo != null && StringUtils.equals(reservedInfo.getStatus(), Constants.ONE);
|
||||||
boolean activeBeforeUpdate = oldReservationInfo != null && StringUtils.equals(oldReservationInfo.getStatus(), Constants.ONE);
|
|
||||||
if (reservedInfo == null) {
|
if (reservedInfo == null) {
|
||||||
reservedInfo = new PileReservationInfo();
|
reservedInfo = new PileReservationInfo();
|
||||||
reservedInfo.setCreateBy(dto.getMemberId());
|
reservedInfo.setCreateBy(dto.getMemberId());
|
||||||
@@ -348,17 +344,7 @@ public class PileReservationInfoServiceImpl implements PileReservationInfoServic
|
|||||||
reservedInfo.getStartTime(), reservedInfo.getEndTime(), reservedInfo.getId())) {
|
reservedInfo.getStartTime(), reservedInfo.getEndTime(), reservedInfo.getId())) {
|
||||||
throw new BusinessException(ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_REFUSED);
|
throw new BusinessException(ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_REFUSED);
|
||||||
}
|
}
|
||||||
boolean yuxinMainboard = activeBeforeUpdate && isYuxinMainboard(reservedInfo.getPileSn());
|
sendReservationCommandAndAssertSuccess(reservedInfo, dto.getMemberId(), activeBeforeUpdate ? "03" : "01");
|
||||||
log.info("创建/覆盖预约充电下发决策, memberId:{}, activeBeforeUpdate:{}, yuxinMainboard:{}, oldReservation:{}, newReservation:{}",
|
|
||||||
dto.getMemberId(), activeBeforeUpdate, yuxinMainboard,
|
|
||||||
reservationLogText(oldReservationInfo), reservationLogText(reservedInfo));
|
|
||||||
if (activeBeforeUpdate && yuxinMainboard) {
|
|
||||||
if (!replaceYuxinReservation(dto.getMemberId(), oldReservationInfo, reservedInfo)) {
|
|
||||||
throwReservationCommandFailed();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sendReservationCommandAndAssertSuccess(reservedInfo, dto.getMemberId(), activeBeforeUpdate ? "03" : "01");
|
|
||||||
}
|
|
||||||
this.insertOrUpdateSelective(reservedInfo);
|
this.insertOrUpdateSelective(reservedInfo);
|
||||||
return reservedInfo.getId();
|
return reservedInfo.getId();
|
||||||
}
|
}
|
||||||
@@ -419,7 +405,6 @@ public class PileReservationInfoServiceImpl implements PileReservationInfoServic
|
|||||||
if (pileReservationInfo == null) {
|
if (pileReservationInfo == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
PileReservationInfo oldReservationInfo = copyReservationInfo(pileReservationInfo);
|
|
||||||
|
|
||||||
String redisKey = CacheConstants.UPDATE_RESERVATION_INFO + pileReservationInfo.getPileConnectorCode();
|
String redisKey = CacheConstants.UPDATE_RESERVATION_INFO + pileReservationInfo.getPileConnectorCode();
|
||||||
|
|
||||||
@@ -471,17 +456,11 @@ public class PileReservationInfoServiceImpl implements PileReservationInfoServic
|
|||||||
发送指令
|
发送指令
|
||||||
*/
|
*/
|
||||||
if (sendFlag) {
|
if (sendFlag) {
|
||||||
boolean yuxinMainboard = isYuxinMainboard(pileReservationInfo.getPileSn());
|
log.info("修改预约充电下发决策, reservedId:{}, memberId:{}, operation:{}, sendFlag:{}, modifyReservationSetting:{}, pileSn:{}, pileConnectorCode:{}, status:{}, startTime:{}, endTime:{}",
|
||||||
boolean replaceYuxinReservation = shouldReplaceYuxinReservation(operation, modifyReservationSetting, oldReservationInfo, yuxinMainboard);
|
|
||||||
log.info("修改预约充电下发决策, reservedId:{}, memberId:{}, operation:{}, sendFlag:{}, modifyReservationSetting:{}, yuxinMainboard:{}, replaceYuxinReservation:{}, oldReservation:{}, newReservation:{}",
|
|
||||||
pileReservationInfo.getId(), dto.getMemberId(), operation, sendFlag, modifyReservationSetting,
|
pileReservationInfo.getId(), dto.getMemberId(), operation, sendFlag, modifyReservationSetting,
|
||||||
yuxinMainboard, replaceYuxinReservation,
|
pileReservationInfo.getPileSn(), pileReservationInfo.getPileConnectorCode(), pileReservationInfo.getStatus(),
|
||||||
reservationLogText(oldReservationInfo), reservationLogText(pileReservationInfo));
|
pileReservationInfo.getStartTime(), pileReservationInfo.getEndTime());
|
||||||
if (replaceYuxinReservation) {
|
sendResult = sendReservationCommand(pileReservationInfo, dto.getMemberId(), operation);
|
||||||
sendResult = replaceYuxinReservation(dto.getMemberId(), oldReservationInfo, pileReservationInfo);
|
|
||||||
} else {
|
|
||||||
sendResult = sendReservationCommand(pileReservationInfo, dto.getMemberId(), operation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置缓存1分钟, 如果更新数据库就删掉, 如果没有更新数据量缓存70秒
|
// 设置缓存1分钟, 如果更新数据库就删掉, 如果没有更新数据量缓存70秒
|
||||||
redisCache.setCacheObject(redisKey, JSON.toJSONString(pileReservationInfo), CacheConstants.cache_expire_time_70s);
|
redisCache.setCacheObject(redisKey, JSON.toJSONString(pileReservationInfo), CacheConstants.cache_expire_time_70s);
|
||||||
@@ -497,123 +476,6 @@ public class PileReservationInfoServiceImpl implements PileReservationInfoServic
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldReplaceYuxinReservation(String operation, boolean modifyReservationSetting,
|
|
||||||
PileReservationInfo oldReservationInfo, boolean yuxinMainboard) {
|
|
||||||
if (!modifyReservationSetting || !yuxinMainboard) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (StringUtils.equals(operation, "03")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return StringUtils.equals(operation, "01")
|
|
||||||
&& oldReservationInfo != null
|
|
||||||
&& StringUtils.equals(oldReservationInfo.getStatus(), Constants.ONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean replaceYuxinReservation(String memberId, PileReservationInfo oldReservationInfo, PileReservationInfo newReservationInfo) {
|
|
||||||
if (oldReservationInfo == null) {
|
|
||||||
log.error("羽信预约替换失败, 旧预约为空, memberId:{}, newReservation:{}", memberId, reservationLogText(newReservationInfo));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
log.info("羽信预约替换开始, memberId:{}, oldReservation:{}, newReservation:{}",
|
|
||||||
memberId, reservationLogText(oldReservationInfo), reservationLogText(newReservationInfo));
|
|
||||||
boolean cancelOldResult = sendReservationCommand(oldReservationInfo, memberId, "02");
|
|
||||||
log.info("羽信预约替换取消旧预约结果, reservedId:{}, pileConnectorCode:{}, result:{}",
|
|
||||||
oldReservationInfo.getId(), oldReservationInfo.getPileConnectorCode(), cancelOldResult);
|
|
||||||
if (!cancelOldResult) {
|
|
||||||
boolean oldReservationEnded = isReservationTimeEnded(oldReservationInfo);
|
|
||||||
if (!oldReservationEnded) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
log.warn("羽信预约替换取消旧预约失败, 但旧预约时间窗已过期, 继续下发新预约, memberId:{}, oldReservation:{}",
|
|
||||||
memberId, reservationLogText(oldReservationInfo));
|
|
||||||
}
|
|
||||||
boolean createNewResult = sendReservationCommand(newReservationInfo, memberId, "01");
|
|
||||||
log.info("羽信预约替换新预约结果, reservedId:{}, pileConnectorCode:{}, result:{}",
|
|
||||||
newReservationInfo.getId(), newReservationInfo.getPileConnectorCode(), createNewResult);
|
|
||||||
if (createNewResult) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!cancelOldResult) {
|
|
||||||
log.error("羽信预约替换新预约失败, 旧预约取消失败但已判定过期, 不恢复旧预约, memberId:{}, oldReservation:{}, newReservation:{}",
|
|
||||||
memberId, reservationLogText(oldReservationInfo), reservationLogText(newReservationInfo));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
boolean restoreOldResult = sendReservationCommand(oldReservationInfo, memberId, "01");
|
|
||||||
log.info("羽信预约替换恢复旧预约结果, reservedId:{}, pileConnectorCode:{}, result:{}",
|
|
||||||
oldReservationInfo.getId(), oldReservationInfo.getPileConnectorCode(), restoreOldResult);
|
|
||||||
if (!restoreOldResult) {
|
|
||||||
log.error("羽信主板修改预约失败后恢复旧预约失败, reservedId:{}, pileConnectorCode:{}",
|
|
||||||
oldReservationInfo.getId(), oldReservationInfo.getPileConnectorCode());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("羽信主板修改预约失败后恢复旧预约异常, reservedId:{}, pileConnectorCode:{}",
|
|
||||||
oldReservationInfo.getId(), oldReservationInfo.getPileConnectorCode(), e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isReservationTimeEnded(PileReservationInfo reservationInfo) {
|
|
||||||
if (reservationInfo == null || reservationInfo.getStartTime() == null || reservationInfo.getEndTime() == null) {
|
|
||||||
log.warn("羽信旧预约过期判断失败, 预约时间为空, reservation:{}", reservationLogText(reservationInfo));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LocalTime now = LocalTime.now();
|
|
||||||
LocalTime startTime = reservationInfo.getStartTime().toLocalTime();
|
|
||||||
LocalTime endTime = reservationInfo.getEndTime().toLocalTime();
|
|
||||||
boolean crossDay = endTime.isBefore(startTime);
|
|
||||||
boolean ended = !crossDay && !endTime.isAfter(now);
|
|
||||||
log.info("羽信旧预约过期判断, reservedId:{}, pileConnectorCode:{}, now:{}, startTime:{}, endTime:{}, crossDay:{}, ended:{}",
|
|
||||||
reservationInfo.getId(), reservationInfo.getPileConnectorCode(), now, startTime, endTime, crossDay, ended);
|
|
||||||
return ended;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isYuxinMainboard(String pileSn) {
|
|
||||||
try {
|
|
||||||
PileBasicInfo pileBasicInfo = pileBasicInfoService.selectPileBasicInfoBySN(pileSn);
|
|
||||||
String programVersion = pileBasicInfo == null ? null : pileBasicInfo.getProgramVersion();
|
|
||||||
PileMainboardManufacturerEnum manufacturer = PileProgramVersionUtils.getMainboardManufacturer(programVersion);
|
|
||||||
boolean yuxinMainboard = manufacturer == PileMainboardManufacturerEnum.YUXIN;
|
|
||||||
log.info("预约充电主板识别, pileSn:{}, programVersion:{}, manufacturer:{}, yuxinMainboard:{}",
|
|
||||||
pileSn, programVersion, manufacturer.getValue(), yuxinMainboard);
|
|
||||||
return yuxinMainboard;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("判断羽信主板失败, pileSn:{}", pileSn, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String reservationLogText(PileReservationInfo reservationInfo) {
|
|
||||||
if (reservationInfo == null) {
|
|
||||||
return "null";
|
|
||||||
}
|
|
||||||
return String.format("reservedId=%s,pileSn=%s,pileConnectorCode=%s,status=%s,reservationType=%s,verifyIdentity=%s,startTime=%s,endTime=%s",
|
|
||||||
reservationInfo.getId(), reservationInfo.getPileSn(), reservationInfo.getPileConnectorCode(),
|
|
||||||
reservationInfo.getStatus(), reservationInfo.getReservationType(), reservationInfo.getVerifyIdentity(),
|
|
||||||
reservationInfo.getStartTime(), reservationInfo.getEndTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
private PileReservationInfo copyReservationInfo(PileReservationInfo source) {
|
|
||||||
PileReservationInfo target = new PileReservationInfo();
|
|
||||||
target.setId(source.getId());
|
|
||||||
target.setMemberId(source.getMemberId());
|
|
||||||
target.setPileSn(source.getPileSn());
|
|
||||||
target.setPileConnectorCode(source.getPileConnectorCode());
|
|
||||||
target.setStatus(source.getStatus());
|
|
||||||
target.setReservationType(source.getReservationType());
|
|
||||||
target.setVerifyIdentity(source.getVerifyIdentity());
|
|
||||||
target.setStartTime(source.getStartTime());
|
|
||||||
target.setEndTime(source.getEndTime());
|
|
||||||
target.setFreq(source.getFreq());
|
|
||||||
target.setCreateBy(source.getCreateBy());
|
|
||||||
target.setCreateTime(source.getCreateTime());
|
|
||||||
target.setUpdateBy(source.getUpdateBy());
|
|
||||||
target.setUpdateTime(source.getUpdateTime());
|
|
||||||
target.setDelFlag(source.getDelFlag());
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 个人桩停止充电
|
* 个人桩停止充电
|
||||||
* @param dto
|
* @param dto
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import com.google.common.primitives.Bytes;
|
|||||||
import com.jsowell.common.constant.Constants;
|
import com.jsowell.common.constant.Constants;
|
||||||
import com.jsowell.common.core.domain.ykc.YKCFrameTypeCode;
|
import com.jsowell.common.core.domain.ykc.YKCFrameTypeCode;
|
||||||
import com.jsowell.common.enums.ykc.PileChannelEntity;
|
import com.jsowell.common.enums.ykc.PileChannelEntity;
|
||||||
import com.jsowell.common.enums.ykc.PileMainboardManufacturerEnum;
|
|
||||||
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
|
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
|
||||||
import com.jsowell.common.exception.BusinessException;
|
import com.jsowell.common.exception.BusinessException;
|
||||||
import com.jsowell.common.protocol.SyncPromise;
|
import com.jsowell.common.protocol.SyncPromise;
|
||||||
@@ -13,10 +12,8 @@ import com.jsowell.common.service.JcppService;
|
|||||||
import com.jsowell.common.util.*;
|
import com.jsowell.common.util.*;
|
||||||
import com.jsowell.common.util.Cp56Time2a.Cp56Time2aUtil;
|
import com.jsowell.common.util.Cp56Time2a.Cp56Time2aUtil;
|
||||||
import com.jsowell.common.util.spring.SpringUtils;
|
import com.jsowell.common.util.spring.SpringUtils;
|
||||||
import com.jsowell.pile.domain.PileBasicInfo;
|
|
||||||
import com.jsowell.pile.domain.ykcCommond.*;
|
import com.jsowell.pile.domain.ykcCommond.*;
|
||||||
import com.jsowell.pile.dto.SavePileMsgDTO;
|
import com.jsowell.pile.dto.SavePileMsgDTO;
|
||||||
import com.jsowell.pile.mapper.PileBasicInfoMapper;
|
|
||||||
import com.jsowell.pile.service.*;
|
import com.jsowell.pile.service.*;
|
||||||
import com.jsowell.pile.vo.web.BillingTemplateVO;
|
import com.jsowell.pile.vo.web.BillingTemplateVO;
|
||||||
import com.jsowell.pile.vo.web.PileModelInfoVO;
|
import com.jsowell.pile.vo.web.PileModelInfoVO;
|
||||||
@@ -33,8 +30,6 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -48,6 +43,11 @@ import java.util.concurrent.TimeUnit;
|
|||||||
@Service
|
@Service
|
||||||
public class YKCPushCommandServiceImpl implements YKCPushCommandService {
|
public class YKCPushCommandServiceImpl implements YKCPushCommandService {
|
||||||
|
|
||||||
|
private static final BigDecimal DEFAULT_YUXIN_ACCOUNT_BALANCE = new BigDecimal("999.99");
|
||||||
|
private static final BigDecimal DEFAULT_YUXIN_CHARGING_PARAM = BigDecimal.ZERO;
|
||||||
|
private static final int DEFAULT_YUXIN_CHARGING_STRATEGY = 0;
|
||||||
|
private static final int DEFAULT_YUXIN_RESERVATION_TIMEOUT = 0;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PileBillingTemplateService pileBillingTemplateService;
|
private PileBillingTemplateService pileBillingTemplateService;
|
||||||
|
|
||||||
@@ -63,9 +63,6 @@ public class YKCPushCommandServiceImpl implements YKCPushCommandService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private PileConnectorInfoService pileConnectorInfoService;
|
private PileConnectorInfoService pileConnectorInfoService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private PileBasicInfoMapper pileBasicInfoMapper;
|
|
||||||
|
|
||||||
@DubboReference
|
@DubboReference
|
||||||
private JcppService jcppService;
|
private JcppService jcppService;
|
||||||
|
|
||||||
@@ -768,20 +765,41 @@ public class YKCPushCommandServiceImpl implements YKCPushCommandService {
|
|||||||
@Override
|
@Override
|
||||||
public byte[] pushReservationChargingCommand(ReservationChargingCommand command) {
|
public byte[] pushReservationChargingCommand(ReservationChargingCommand command) {
|
||||||
String pileSn = command.getPileSn();
|
String pileSn = command.getPileSn();
|
||||||
YKCFrameTypeCode frameTypeCode = getReservationChargingFrameType(pileSn);
|
byte[] msg = buildReservationChargingMsg(command);
|
||||||
byte[] msg = frameTypeCode == YKCFrameTypeCode.YUXIN_RESERVATION_CHARGING_SETUP_CODE
|
|
||||||
? buildYuxinReservationChargingMsg(command)
|
|
||||||
: buildReservationChargingMsg(command);
|
|
||||||
byte[] response;
|
byte[] response;
|
||||||
try {
|
try {
|
||||||
response = this.supplySend(msg, pileSn, frameTypeCode);
|
response = this.supplySend(msg, pileSn, YKCFrameTypeCode.RESERVATION_CHARGING_SETUP_CODE);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("发送消息异常", e);
|
log.error("发送消息异常", e);
|
||||||
response = null;
|
response = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("【=====平台下发指令=====】: 预约充电指令, 帧类型:{}, 交易流水号:{}, 桩编号:{}, 枪口号:{}, 操作(01-启动; 02-取消; 03-修改):{}, 身份验证:{}, 开始时间:{}, 结束时间:{}, 启动金额:{}",
|
log.info("【=====平台下发指令=====】: 预约充电指令, 帧类型:{}, 交易流水号:{}, 桩编号:{}, 枪口号:{}, 操作(01-启动; 02-取消; 03-修改):{}, 身份验证:{}, 开始时间:{}, 结束时间:{}, 启动金额:{}",
|
||||||
YKCUtils.frameType2Str(frameTypeCode.getBytes()), command.getTransactionCode(), pileSn, command.getConnectorCode(), command.getOperation(), command.getVerifyIdentity(), DateUtils.formatDateTime(command.getReservedStartTime()), DateUtils.formatDateTime(command.getReservedEndTime()), command.getAmount());
|
YKCUtils.frameType2Str(YKCFrameTypeCode.RESERVATION_CHARGING_SETUP_CODE.getBytes()),
|
||||||
|
command.getTransactionCode(), pileSn, command.getConnectorCode(), command.getOperation(),
|
||||||
|
command.getVerifyIdentity(), DateUtils.formatDateTime(command.getReservedStartTime()),
|
||||||
|
DateUtils.formatDateTime(command.getReservedEndTime()), command.getAmount());
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] pushYuxinReservationChargingCommand(YuxinReservationChargingCommand command) {
|
||||||
|
String pileSn = command.getPileSn();
|
||||||
|
byte[] msg = buildYuxinReservationChargingMsg(command);
|
||||||
|
byte[] response;
|
||||||
|
try {
|
||||||
|
response = this.supplySend(msg, pileSn, YKCFrameTypeCode.YUXIN_RESERVATION_CHARGING_SETUP_CODE);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("发送羽信预约充电消息异常", e);
|
||||||
|
response = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("【=====平台下发指令=====】: 羽信预约充电指令, 帧类型:{}, 交易流水号:{}, 桩编号:{}, 枪口号:{}, 账户余额:{}, 预约类型(00-立即预约;01-取消预约):{}, 充电策略:{}, 充电参数:{}, 系统时间:{}, 预约启动时间:{}, 预约超时时间:{}",
|
||||||
|
YKCUtils.frameType2Str(YKCFrameTypeCode.YUXIN_RESERVATION_CHARGING_SETUP_CODE.getBytes()),
|
||||||
|
command.getTransactionCode(), pileSn, command.getConnectorCode(), getYuxinAccountBalance(command),
|
||||||
|
command.getReservationType(), getYuxinChargingStrategy(command), getYuxinChargingParam(command),
|
||||||
|
DateUtils.formatDateTime(getYuxinSystemTime(command)),
|
||||||
|
DateUtils.formatDateTime(command.getReservedStartTime()), getYuxinReservationTimeout(command));
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -841,53 +859,51 @@ public class YKCPushCommandServiceImpl implements YKCPushCommandService {
|
|||||||
reservedStartTimeByteArr, reservedEndTimeByteArr, amountByteArr);
|
reservedStartTimeByteArr, reservedEndTimeByteArr, amountByteArr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] buildYuxinReservationChargingMsg(ReservationChargingCommand command) {
|
private byte[] buildYuxinReservationChargingMsg(YuxinReservationChargingCommand command) {
|
||||||
|
BigDecimal accountBalance = getYuxinAccountBalance(command);
|
||||||
|
int chargingStrategy = getYuxinChargingStrategy(command);
|
||||||
|
BigDecimal chargingParam = getYuxinChargingParam(command);
|
||||||
|
Date systemTime = getYuxinSystemTime(command);
|
||||||
|
int reservationTimeout = getYuxinReservationTimeout(command);
|
||||||
byte[] transactionCodeArr = BytesUtil.ensureLengthPrependZero(BytesUtil.str2Bcd(command.getTransactionCode()), 16);
|
byte[] transactionCodeArr = BytesUtil.ensureLengthPrependZero(BytesUtil.str2Bcd(command.getTransactionCode()), 16);
|
||||||
byte[] pileSnByteArr = BytesUtil.ensureLengthPrependZero(BytesUtil.str2Bcd(command.getPileSn()), 7);
|
byte[] pileSnByteArr = BytesUtil.ensureLengthPrependZero(BytesUtil.str2Bcd(command.getPileSn()), 7);
|
||||||
byte[] connectorCodeByteArr = BytesUtil.intToBytes(parseDecimalByte(command.getConnectorCode(), "枪口号"), 1);
|
byte[] connectorCodeByteArr = BytesUtil.intToBytes(parseDecimalByte(command.getConnectorCode(), "枪口号"), 1);
|
||||||
byte[] accountBalanceByteArr = YKCUtils.getPriceByte(getAmount(command).toString(), 2);
|
byte[] accountBalanceByteArr = YKCUtils.getPriceByte(accountBalance.toString(), 2);
|
||||||
byte[] reservationTypeByteArr = BytesUtil.intToBytes(StringUtils.equals(command.getOperation(), "02") ? 0x01 : 0x00, 1);
|
byte[] reservationTypeByteArr = BytesUtil.intToBytes(parseByteCode(command.getReservationType(), "预约类型"), 1);
|
||||||
byte[] chargingStrategyByteArr = BytesUtil.intToBytes(0x00, 1);
|
byte[] chargingStrategyByteArr = BytesUtil.intToBytes(chargingStrategy, 1);
|
||||||
byte[] chargingParamByteArr = YKCUtils.getPriceByte(BigDecimal.ZERO.toString(), 2);
|
byte[] chargingParamByteArr = YKCUtils.getPriceByte(chargingParam.toString(), 2);
|
||||||
byte[] systemTimeByteArr = Cp56Time2aUtil.date2Hbyte(new Date());
|
byte[] systemTimeByteArr = Cp56Time2aUtil.date2Hbyte(systemTime);
|
||||||
Date reservedStartDate = getYuxinReservedStartDate(command);
|
byte[] reservedStartTimeByteArr = Cp56Time2aUtil.date2Hbyte(command.getReservedStartTime());
|
||||||
byte[] reservedStartTimeByteArr = Cp56Time2aUtil.date2Hbyte(reservedStartDate);
|
byte[] reservationTimeoutByteArr = BytesUtil.intToBytes(reservationTimeout, 1);
|
||||||
byte[] reservationTimeoutByteArr = BytesUtil.intToBytes(getYuxinReservationTimeout(command), 1);
|
log.info("羽信预约充电组包, pileSn:{}, connectorCode:{}, accountBalance:{}, reservationType:{}, chargingStrategy:{}, chargingParam:{}, systemTime:{}, reservedStartTime:{}, reservationTimeout:{}",
|
||||||
log.info("羽信预约充电组包, pileSn:{}, connectorCode:{}, operation:{}, reservationType:{}, reservedStartTime:{}, reservedStartDate:{}, reservationTimeout:{}",
|
command.getPileSn(), command.getConnectorCode(), accountBalance,
|
||||||
command.getPileSn(), command.getConnectorCode(), command.getOperation(),
|
BytesUtil.bin2HexStr(reservationTypeByteArr), chargingStrategy, chargingParam,
|
||||||
BytesUtil.bin2HexStr(reservationTypeByteArr), command.getReservedStartTime(),
|
DateUtils.formatDateTime(systemTime),
|
||||||
DateUtils.formatDateTime(reservedStartDate), getYuxinReservationTimeout(command));
|
DateUtils.formatDateTime(command.getReservedStartTime()), reservationTimeout);
|
||||||
|
|
||||||
return Bytes.concat(transactionCodeArr, pileSnByteArr, connectorCodeByteArr, accountBalanceByteArr,
|
return Bytes.concat(transactionCodeArr, pileSnByteArr, connectorCodeByteArr, accountBalanceByteArr,
|
||||||
reservationTypeByteArr, chargingStrategyByteArr, chargingParamByteArr, systemTimeByteArr,
|
reservationTypeByteArr, chargingStrategyByteArr, chargingParamByteArr, systemTimeByteArr,
|
||||||
reservedStartTimeByteArr, reservationTimeoutByteArr);
|
reservedStartTimeByteArr, reservationTimeoutByteArr);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BigDecimal getAmount(ReservationChargingCommand command) {
|
private BigDecimal getYuxinAccountBalance(YuxinReservationChargingCommand command) {
|
||||||
return command.getAmount() == null ? BigDecimal.ZERO : command.getAmount();
|
return DEFAULT_YUXIN_ACCOUNT_BALANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Date getYuxinReservedStartDate(ReservationChargingCommand command) {
|
private int getYuxinChargingStrategy(YuxinReservationChargingCommand command) {
|
||||||
LocalDateTime now = LocalDateTime.now();
|
return command.getChargingStrategy() == null ? DEFAULT_YUXIN_CHARGING_STRATEGY : command.getChargingStrategy();
|
||||||
LocalTime reservedStartTime = command.getReservedStartTime();
|
|
||||||
LocalDateTime reservedStartDateTime = now.toLocalDate().atTime(reservedStartTime);
|
|
||||||
if (StringUtils.equals(command.getOperation(), "02")) {
|
|
||||||
return DateUtils.localDateTime2Date(reservedStartDateTime);
|
|
||||||
}
|
|
||||||
if (!reservedStartDateTime.isAfter(now)) {
|
|
||||||
reservedStartDateTime = reservedStartDateTime.plusDays(1);
|
|
||||||
}
|
|
||||||
return DateUtils.localDateTime2Date(reservedStartDateTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getYuxinReservationTimeout(ReservationChargingCommand command) {
|
private BigDecimal getYuxinChargingParam(YuxinReservationChargingCommand command) {
|
||||||
LocalTime reservedStartTime = command.getReservedStartTime();
|
return command.getChargingParam() == null ? DEFAULT_YUXIN_CHARGING_PARAM : command.getChargingParam();
|
||||||
LocalTime reservedEndTime = command.getReservedEndTime();
|
}
|
||||||
long timeout = Duration.between(reservedStartTime, reservedEndTime).toMinutes();
|
|
||||||
if (timeout <= 0) {
|
private Date getYuxinSystemTime(YuxinReservationChargingCommand command) {
|
||||||
timeout += TimeUnit.DAYS.toMinutes(1);
|
return command.getSystemTime() == null ? new Date() : command.getSystemTime();
|
||||||
}
|
}
|
||||||
return (int) Math.min(timeout, 0xFF);
|
|
||||||
|
private int getYuxinReservationTimeout(YuxinReservationChargingCommand command) {
|
||||||
|
return command.getReservationTimeout() == null ? DEFAULT_YUXIN_RESERVATION_TIMEOUT : command.getReservationTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int parseDecimalByte(String value, String fieldName) {
|
private int parseDecimalByte(String value, String fieldName) {
|
||||||
@@ -898,18 +914,21 @@ public class YKCPushCommandServiceImpl implements YKCPushCommandService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private YKCFrameTypeCode getReservationChargingFrameType(String pileSn) {
|
private int parseByteCode(String value, String fieldName) {
|
||||||
try {
|
if (StringUtils.isBlank(value)) {
|
||||||
PileBasicInfo pileBasicInfo = pileBasicInfoMapper.selectPileBasicInfoBySn(pileSn);
|
throw new IllegalArgumentException(fieldName + "不能为空");
|
||||||
String programVersion = pileBasicInfo == null ? null : pileBasicInfo.getProgramVersion();
|
|
||||||
PileMainboardManufacturerEnum manufacturer = PileProgramVersionUtils.getMainboardManufacturer(programVersion);
|
|
||||||
if (manufacturer == PileMainboardManufacturerEnum.YUXIN) {
|
|
||||||
return YKCFrameTypeCode.YUXIN_RESERVATION_CHARGING_SETUP_CODE;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.warn("查询主板厂家失败, 使用默认预约充电帧类型, pileSn:{}", pileSn, e);
|
|
||||||
}
|
}
|
||||||
return YKCFrameTypeCode.RESERVATION_CHARGING_SETUP_CODE;
|
String normalized = value.trim();
|
||||||
|
int result;
|
||||||
|
if (normalized.startsWith("0x") || normalized.startsWith("0X")) {
|
||||||
|
result = Integer.parseInt(normalized.substring(2), 16);
|
||||||
|
} else {
|
||||||
|
result = Integer.parseInt(normalized);
|
||||||
|
}
|
||||||
|
if (result < 0 || result > 0xFF) {
|
||||||
|
throw new IllegalArgumentException(fieldName + "超出1字节范围:" + value);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,384 @@
|
|||||||
|
package com.jsowell.pile.service.impl;
|
||||||
|
|
||||||
|
import com.jsowell.common.constant.Constants;
|
||||||
|
import com.jsowell.common.enums.DelFlagEnum;
|
||||||
|
import com.jsowell.common.enums.ykc.PileMainboardManufacturerEnum;
|
||||||
|
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
|
||||||
|
import com.jsowell.common.exception.BusinessException;
|
||||||
|
import com.jsowell.common.util.DateUtils;
|
||||||
|
import com.jsowell.common.util.PileProgramVersionUtils;
|
||||||
|
import com.jsowell.common.util.StringUtils;
|
||||||
|
import com.jsowell.common.util.YKCUtils;
|
||||||
|
import com.jsowell.pile.domain.PileBasicInfo;
|
||||||
|
import com.jsowell.pile.domain.PileReservationInfo;
|
||||||
|
import com.jsowell.pile.domain.ykcCommond.YuxinReservationChargingCommand;
|
||||||
|
import com.jsowell.pile.dto.YuxinReservationChargingDTO;
|
||||||
|
import com.jsowell.pile.mapper.PileReservationInfoMapper;
|
||||||
|
import com.jsowell.pile.service.PileBasicInfoService;
|
||||||
|
import com.jsowell.pile.service.PileRemoteService;
|
||||||
|
import com.jsowell.pile.service.YuxinReservationChargingService;
|
||||||
|
import com.jsowell.pile.vo.PileReservationInfoVO;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.Time;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class YuxinReservationChargingServiceImpl implements YuxinReservationChargingService {
|
||||||
|
|
||||||
|
private static final String YUXIN_RESERVATION_TYPE_CREATE = "00";
|
||||||
|
private static final String YUXIN_RESERVATION_TYPE_CANCEL = "01";
|
||||||
|
private static final BigDecimal YUXIN_ACCOUNT_BALANCE = new BigDecimal("999.99");
|
||||||
|
private static final BigDecimal DEFAULT_CHARGING_PARAM = BigDecimal.ZERO;
|
||||||
|
private static final int DEFAULT_CHARGING_STRATEGY = 0;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PileReservationInfoMapper pileReservationInfoMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PileRemoteService pileRemoteService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PileBasicInfoService pileBasicInfoService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int createReservation(YuxinReservationChargingDTO dto) {
|
||||||
|
validateCreateOrUpdateParam(dto);
|
||||||
|
normalizePileInfo(dto);
|
||||||
|
assertYuxinMainboard(dto.getPileSn());
|
||||||
|
|
||||||
|
PileReservationInfo currentReservation = pileReservationInfoMapper.selectByPileConnectorCode(dto.getPileConnectorCode());
|
||||||
|
PileReservationInfo oldReservation = currentReservation == null ? null : copyReservationInfo(currentReservation);
|
||||||
|
boolean oldActive = oldReservation != null && StringUtils.equals(oldReservation.getStatus(), Constants.ONE);
|
||||||
|
|
||||||
|
PileReservationInfo reservationInfo = currentReservation == null ? new PileReservationInfo() : currentReservation;
|
||||||
|
fillReservationInfo(reservationInfo, dto);
|
||||||
|
if (currentReservation == null) {
|
||||||
|
reservationInfo.setCreateBy(dto.getMemberId());
|
||||||
|
} else {
|
||||||
|
reservationInfo.setUpdateBy(dto.getMemberId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isTimeSlotAvailable(dto.getMemberId(), dto.getPileSn(), reservationInfo.getStartTime(),
|
||||||
|
reservationInfo.getEndTime(), reservationInfo.getId())) {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_REFUSED);
|
||||||
|
}
|
||||||
|
if (oldActive) {
|
||||||
|
cancelOldReservationBeforeCreate(dto, oldReservation);
|
||||||
|
}
|
||||||
|
sendYuxinReservationCommandAndAssertSuccess(dto, reservationInfo, YUXIN_RESERVATION_TYPE_CREATE);
|
||||||
|
pileReservationInfoMapper.insertOrUpdateSelective(reservationInfo);
|
||||||
|
return reservationInfo.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int updateReservation(YuxinReservationChargingDTO dto) {
|
||||||
|
if (StringUtils.isBlank(dto.getReservedId())) {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR);
|
||||||
|
}
|
||||||
|
PileReservationInfo reservationInfo = pileReservationInfoMapper.selectByPrimaryKey(Integer.valueOf(dto.getReservedId()));
|
||||||
|
if (reservationInfo == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
dto.setPileSn(StringUtils.defaultIfBlank(dto.getPileSn(), reservationInfo.getPileSn()));
|
||||||
|
dto.setPileConnectorCode(StringUtils.defaultIfBlank(dto.getPileConnectorCode(), reservationInfo.getPileConnectorCode()));
|
||||||
|
dto.setStartTime(StringUtils.defaultIfBlank(dto.getStartTime(), reservationInfo.getStartTime().toString()));
|
||||||
|
dto.setEndTime(StringUtils.defaultIfBlank(dto.getEndTime(), reservationInfo.getEndTime().toString()));
|
||||||
|
assertYuxinMainboard(dto.getPileSn());
|
||||||
|
|
||||||
|
PileReservationInfo oldReservation = copyReservationInfo(reservationInfo);
|
||||||
|
fillReservationInfo(reservationInfo, dto);
|
||||||
|
reservationInfo.setUpdateBy(dto.getMemberId());
|
||||||
|
|
||||||
|
if (!isTimeSlotAvailable(dto.getMemberId(), dto.getPileSn(), reservationInfo.getStartTime(),
|
||||||
|
reservationInfo.getEndTime(), reservationInfo.getId())) {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_REFUSED);
|
||||||
|
}
|
||||||
|
if (StringUtils.equals(oldReservation.getStatus(), Constants.ONE)) {
|
||||||
|
cancelOldReservationBeforeCreate(dto, oldReservation);
|
||||||
|
}
|
||||||
|
sendYuxinReservationCommandAndAssertSuccess(dto, reservationInfo, YUXIN_RESERVATION_TYPE_CREATE);
|
||||||
|
return pileReservationInfoMapper.insertOrUpdateSelective(reservationInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancelReservation(YuxinReservationChargingDTO dto) {
|
||||||
|
if (StringUtils.isBlank(dto.getReservedId())) {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR);
|
||||||
|
}
|
||||||
|
PileReservationInfo reservationInfo = pileReservationInfoMapper.selectByPrimaryKey(Integer.valueOf(dto.getReservedId()));
|
||||||
|
if (reservationInfo == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assertYuxinMainboard(reservationInfo.getPileSn());
|
||||||
|
boolean cancelSuccess = true;
|
||||||
|
if (StringUtils.equals(reservationInfo.getStatus(), Constants.ONE)) {
|
||||||
|
cancelSuccess = sendYuxinReservationCommand(dto, reservationInfo, YUXIN_RESERVATION_TYPE_CANCEL);
|
||||||
|
}
|
||||||
|
if (!cancelSuccess && !isReservationTimeEnded(reservationInfo)) {
|
||||||
|
throwReservationCommandFailed();
|
||||||
|
}
|
||||||
|
if (!cancelSuccess) {
|
||||||
|
log.warn("羽信取消预约失败, 但预约时间窗已过期, 本地停用预约, memberId:{}, reservation:{}",
|
||||||
|
dto.getMemberId(), reservationLogText(reservationInfo));
|
||||||
|
}
|
||||||
|
reservationInfo.setStatus(Constants.ZERO);
|
||||||
|
reservationInfo.setUpdateBy(dto.getMemberId());
|
||||||
|
pileReservationInfoMapper.updateByPrimaryKeySelective(reservationInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteReservation(YuxinReservationChargingDTO dto) {
|
||||||
|
if (StringUtils.isBlank(dto.getReservedId())) {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR);
|
||||||
|
}
|
||||||
|
PileReservationInfo reservationInfo = pileReservationInfoMapper.selectByPrimaryKey(Integer.valueOf(dto.getReservedId()));
|
||||||
|
if (Objects.isNull(reservationInfo)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assertYuxinMainboard(reservationInfo.getPileSn());
|
||||||
|
boolean cancelSuccess = true;
|
||||||
|
if (StringUtils.equals(reservationInfo.getStatus(), Constants.ONE)) {
|
||||||
|
cancelSuccess = sendYuxinReservationCommand(dto, reservationInfo, YUXIN_RESERVATION_TYPE_CANCEL);
|
||||||
|
}
|
||||||
|
if (!cancelSuccess && !isReservationTimeEnded(reservationInfo)) {
|
||||||
|
throwReservationCommandFailed();
|
||||||
|
}
|
||||||
|
reservationInfo.setStatus(Constants.ZERO);
|
||||||
|
reservationInfo.setDelFlag(DelFlagEnum.DELETE.getValue());
|
||||||
|
reservationInfo.setUpdateBy(dto.getMemberId());
|
||||||
|
pileReservationInfoMapper.updateByPrimaryKey(reservationInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PileReservationInfoVO queryReservationInfo(YuxinReservationChargingDTO dto) {
|
||||||
|
if (StringUtils.isBlank(dto.getPileConnectorCode())) {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR);
|
||||||
|
}
|
||||||
|
PileReservationInfo reservationInfo = pileReservationInfoMapper.selectByPileConnectorCode(dto.getPileConnectorCode());
|
||||||
|
if (reservationInfo == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return PileReservationInfoVO.builder()
|
||||||
|
.reservedId(reservationInfo.getId() + "")
|
||||||
|
.pileSn(reservationInfo.getPileSn())
|
||||||
|
.pileConnectorCode(reservationInfo.getPileConnectorCode())
|
||||||
|
.startTime(reservationInfo.getStartTime().toString())
|
||||||
|
.endTime(reservationInfo.getEndTime().toString())
|
||||||
|
.verifyIdentity(reservationInfo.getVerifyIdentity())
|
||||||
|
.status(reservationInfo.getStatus())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillReservationInfo(PileReservationInfo reservationInfo, YuxinReservationChargingDTO dto) {
|
||||||
|
reservationInfo.setMemberId(dto.getMemberId());
|
||||||
|
reservationInfo.setPileSn(dto.getPileSn());
|
||||||
|
reservationInfo.setPileConnectorCode(dto.getPileConnectorCode());
|
||||||
|
reservationInfo.setStatus(Constants.ONE);
|
||||||
|
reservationInfo.setDelFlag(DelFlagEnum.NORMAL.getValue());
|
||||||
|
reservationInfo.setReservationType("recurring");
|
||||||
|
reservationInfo.setFreq("daily");
|
||||||
|
reservationInfo.setVerifyIdentity(Constants.ZERO);
|
||||||
|
reservationInfo.setStartTime(parseSqlTime(dto.getStartTime()));
|
||||||
|
reservationInfo.setEndTime(parseSqlTime(dto.getEndTime()));
|
||||||
|
if (reservationInfo.getId() == null) {
|
||||||
|
reservationInfo.setCreateTime(DateUtils.getNowDate());
|
||||||
|
} else {
|
||||||
|
reservationInfo.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelOldReservationBeforeCreate(YuxinReservationChargingDTO dto, PileReservationInfo oldReservation) {
|
||||||
|
boolean cancelSuccess = sendYuxinReservationCommand(dto, oldReservation, YUXIN_RESERVATION_TYPE_CANCEL);
|
||||||
|
if (!cancelSuccess && !isReservationTimeEnded(oldReservation)) {
|
||||||
|
throwReservationCommandFailed();
|
||||||
|
}
|
||||||
|
if (!cancelSuccess) {
|
||||||
|
log.warn("羽信预约新时间前取消旧预约失败, 但旧预约时间窗已过期, 继续预约新时间, memberId:{}, oldReservation:{}",
|
||||||
|
dto.getMemberId(), reservationLogText(oldReservation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendYuxinReservationCommandAndAssertSuccess(YuxinReservationChargingDTO dto,
|
||||||
|
PileReservationInfo reservationInfo,
|
||||||
|
String yuxinReservationType) {
|
||||||
|
if (!sendYuxinReservationCommand(dto, reservationInfo, yuxinReservationType)) {
|
||||||
|
throwReservationCommandFailed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean sendYuxinReservationCommand(YuxinReservationChargingDTO dto,
|
||||||
|
PileReservationInfo reservationInfo,
|
||||||
|
String yuxinReservationType) {
|
||||||
|
YuxinReservationChargingCommand command = buildYuxinReservationChargingCommand(dto, reservationInfo, yuxinReservationType);
|
||||||
|
log.info("羽信预约充电指令下发, memberId:{}, reservedId:{}, reservationType:{}, reservation:{}",
|
||||||
|
dto.getMemberId(), reservationInfo.getId(), yuxinReservationType, reservationLogText(reservationInfo));
|
||||||
|
String result = pileRemoteService.yuxinReservationCharging(command);
|
||||||
|
boolean success = StringUtils.equals(result, Constants.ONE);
|
||||||
|
log.info("羽信预约充电指令返回, memberId:{}, reservedId:{}, reservationType:{}, result:{}, success:{}",
|
||||||
|
dto.getMemberId(), reservationInfo.getId(), yuxinReservationType, result, success);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
private YuxinReservationChargingCommand buildYuxinReservationChargingCommand(YuxinReservationChargingDTO dto,
|
||||||
|
PileReservationInfo reservationInfo,
|
||||||
|
String yuxinReservationType) {
|
||||||
|
return YuxinReservationChargingCommand.builder()
|
||||||
|
.transactionCode(Constants.ILLEGAL_TRANSACTION_CODE)
|
||||||
|
.pileSn(reservationInfo.getPileSn())
|
||||||
|
.connectorCode(getConnectorCode(reservationInfo))
|
||||||
|
.accountBalance(YUXIN_ACCOUNT_BALANCE)
|
||||||
|
.reservationType(yuxinReservationType)
|
||||||
|
.chargingStrategy(dto.getChargingStrategy() == null ? DEFAULT_CHARGING_STRATEGY : dto.getChargingStrategy())
|
||||||
|
.chargingParam(dto.getChargingParam() == null ? DEFAULT_CHARGING_PARAM : dto.getChargingParam())
|
||||||
|
.systemTime(new Date())
|
||||||
|
.reservedStartTime(getReservedStartDate(reservationInfo.getStartTime().toLocalTime(), yuxinReservationType))
|
||||||
|
.reservationTimeout(getReservationTimeout(dto, reservationInfo, yuxinReservationType))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Date getReservedStartDate(LocalTime reservedStartTime, String yuxinReservationType) {
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
LocalDateTime reservedStartDateTime = now.toLocalDate().atTime(reservedStartTime);
|
||||||
|
if (StringUtils.equals(yuxinReservationType, YUXIN_RESERVATION_TYPE_CREATE)
|
||||||
|
&& !reservedStartDateTime.isAfter(now)) {
|
||||||
|
reservedStartDateTime = reservedStartDateTime.plusDays(1);
|
||||||
|
}
|
||||||
|
return DateUtils.localDateTime2Date(reservedStartDateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getReservationTimeout(YuxinReservationChargingDTO dto,
|
||||||
|
PileReservationInfo reservationInfo,
|
||||||
|
String yuxinReservationType) {
|
||||||
|
if (StringUtils.equals(yuxinReservationType, YUXIN_RESERVATION_TYPE_CANCEL)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (dto.getReservationTimeout() != null) {
|
||||||
|
return Math.min(Math.max(dto.getReservationTimeout(), 0), 0xFF);
|
||||||
|
}
|
||||||
|
LocalTime startTime = reservationInfo.getStartTime().toLocalTime();
|
||||||
|
LocalTime endTime = reservationInfo.getEndTime().toLocalTime();
|
||||||
|
long timeout = Duration.between(startTime, endTime).toMinutes();
|
||||||
|
if (timeout <= 0) {
|
||||||
|
timeout += TimeUnit.DAYS.toMinutes(1);
|
||||||
|
}
|
||||||
|
return (int) Math.min(timeout, 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getConnectorCode(PileReservationInfo reservationInfo) {
|
||||||
|
return reservationInfo.getPileConnectorCode().replace(reservationInfo.getPileSn(), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void normalizePileInfo(YuxinReservationChargingDTO dto) {
|
||||||
|
if (StringUtils.isBlank(dto.getPileConnectorCode())) {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR);
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(dto.getPileSn())) {
|
||||||
|
dto.setPileSn(YKCUtils.getPileSn(dto.getPileConnectorCode()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateCreateOrUpdateParam(YuxinReservationChargingDTO dto) {
|
||||||
|
if (StringUtils.isBlank(dto.getMemberId())
|
||||||
|
|| StringUtils.isBlank(dto.getPileConnectorCode())
|
||||||
|
|| StringUtils.isBlank(dto.getStartTime())
|
||||||
|
|| StringUtils.isBlank(dto.getEndTime())) {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Time parseSqlTime(String time) {
|
||||||
|
if (time.length() == 5) {
|
||||||
|
return Time.valueOf(time + ":00");
|
||||||
|
}
|
||||||
|
return Time.valueOf(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isTimeSlotAvailable(String memberId, String pileSn, Time startTime, Time endTime, Integer reservationId) {
|
||||||
|
List<PileReservationInfo> reservations = pileReservationInfoMapper.findByMemberIdAndPileSnAndStatus(memberId, pileSn, Constants.ONE);
|
||||||
|
LocalTime newStartTime = startTime.toLocalTime();
|
||||||
|
LocalTime newEndTime = endTime.toLocalTime();
|
||||||
|
for (PileReservationInfo res : reservations) {
|
||||||
|
if (reservationId != null && res.getId().equals(reservationId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LocalTime existingStartTime = res.getStartTime().toLocalTime();
|
||||||
|
LocalTime existingEndTime = res.getEndTime().toLocalTime();
|
||||||
|
if (newStartTime.isBefore(existingEndTime) && newEndTime.isAfter(existingStartTime)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isReservationTimeEnded(PileReservationInfo reservationInfo) {
|
||||||
|
if (reservationInfo == null || reservationInfo.getStartTime() == null || reservationInfo.getEndTime() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LocalTime now = LocalTime.now();
|
||||||
|
LocalTime startTime = reservationInfo.getStartTime().toLocalTime();
|
||||||
|
LocalTime endTime = reservationInfo.getEndTime().toLocalTime();
|
||||||
|
boolean crossDay = endTime.isBefore(startTime);
|
||||||
|
boolean ended = crossDay
|
||||||
|
? !now.isBefore(endTime) && now.isBefore(startTime)
|
||||||
|
: !endTime.isAfter(now);
|
||||||
|
log.info("羽信预约过期判断, reservedId:{}, pileConnectorCode:{}, now:{}, startTime:{}, endTime:{}, crossDay:{}, ended:{}",
|
||||||
|
reservationInfo.getId(), reservationInfo.getPileConnectorCode(), now, startTime, endTime, crossDay, ended);
|
||||||
|
return ended;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertYuxinMainboard(String pileSn) {
|
||||||
|
PileBasicInfo pileBasicInfo = pileBasicInfoService.selectPileBasicInfoBySN(pileSn);
|
||||||
|
String programVersion = pileBasicInfo == null ? null : pileBasicInfo.getProgramVersion();
|
||||||
|
PileMainboardManufacturerEnum manufacturer = PileProgramVersionUtils.getMainboardManufacturer(programVersion);
|
||||||
|
if (manufacturer != PileMainboardManufacturerEnum.YUXIN) {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_FAILED.getValue(), "当前充电桩不是羽信主板");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void throwReservationCommandFailed() {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_ERROR.getValue(),
|
||||||
|
ReturnCodeEnum.CODE_UPDATE_RESERVED_STATUS_ERROR.getLabel() + ": 充电桩返回修改失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String reservationLogText(PileReservationInfo reservationInfo) {
|
||||||
|
if (reservationInfo == null) {
|
||||||
|
return "null";
|
||||||
|
}
|
||||||
|
return String.format("reservedId=%s,pileSn=%s,pileConnectorCode=%s,status=%s,reservationType=%s,verifyIdentity=%s,startTime=%s,endTime=%s",
|
||||||
|
reservationInfo.getId(), reservationInfo.getPileSn(), reservationInfo.getPileConnectorCode(),
|
||||||
|
reservationInfo.getStatus(), reservationInfo.getReservationType(), reservationInfo.getVerifyIdentity(),
|
||||||
|
reservationInfo.getStartTime(), reservationInfo.getEndTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
private PileReservationInfo copyReservationInfo(PileReservationInfo source) {
|
||||||
|
PileReservationInfo target = new PileReservationInfo();
|
||||||
|
target.setId(source.getId());
|
||||||
|
target.setMemberId(source.getMemberId());
|
||||||
|
target.setPileSn(source.getPileSn());
|
||||||
|
target.setPileConnectorCode(source.getPileConnectorCode());
|
||||||
|
target.setStatus(source.getStatus());
|
||||||
|
target.setReservationType(source.getReservationType());
|
||||||
|
target.setVerifyIdentity(source.getVerifyIdentity());
|
||||||
|
target.setStartTime(source.getStartTime());
|
||||||
|
target.setEndTime(source.getEndTime());
|
||||||
|
target.setFreq(source.getFreq());
|
||||||
|
target.setCreateBy(source.getCreateBy());
|
||||||
|
target.setCreateTime(source.getCreateTime());
|
||||||
|
target.setUpdateBy(source.getUpdateBy());
|
||||||
|
target.setUpdateTime(source.getUpdateTime());
|
||||||
|
target.setDelFlag(source.getDelFlag());
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user