订单生成明细

This commit is contained in:
yanglei 2026-01-15 13:38:35 +08:00
parent 5ac51606d9
commit fab86d8bab
5 changed files with 348 additions and 21 deletions

View File

@ -8,6 +8,7 @@ import com.cdzy.user.model.dto.EbikeUserCyclingDto;
import com.cdzy.user.model.dto.EbikeUserCyclingEndDto;
import com.cdzy.user.model.entity.EbikeOrder;
import com.cdzy.user.model.vo.EbikeBikeInfoVo;
import com.cdzy.user.model.vo.EbikeOrderDetailVo;
import com.cdzy.user.model.vo.EbikeRevenueStatisticsVo;
import com.cdzy.user.model.vo.EbikeUserAllOrdersVo;
import com.cdzy.user.service.EbikeOrderService;
@ -107,7 +108,7 @@ public class EbikeOrderController {
*/
@GetMapping("getInfo")
public JsonResult<?> getInfo(@RequestParam("orderId") Long orderId) {
EbikeOrder userOrder = ebikeOrderService.getById(orderId);
EbikeOrderDetailVo userOrder = ebikeOrderService.getInfo(orderId);
return JsonResult.success(userOrder);
}

View File

@ -0,0 +1,56 @@
package com.cdzy.user.model.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* @author yanglei
* @since 2026-01-15 10:52
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EbikeCostDetailDto implements Serializable {
/**
* 起步费用
*/
private BigDecimal baseFee;
/**
* 时长费用
*/
private BigDecimal durationFee;
/**
* 禁停区调度费)
*/
private BigDecimal noParkingZoneFee;
/**
* 停车区外调度费
*/
private BigDecimal outOfParkingAreaFee;
/**
* 运营区域外调度费
*/
private BigDecimal outOfServiceAreaFee;
/**
* 头盔管理费)
*/
private BigDecimal helmetManagementFee;
/**
* 总计费用
*/
private BigDecimal totalCost;
}

View File

@ -0,0 +1,180 @@
package com.cdzy.user.model.vo;
import com.cdzy.user.handler.PointDeserializer;
import com.cdzy.user.handler.PointSerializer;
import com.cdzy.user.handler.PointTypeHandler;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.mybatisflex.annotation.Column;
import lombok.Data;
import org.locationtech.jts.geom.Point;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* @author yanglei
* @since 2026-01-15 11:18
*/
@Data
public class EbikeOrderDetailVo {
/**
* 订单表主键ID
*/
private Long orderId;
/**
* 用户ID关联用户表
*/
private Long userId;
/**
* 运营商ID
*/
private Long operatorId;
/**
* 车辆编码
*/
private String bikeCode;
/**
* 订单类型1-单次骑行 2-骑行卡购买 3-会员卡续费
*/
private Integer orderType;
/**
* 订单状态0-进行中 1-已取消 2-待支付 3-已支付 4-退款中 5-已退款
*/
@Column(onInsertValue = "0")
private Integer orderStatus;
/**
* 订单总金额单位
*/
private BigDecimal totalAmount;
/**
* 实付金额扣除卡券优惠后
*/
private BigDecimal actualAmount;
/**
* 骑行开始时间仅骑行订单有效
*/
private LocalDateTime startTime;
/**
* 骑行结束时间仅骑行订单有效
*/
private LocalDateTime endTime;
/**
* 支付成功时间
*/
private LocalDateTime paymentTime;
/**
* 支付方式1-wechat 2-alipay 3-balance
*/
private Integer paymentMethod;
/**
* 起步时长分钟
*/
private Integer baseDurationMinutes;
/**
* 起步费用
*/
private BigDecimal baseFee;
/**
* 时长费用
*/
private BigDecimal durationFee;
/**
* 免费时长分钟
*/
private Integer freeDurationMinutes;
/**
* 时长分钟
*/
private Integer chargeDurationMinutes;
/**
* 禁停区调度费)
*/
private BigDecimal noParkingZoneFee;
/**
* 停车区外调度费
*/
private BigDecimal outOfParkingAreaFee;
/**
* 运营区域外调度费
*/
private BigDecimal outOfServiceAreaFee;
/**
* 封顶金额)
*/
private BigDecimal maxFeeAmount;
/**
* 头盔管理费)
*/
private BigDecimal helmetManagementFee;
/**
* 骑行起始点
*/
@Column(typeHandler = PointTypeHandler.class)
@JsonSerialize(using = PointSerializer.class)
@JsonDeserialize(using = PointDeserializer.class)
private Point startLocation;
/**
* 骑行结束点
*/
@Column(typeHandler = PointTypeHandler.class)
@JsonSerialize(using = PointSerializer.class)
@JsonDeserialize(using = PointDeserializer.class)
private Point endLocation;
/**
* 创建人
*/
private Long createBy;
/**
* 创建时间
*/
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
/**
* 更新人
*/
private Long updateBy;
/**
* 更新时间
*/
@Column(onUpdateValue = "now()")
private LocalDateTime updateTime;
/**
* 删除状态true表示已删除
*/
private Boolean isDeleted;
/**
* 是否免费订单 true-免费 false-收费
*/
private Boolean isFreeOrder;
}

View File

@ -5,6 +5,7 @@ import com.cdzy.user.model.dto.EbikeUserCyclingDto;
import com.cdzy.user.model.dto.EbikeUserCyclingEndDto;
import com.cdzy.user.model.entity.EbikeOrder;
import com.cdzy.user.model.vo.EbikeBikeInfoVo;
import com.cdzy.user.model.vo.EbikeOrderDetailVo;
import com.cdzy.user.model.vo.EbikeRevenueStatisticsVo;
import com.cdzy.user.model.vo.EbikeUserAllOrdersVo;
import com.ebike.feign.model.dto.FeignEbikeDto;
@ -105,4 +106,11 @@ public interface EbikeOrderService extends IService<EbikeOrder> {
* @return 营收统计
*/
List<EbikeRevenueStatisticsVo> getRevenueStatistics();
/**
* 根据订单id查看订单详情
* @param orderId 订单id
* @return 订单详情
*/
EbikeOrderDetailVo getInfo(Long orderId);
}

View File

@ -5,14 +5,21 @@ import com.cdzy.common.enums.GlobalConstants;
import com.cdzy.common.ex.EbikeException;
import com.cdzy.common.model.request.PageParam;
import com.cdzy.common.model.response.JsonResult;
import com.cdzy.user.enums.*;
import com.cdzy.user.enums.EbikeOrderDetailType;
import com.cdzy.user.enums.EbikePaymentMethod;
import com.cdzy.user.enums.EbikePaymentTradeStatus;
import com.cdzy.user.enums.OrderStatus;
import com.cdzy.user.enums.OrderType;
import com.cdzy.user.mapper.EbikeOrderMapper;
import com.cdzy.user.model.dto.EbikeCostDetailDto;
import com.cdzy.user.model.dto.EbikeUserCyclingDto;
import com.cdzy.user.model.dto.EbikeUserCyclingEndDto;
import com.cdzy.user.model.entity.EbikeOrder;
import com.cdzy.user.model.entity.EbikeOrderDetail;
import com.cdzy.user.model.entity.EbikePayment;
import com.cdzy.user.model.vo.EbikeBikeInfoVo;
import com.cdzy.user.model.vo.EbikeOrderDetailVo;
import com.cdzy.user.model.vo.EbikePaymentCostDetailVo;
import com.cdzy.user.model.vo.EbikeRevenueStatisticsVo;
import com.cdzy.user.model.vo.EbikeUserAllOrdersVo;
import com.cdzy.user.service.EbikeOrderDetailService;
@ -42,6 +49,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import static com.cdzy.user.model.entity.table.EbikeOrderDetailTableDef.EBIKE_ORDER_DETAIL;
import static com.cdzy.user.model.entity.table.EbikeOrderTableDef.EBIKE_ORDER;
import static com.cdzy.user.model.entity.table.EbikeRefundTableDef.EBIKE_REFUND;
@ -221,7 +229,9 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
}
FeignEbikeUserLockDto data = jsonResult.getData();
// 订单费用计算
BigDecimal totalAmount = costCalculation(order.getEndTime(), order, data);
EbikeCostDetailDto ebikeCostDetail = costCalculation(order.getEndTime(), order, data);
// 获取总费用
BigDecimal totalAmount = ebikeCostDetail.getTotalCost();
// 费用为0不生成支付订单直接订单已支付返回订单id
if (totalAmount.compareTo(BigDecimal.ZERO) == 0) {
order.setPaymentTime(LocalDateTime.now());
@ -251,7 +261,7 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
.build();
ebikePaymentService.save(payment);
// 保存计算订单详情
List<EbikeOrderDetail> orderDetails = buildOrderDetails(order);
List<EbikeOrderDetail> orderDetails = buildOrderDetails(order, ebikeCostDetail);
ebikeOrderDetailService.saveBatch(orderDetails);
return order.getOrderId();
}
@ -296,6 +306,68 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
return list;
}
@Override
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
)
.where(EBIKE_ORDER.ORDER_ID.eq(orderId));
EbikeOrderDetailVo ebikeOrderDetailVo = this.mapper.selectOneByQueryAs(queryWrapper, EbikeOrderDetailVo.class);
//获取费用详情
List<EbikePaymentCostDetailVo> details = ebikeOrderDetailService.getOrderDetailsByOrderId(orderId);
if (Objects.nonNull(details)) {
for (EbikePaymentCostDetailVo payDetailVo : details) {
//1-时长费用 2-起步费用 3-运营区调度费用 4-停车区外调度费用 5-禁停区调度费用 6-头盔使用费用
switch (payDetailVo.getDetailType()) {
case 1 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setDurationFee((current != null ? current : BigDecimal.ZERO));
}
case 2 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setBaseFee((current != null ? current : BigDecimal.ZERO));
}
case 3 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setOutOfServiceAreaFee((current != null ? current : BigDecimal.ZERO));
}
case 4 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setOutOfParkingAreaFee((current != null ? current : BigDecimal.ZERO));
}
case 5 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setNoParkingZoneFee((current != null ? current : BigDecimal.ZERO));
}
case 6 -> {
BigDecimal current = payDetailVo.getDetailAmount();
ebikeOrderDetailVo.setHelmetManagementFee((current != null ? current : BigDecimal.ZERO));
}
}
}
}
return ebikeOrderDetailVo;
}
/**
* 计算增长率并格式化为百分比字符串
*
@ -325,39 +397,39 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
}
private List<EbikeOrderDetail> buildOrderDetails(EbikeOrder order) {
private List<EbikeOrderDetail> buildOrderDetails(EbikeOrder order, EbikeCostDetailDto ebikeCostDetail) {
List<EbikeOrderDetail> details = new ArrayList<>();
//时长费用
if (order.getDurationFee() != null && order.getDurationFee().compareTo(BigDecimal.ZERO) > 0) {
details.add(buildDetail(order, EbikeOrderDetailType.DURATION_FEE, order.getDurationFee(), "骑行时长费用"));
if (ebikeCostDetail.getDurationFee() != null && ebikeCostDetail.getDurationFee().compareTo(BigDecimal.ZERO) > 0) {
details.add(buildDetail(order, EbikeOrderDetailType.DURATION_FEE, ebikeCostDetail.getDurationFee(), "骑行时长费用"));
}
// 起步费用
if (order.getBaseFee() != null && order.getBaseFee().compareTo(BigDecimal.ZERO) > 0) {
details.add(buildDetail(order, EbikeOrderDetailType.STARTUP_FEE, order.getBaseFee(), "起步费用"));
if (ebikeCostDetail.getBaseFee() != null && ebikeCostDetail.getBaseFee().compareTo(BigDecimal.ZERO) > 0) {
details.add(buildDetail(order, EbikeOrderDetailType.STARTUP_FEE, ebikeCostDetail.getBaseFee(), "起步费用"));
}
if (order.getOutOfServiceAreaFee() != null && order.getOutOfServiceAreaFee().compareTo(BigDecimal.ZERO) > 0) {
if (ebikeCostDetail.getOutOfServiceAreaFee() != null && ebikeCostDetail.getOutOfServiceAreaFee().compareTo(BigDecimal.ZERO) > 0) {
details.add(buildDetail(order, EbikeOrderDetailType.OPERATION_AREA_DISPATCH_FEE,
order.getOutOfServiceAreaFee(), "运营区外调度费"));
ebikeCostDetail.getOutOfServiceAreaFee(), "运营区外调度费"));
}
// 4. 停车区外调度费用
if (order.getOutOfParkingAreaFee() != null && order.getOutOfParkingAreaFee().compareTo(BigDecimal.ZERO) > 0) {
if (ebikeCostDetail.getOutOfParkingAreaFee() != null && ebikeCostDetail.getOutOfParkingAreaFee().compareTo(BigDecimal.ZERO) > 0) {
details.add(buildDetail(order, EbikeOrderDetailType.OUT_OF_PARKING_AREA_FEE,
order.getOutOfParkingAreaFee(), "停车区外调度费"));
ebikeCostDetail.getOutOfParkingAreaFee(), "停车区外调度费"));
}
// 5. 禁停区调度费用
if (order.getNoParkingZoneFee() != null && order.getNoParkingZoneFee().compareTo(BigDecimal.ZERO) > 0) {
if (ebikeCostDetail.getNoParkingZoneFee() != null && ebikeCostDetail.getNoParkingZoneFee().compareTo(BigDecimal.ZERO) > 0) {
details.add(buildDetail(order, EbikeOrderDetailType.NO_PARKING_ZONE_FEE,
order.getNoParkingZoneFee(), "禁停区调度费"));
ebikeCostDetail.getNoParkingZoneFee(), "禁停区调度费"));
}
// 6. 头盔使用费用
if (order.getHelmetManagementFee() != null && order.getHelmetManagementFee().compareTo(BigDecimal.ZERO) > 0) {
if (ebikeCostDetail.getHelmetManagementFee() != null && ebikeCostDetail.getHelmetManagementFee().compareTo(BigDecimal.ZERO) > 0) {
details.add(buildDetail(order, EbikeOrderDetailType.HELMET_FEE,
order.getHelmetManagementFee(), "头盔使用费"));
ebikeCostDetail.getHelmetManagementFee(), "头盔使用费"));
}
return details;
}
@ -386,8 +458,8 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
* @param data 是否在停车区
* @return 订单费用
*/
private BigDecimal costCalculation(LocalDateTime endTime,
EbikeOrder order, FeignEbikeUserLockDto data) {
private EbikeCostDetailDto costCalculation(LocalDateTime endTime,
EbikeOrder order, FeignEbikeUserLockDto data) {
// 基础费用计算
BigDecimal baseFee = Objects.requireNonNullElse(order.getBaseFee(), BigDecimal.ZERO);
BigDecimal durationFee = Objects.requireNonNullElse(order.getDurationFee(), BigDecimal.ZERO);
@ -399,14 +471,20 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
long freeDurationSeconds = freeDurationMinutes * GlobalConstants.LONG_SIXTY;
// 如果骑行时长小于等于免费时长,不收费
BigDecimal baseCost;
EbikeCostDetailDto ebikeCostDetailDto = new EbikeCostDetailDto();
// 起步费用
ebikeCostDetailDto.setBaseFee(baseFee);
if (totalRideSeconds <= freeDurationSeconds) {
return BigDecimal.ZERO;
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);
}
@ -416,12 +494,15 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
// 运营区
if (Boolean.FALSE.equals(data.getBikeInRegion())) {
additionalFee = order.getOutOfServiceAreaFee() != null ? order.getOutOfServiceAreaFee() : BigDecimal.ZERO;
ebikeCostDetailDto.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);
}
}
// 计算总费用
@ -431,7 +512,8 @@ public class EbikeOrderServiceImpl extends ServiceImpl<EbikeOrderMapper, EbikeOr
if (maxFee != null && totalCost.compareTo(maxFee) > 0) {
totalCost = maxFee;
}
return totalCost;
ebikeCostDetailDto.setTotalCost(totalCost);
return ebikeCostDetailDto;
}
/**