Merge remote-tracking branch 'origin/main'

This commit is contained in:
PC 2026-01-15 16:53:32 +08:00
commit fb78f577b7
4 changed files with 121 additions and 74 deletions

View File

@ -4,15 +4,51 @@ import cn.dev33.satoken.stp.StpUtil;
import com.cdzy.common.ex.EbikeException;
import com.cdzy.common.model.dto.ResGPSDto;
import com.cdzy.common.model.request.PageParam;
import com.cdzy.operations.enums.*;
import com.cdzy.operations.mapper.*;
import com.cdzy.operations.enums.BatteryStatus;
import com.cdzy.operations.enums.BikeOrderType;
import com.cdzy.operations.enums.BikeQrStatus;
import com.cdzy.operations.enums.BikeStatus;
import com.cdzy.operations.enums.BikeUsageStatus;
import com.cdzy.operations.enums.OrderDispatchState;
import com.cdzy.operations.enums.OrderHandleState;
import com.cdzy.operations.enums.RegionStatus;
import com.cdzy.operations.enums.SpecialBillingConfigurationType;
import com.cdzy.operations.mapper.EbiekSpecialDayMapper;
import com.cdzy.operations.mapper.EbiekSpecialTimeMapper;
import com.cdzy.operations.mapper.EbikeBatteryInfoMapper;
import com.cdzy.operations.mapper.EbikeBikeInfoMapper;
import com.cdzy.operations.mapper.EbikeBikeOrderMapper;
import com.cdzy.operations.mapper.EbikeBikeQrMapper;
import com.cdzy.operations.mapper.EbikeDefaultBillingConfigurationMapper;
import com.cdzy.operations.mapper.EbikeRegionMapper;
import com.cdzy.operations.mapper.EbikeSiteMapper;
import com.cdzy.operations.mapper.EbikeSpecialBillingConfigurationMapper;
import com.cdzy.operations.model.dto.EbikeBikeInfoDto;
import com.cdzy.operations.model.dto.EbikeDto;
import com.cdzy.operations.model.dto.EbikeUserBikeInfo;
import com.cdzy.operations.model.dto.EbikeUserLockDto;
import com.cdzy.operations.model.entity.*;
import com.cdzy.operations.model.vo.*;
import com.cdzy.operations.service.*;
import com.cdzy.operations.model.entity.EbikeBatteryInfo;
import com.cdzy.operations.model.entity.EbikeBikeInfo;
import com.cdzy.operations.model.entity.EbikeBikeOrder;
import com.cdzy.operations.model.entity.EbikeBikeQr;
import com.cdzy.operations.model.entity.EbikeDefaultBillingConfiguration;
import com.cdzy.operations.model.entity.EbikeDispatchConfiguration;
import com.cdzy.operations.model.entity.EbikeEcuInfo;
import com.cdzy.operations.model.entity.EbikeInventoryRecord;
import com.cdzy.operations.model.entity.EbikeRegion;
import com.cdzy.operations.model.entity.EbikeSpecialBillingConfiguration;
import com.cdzy.operations.model.entity.EbikeSpecialDay;
import com.cdzy.operations.model.entity.EbikeSpecialTime;
import com.cdzy.operations.model.vo.EbikeBatchLaunchVo;
import com.cdzy.operations.model.vo.EbikeBatchUnLaunchVo;
import com.cdzy.operations.model.vo.EbikeBikeBindVo;
import com.cdzy.operations.model.vo.EbikeBikeRadiusVo;
import com.cdzy.operations.model.vo.EbikeInventoryVo;
import com.cdzy.operations.service.EbikeBikeInfoService;
import com.cdzy.operations.service.EbikeDispatchConfigurationService;
import com.cdzy.operations.service.EbikeEcuInfoService;
import com.cdzy.operations.service.EbikeInventoryRecordService;
import com.cdzy.operations.service.EbikeInventoryService;
import com.cdzy.operations.utils.RedisUtil;
import com.ebike.feign.model.vo.EbikeLockVo;
import com.mybatisflex.core.paginate.Page;
@ -365,6 +401,8 @@ public class EbikeBikeInfoServiceImpl extends ServiceImpl<EbikeBikeInfoMapper, E
bikeOrder.setHandleState(OrderHandleState.VOIDED);
orderMapper.update(bikeOrder);
}
// 删除redis中的 车辆多长时间无单生成调度工单
redisUtil.deleteNoDocument(bikeCode);
}
@Override

View File

@ -488,7 +488,7 @@ public class RedisUtil {
}
/**
* 数据库2专用存储 辆多长时间无单生成调度工单 并设置过期时间
* 数据库2专用删除 车辆多长时间无单生成调度工单
*/
public void deleteNoDocument(String bikeCode) {
delete(Database.DB2, BIKE_NO_DOCUMENT_PREFIX + bikeCode);

View File

@ -19,9 +19,6 @@ import java.time.LocalDateTime;
@Data
public class EbikeOrderDetailVo {
/**
* 订单表主键ID
*/
private Long orderId;
/**
@ -177,4 +174,24 @@ public class EbikeOrderDetailVo {
* 是否免费订单 true-免费 false-收费
*/
private Boolean isFreeOrder;
/**
* 用户花费时长费用
*/
private BigDecimal userDurationFee;
/**
* 用户花费起步费用
*/
private BigDecimal userBaseFee;
/**
* 用户花费调度费用
*/
private BigDecimal userDispatchFee;
/**
* 用户头盔费用
*/
private BigDecimal userHelmetFee;
}

View File

@ -310,28 +310,13 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
public EbikeOrderDetailVo getInfo(Long orderId) {
QueryWrapper queryWrapper = QueryWrapper.create()
.select(
EBIKE_ORDER.ORDER_ID,
EBIKE_ORDER.USER_ID,
EBIKE_ORDER.OPERATOR_ID,
EBIKE_ORDER.BIKE_CODE,
EBIKE_ORDER.ORDER_TYPE,
EBIKE_ORDER.ORDER_STATUS,
EBIKE_ORDER.TOTAL_AMOUNT,
EBIKE_ORDER.ACTUAL_AMOUNT,
EBIKE_ORDER.START_TIME,
EBIKE_ORDER.END_TIME,
EBIKE_ORDER.PAYMENT_TIME,
EBIKE_ORDER.PAYMENT_METHOD,
EBIKE_ORDER.BASE_DURATION_MINUTES,
EBIKE_ORDER.FREE_DURATION_MINUTES,
EBIKE_ORDER.CHARGE_DURATION_MINUTES,
EBIKE_ORDER.MAX_FEE_AMOUNT,
EBIKE_ORDER.START_LOCATION,
EBIKE_ORDER.END_LOCATION,
EBIKE_ORDER.IS_FREE_ORDER
EBIKE_ORDER.ALL_COLUMNS
)
.where(EBIKE_ORDER.ORDER_ID.eq(orderId));
EbikeOrderDetailVo ebikeOrderDetailVo = this.mapper.selectOneByQueryAs(queryWrapper, EbikeOrderDetailVo.class);
if (Objects.isNull(ebikeOrderDetailVo)) {
throw new EbikeException("订单不存在");
}
//获取费用详情
List<EbikePaymentCostDetailVo> details = ebikeOrderDetailService.getOrderDetailsByOrderId(orderId);
if (Objects.nonNull(details)) {
@ -340,27 +325,27 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
switch (payDetailVo.getDetailType()) {
case 1 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setDurationFee((current != null ? current : BigDecimal.ZERO));
ebikeOrderDetailVo.setUserDurationFee((current != null ? current : BigDecimal.ZERO));
}
case 2 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setBaseFee((current != null ? current : BigDecimal.ZERO));
ebikeOrderDetailVo.setUserBaseFee((current != null ? current : BigDecimal.ZERO));
}
case 3 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setOutOfServiceAreaFee((current != null ? current : BigDecimal.ZERO));
ebikeOrderDetailVo.setUserDispatchFee((current != null ? current : BigDecimal.ZERO));
}
case 4 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setOutOfParkingAreaFee((current != null ? current : BigDecimal.ZERO));
ebikeOrderDetailVo.setUserDispatchFee((current != null ? current : BigDecimal.ZERO));
}
case 5 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setNoParkingZoneFee((current != null ? current : BigDecimal.ZERO));
ebikeOrderDetailVo.setUserDispatchFee((current != null ? current : BigDecimal.ZERO));
}
case 6 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setHelmetManagementFee((current != null ? current : BigDecimal.ZERO));
ebikeOrderDetailVo.setUserHelmetFee((current != null ? current : BigDecimal.ZERO));
}
}
}
@ -459,61 +444,68 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
* @return 订单费用
*/
private EbikeCostDetailDto costCalculation(LocalDateTime endTime,
EbikeOrder order, FeignEbikeUserLockDto data) {
// 基础费用计算
EbikeOrder order,
FeignEbikeUserLockDto data) {
EbikeCostDetailDto dto = new EbikeCostDetailDto();
// 1. 基础参数
BigDecimal baseFee = Objects.requireNonNullElse(order.getBaseFee(), BigDecimal.ZERO);
BigDecimal durationFee = Objects.requireNonNullElse(order.getDurationFee(), BigDecimal.ZERO);
Integer freeDurationMinutes = order.getFreeDurationMinutes();
Integer chargeDurationMinutes = order.getChargeDurationMinutes();
// 获取总骑行时长
Integer freeDurationMinutes = Objects.requireNonNullElse(order.getFreeDurationMinutes(), 0);
Integer baseDurationMinutes = Objects.requireNonNullElse(order.getBaseDurationMinutes(), 0);
int chargeDurationMinutes = Objects.requireNonNullElse(order.getChargeDurationMinutes(), 1);
// 2. 计算总骑行时长
long totalRideSeconds = Duration.between(order.getStartTime(), endTime).toSeconds();
// 免费时间
long freeDurationSeconds = freeDurationMinutes * GlobalConstants.LONG_SIXTY;
// 如果骑行时长小于等于免费时长,不收费
BigDecimal baseCost;
EbikeCostDetailDto ebikeCostDetailDto = new EbikeCostDetailDto();
// 起步费用
ebikeCostDetailDto.setBaseFee(baseFee);
if (totalRideSeconds <= freeDurationSeconds) {
ebikeCostDetailDto.setTotalCost(BigDecimal.ZERO);
return ebikeCostDetailDto;
} else {
long totalRoundedMinutes = (totalRideSeconds + GlobalConstants.NUMBER_FIFTY_NINE) / GlobalConstants.NUMBER_SIXTY;
// 可计费分钟数 = 向上取整后的总分钟 - 免费分钟
long chargeableMinutes = totalRoundedMinutes - freeDurationMinutes;
long chargeUnits = (chargeableMinutes + chargeDurationMinutes - 1) / chargeDurationMinutes;
BigDecimal durationCost = durationFee.multiply(BigDecimal.valueOf(chargeUnits));
// 时长费用
ebikeCostDetailDto.setDurationFee(durationCost);
// 总基础费用
baseCost = baseFee.add(durationCost);
// 向上取整为分钟
long totalRideMinutes = (totalRideSeconds + 59) / 60;
// 3. 免费阶段总时长 <= 免费时长
if (totalRideMinutes <= freeDurationMinutes) {
dto.setTotalCost(BigDecimal.ZERO);
return dto;
}
// 计算调度费按优先级判断附加费用运营区 > 停车区外 > 禁停区
// 4. 起步阶段免费之后但未超出起步时长 只收起步费
long includedInBaseMinutes = freeDurationMinutes + baseDurationMinutes;
if (totalRideMinutes <= includedInBaseMinutes) {
dto.setBaseFee(baseFee);
dto.setTotalCost(baseFee);
return dto;
}
// 5. 超出起步阶段计算额外时长费用
long extraMinutes = totalRideMinutes - includedInBaseMinutes;
long chargeUnits = (extraMinutes + chargeDurationMinutes - 1) / chargeDurationMinutes;
BigDecimal durationCost = durationFee.multiply(BigDecimal.valueOf(chargeUnits));
dto.setBaseFee(baseFee);
dto.setDurationFee(durationCost);
BigDecimal baseCost = baseFee.add(durationCost);
// 6. 调度费用
BigDecimal additionalFee = BigDecimal.ZERO;
if (data != null) {
// 运营区
if (Boolean.FALSE.equals(data.getBikeInRegion())) {
additionalFee = order.getOutOfServiceAreaFee() != null ? order.getOutOfServiceAreaFee() : BigDecimal.ZERO;
ebikeCostDetailDto.setOutOfServiceAreaFee(additionalFee);
additionalFee = Objects.requireNonNullElse(order.getOutOfServiceAreaFee(), BigDecimal.ZERO);
dto.setOutOfServiceAreaFee(additionalFee);
} else if (Boolean.FALSE.equals(data.getBikeInParking())) {
// 不在运营区内但在停车区内
additionalFee = order.getOutOfParkingAreaFee() != null ? order.getOutOfParkingAreaFee() : BigDecimal.ZERO;
ebikeCostDetailDto.setOutOfParkingAreaFee(additionalFee);
} else if (Boolean.FALSE.equals(data.getBikeInNoParking())) {
// 不在运营区内也不在停车区内但在禁停区内
additionalFee = order.getNoParkingZoneFee() != null ? order.getNoParkingZoneFee() : BigDecimal.ZERO;
ebikeCostDetailDto.setNoParkingZoneFee(additionalFee);
additionalFee = Objects.requireNonNullElse(order.getOutOfParkingAreaFee(), BigDecimal.ZERO);
dto.setOutOfParkingAreaFee(additionalFee);
} else if (Boolean.TRUE.equals(data.getBikeInNoParking())) {
additionalFee = Objects.requireNonNullElse(order.getNoParkingZoneFee(), BigDecimal.ZERO);
dto.setNoParkingZoneFee(additionalFee);
}
}
// 计算总费用
// 7. 总费用 + 封顶
BigDecimal totalCost = baseCost.add(additionalFee);
// 检查是否超过封顶金额
BigDecimal maxFee = order.getMaxFeeAmount();
if (maxFee != null && totalCost.compareTo(maxFee) > 0) {
totalCost = maxFee;
}
ebikeCostDetailDto.setTotalCost(totalCost);
return ebikeCostDetailDto;
dto.setTotalCost(totalCost);
return dto;
}
/**