增加续租和逾期处理的接口

This commit is contained in:
2025-08-09 23:38:45 +08:00
parent badedc1e9f
commit 134aaaeeb4
9 changed files with 273 additions and 5 deletions

View File

@ -4,4 +4,5 @@ public interface RedisKeyConstants {
String SERVICE_PREFIX = "sczxOrder:";
String ORDER_SUB_KEY = SERVICE_PREFIX + "orderSub:";
}

View File

@ -13,6 +13,7 @@ import lombok.Getter;
public enum OrderStatusEnum {
WAIT_PAY("WAIT_PAY", "待支付"),
WAIT_PICK("WAIT_PICK", "待取车"),
RERENT_WAIT_PAY("RERENT_WAIT_PAY", "续租或逾期待支付"),
RENT_ING("RENT_ING", "租赁中"),
WAIT_RETURN("WAIT_RETURN", "待还车"),
RENT_OVERDUE("RENT_OVERDUE", "逾期"),

View File

@ -11,6 +11,7 @@ import lombok.Getter;
@AllArgsConstructor
@Getter
public enum RentCarTypeEnum {
HOUR_RENTAL("1", "时租"),
DAILY_RENTAL("2", "日租"),
DAYS_RENTAL("3", "按天数租"),
RENT_INSTEAD_SELL("4", "以租代售"),

View File

@ -14,6 +14,7 @@ public enum SubOrderTypeEnum {
DEPOSIT("DEPOSIT", "押金订单"),
RENTCAR("RENTCAR", "租车订单"),
RENTBATTEY("RENTBATTEY", "租电订单"),
OVERDUE("OVERDUE", "逾期订单"),
;
private final String code;

View File

@ -44,6 +44,18 @@ public class ClientOrderController {
return Result.ok(orderService.submitRentCarOrder(rentCarOrderReq));
}
@ApiOperation(value = "续租车")
@PostMapping("/reRentalCarOrder")
public Result<RentCarOrderResultDTO> reRentalCarOrder(@Valid @RequestBody RentCarOrderReq rentCarOrderReq){
return Result.ok(orderService.reRentalCarOrder(rentCarOrderReq));
}
@ApiOperation(value = "逾期处理")
@PostMapping("/overDueRentalCarOrder")
public Result<RentCarOrderResultDTO> overDueRentalCarOrder(@Valid @RequestBody RentCarOrderReq rentCarOrderReq){
return Result.ok(orderService.reRentalCarOrder(rentCarOrderReq));
}
@ApiOperation(value = "申请还车")
@PostMapping("/requestReturnCar")
public Result<OrderDTO> requestReturnCar(@RequestBody ReturnCarReq returnCarReq){

View File

@ -126,7 +126,8 @@ public class OrderDetailDTO {
private Integer overdueDays;
@ApiModelProperty("逾期金额")
private Integer overdueAmount;
private BigDecimal overdueAmount;
@ApiModelProperty("续租次数")
private Integer renewalTimes;

View File

@ -17,6 +17,8 @@ import javax.validation.constraints.NotNull;
@ApiModel(value = "租车订单请求参数")
public class RentCarOrderReq {
@ApiModelProperty(value = "订单编号,租车不需要传,续租和逾期处理需要传")
private String orderNo;
@ApiModelProperty(value = "运营商id")
private Long operatorId;

View File

@ -4,6 +4,9 @@ package com.sczx.order.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.sczx.order.dto.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
public interface OrderService {
/**
@ -13,6 +16,21 @@ public interface OrderService {
*/
RentCarOrderResultDTO submitRentCarOrder(RentCarOrderReq rentCarOrderReq);
/**
* 续租车
* @param rentCarOrderReq
* @return
*/
RentCarOrderResultDTO reRentalCarOrder(RentCarOrderReq rentCarOrderReq);
/**
* 逾期处理
* @param rentCarOrderReq
* @return
*/
RentCarOrderResultDTO overDueRentalCarOrder(RentCarOrderReq rentCarOrderReq);
/**
* 根据订单号查询订单信息
* @param orderNo
@ -27,6 +45,21 @@ public interface OrderService {
*/
OrderDetailDTO getOrderDetailByOrderNo(String orderNo);
/**
* 计算订单逾期天数
* @param endRentTime
* @return
*/
Integer getOrderOverdueDays(LocalDateTime endRentTime);
/**
* 计算逾期金额
* @param overdueDays
* @param overdueFee
* @return
*/
BigDecimal getOrderOverdueAmount(Integer overdueDays, BigDecimal overdueFee);
/**
* 查询用户当前未完成的订单
* @param customerId

View File

@ -33,6 +33,7 @@ import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -103,7 +104,9 @@ public class OrderServiceImpl implements OrderService {
// orderMainPO.setOrderStatus(OrderStatusEnum.WAIT_PAY.getCode());
orderMainPO.setOrderStatus(OrderStatusEnum.WAIT_PICK.getCode());
orderMainPO.setFirstOrderTime(LocalDateTime.now());
if(StringUtils.equalsIgnoreCase(RentCarTypeEnum.DAILY_RENTAL.getCode(), rentCarRuleDTO.getRentalType())){
//设置预计还车时间
if(StringUtils.equalsIgnoreCase(RentCarTypeEnum.DAILY_RENTAL.getCode(), rentCarRuleDTO.getRentalType())
|| StringUtils.equalsIgnoreCase(RentCarTypeEnum.HOUR_RENTAL.getCode(), orderMainPO.getRentalType())){
orderMainPO.setEndRentTime(LocalDateTime.now().plusDays(1));
} else if(StringUtils.equalsIgnoreCase(RentCarTypeEnum.DAYS_RENTAL.getCode(), rentCarRuleDTO.getRentalType())){
orderMainPO.setEndRentTime(LocalDateTime.now().plusDays(rentCarRuleDTO.getRentalDays()));
@ -148,10 +151,16 @@ public class OrderServiceImpl implements OrderService {
orderSubPOList.add(depositOrder);
}
//生成租车订单
BigDecimal rentCarOrderAmount = new BigDecimal(0);
if(RentCarTypeEnum.DAYS_RENTAL.getCode().equalsIgnoreCase(rentCarRuleDTO.getRentalType())){
rentCarOrderAmount = rentCarRuleDTO.getRentalPrice().multiply(new BigDecimal(rentCarRuleDTO.getRentalDays()));
}else {
rentCarOrderAmount = rentCarOrderAmount.add(rentCarRuleDTO.getRentalPrice());
}
OrderSubPO rentOrder = new OrderSubPO();
rentOrder.setSuborderNo(OrderUtil.generateSubOrderNo(OrderUtil.ZC_PREFIX));
rentOrder.setSuborderType(SubOrderTypeEnum.RENTCAR.getCode());
rentOrder.setAmount(orderMainPO.getRentalPrice());
rentOrder.setAmount(rentCarOrderAmount);
rentOrder.setCreatedAt(LocalDateTime.now());
rentOrder.setPaymentMethod(paymentType);
orderSubPOList.add(rentOrder);
@ -190,6 +199,158 @@ public class OrderServiceImpl implements OrderService {
}
}
@Override
public RentCarOrderResultDTO reRentalCarOrder(RentCarOrderReq rentCarOrderReq) {
SimpleUserInfoDTO userInfoDTO = jwtUtil.getUserInfoFromToken();
String redisLockKey = RedisKeyConstants.ORDER_SUB_KEY + userInfoDTO.getUserId();
if(redisUtil.getRedisLock(redisLockKey, "续租")) {
try{
LambdaQueryWrapper<OrderMainPO> currentOrderWrapper = new LambdaQueryWrapper<>();
currentOrderWrapper.eq(OrderMainPO::getOrderNo, rentCarOrderReq.getOrderNo()).last( " limit 1");
OrderMainPO orderMainPO = orderMainRepo.getOne(currentOrderWrapper);
if(orderMainPO == null){
throw new BizException("订单不存在");
}
//生成子表订单
String paymentType;
if(rentCarOrderReq.getIsAutoDeduct()){
if(StringUtils.equalsIgnoreCase(userInfoDTO.getMiniProgramType(), MiniProgramTypeEnum.WECHAT.getType())){
paymentType = PaymentTypeEnum.WX_DQ.getCode();
}else {
paymentType = PaymentTypeEnum.ZFB_DQ.getCode();
}
} else {
if(StringUtils.equalsIgnoreCase(userInfoDTO.getMiniProgramType(), MiniProgramTypeEnum.WECHAT.getType())){
paymentType = PaymentTypeEnum.WX_PAY.getCode();
}else {
paymentType = PaymentTypeEnum.ZFB_PAY.getCode();
}
}
//生成租车订单
BigDecimal rentCarOrderAmount = new BigDecimal(0);
if(RentCarTypeEnum.DAYS_RENTAL.getCode().equalsIgnoreCase(orderMainPO.getRentalType())){
rentCarOrderAmount = orderMainPO.getRentalPrice().multiply(new BigDecimal(orderMainPO.getRentalDays()));
}else {
rentCarOrderAmount = rentCarOrderAmount.add(orderMainPO.getRentalPrice());
}
//生成租车子订单
OrderSubPO rentOrder = new OrderSubPO();
rentOrder.setSuborderNo(OrderUtil.generateSubOrderNo(OrderUtil.ZC_PREFIX));
rentOrder.setSuborderType(SubOrderTypeEnum.RENTCAR.getCode());
rentOrder.setAmount(rentCarOrderAmount);
rentOrder.setCreatedAt(LocalDateTime.now());
rentOrder.setPaymentMethod(paymentType);
orderSubRepo.save(rentOrder);
LocalDateTime oldEndRentTime = orderMainPO.getEndRentTime();
LocalDateTime newEndRentTime = oldEndRentTime;
//刷新预计还车时间
if(StringUtils.equalsIgnoreCase(RentCarTypeEnum.DAILY_RENTAL.getCode(), orderMainPO.getRentalType())
|| StringUtils.equalsIgnoreCase(RentCarTypeEnum.HOUR_RENTAL.getCode(), orderMainPO.getRentalType())){
newEndRentTime = oldEndRentTime.plusDays(1);
} else if(StringUtils.equalsIgnoreCase(RentCarTypeEnum.DAYS_RENTAL.getCode(), orderMainPO.getRentalType())){
orderMainPO.setEndRentTime(LocalDateTime.now().plusDays(orderMainPO.getRentalDays()));
newEndRentTime = oldEndRentTime.plusDays(orderMainPO.getRentalDays());
}
//更新订单状态及信息
LambdaUpdateWrapper<OrderMainPO> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(OrderMainPO::getRenewalTimes, orderMainPO.getRenewalTimes()+1);
updateWrapper.set(OrderMainPO::getEndRentTime, newEndRentTime);
updateWrapper.set(OrderMainPO::getOrderAmount, orderMainPO.getOrderAmount().add(rentCarOrderAmount));
updateWrapper.eq(OrderMainPO::getOrderNo, rentCarOrderReq.getOrderNo());
orderMainRepo.update(updateWrapper);
// TODO 发起支付返回预支付信息
UnifiedPaymentInfoDTO unifiedPaymentInfoDTO = new UnifiedPaymentInfoDTO();
//返回订单信息
OrderDTO orderDTO = getOrderInfoByOrderNo(rentCarOrderReq.getOrderNo());
RentCarOrderResultDTO rentCarOrderResultDTO = new RentCarOrderResultDTO();
rentCarOrderResultDTO.setOrderMainInfo(orderDTO);
rentCarOrderResultDTO.setUnifiedPaymentInfo(unifiedPaymentInfoDTO);
return rentCarOrderResultDTO;
}catch (Exception e){
log.warn("下单失败", e);
throw e;
} finally {
redisUtil.deleteRedisLock(redisLockKey);
}
}else {
log.warn("续租失败,锁已被占用");
throw new InnerException("服务器正在处理,请稍后再试");
}
}
@Override
public RentCarOrderResultDTO overDueRentalCarOrder(RentCarOrderReq rentCarOrderReq) {
SimpleUserInfoDTO userInfoDTO = jwtUtil.getUserInfoFromToken();
String redisLockKey = RedisKeyConstants.ORDER_SUB_KEY + userInfoDTO.getUserId();
if(redisUtil.getRedisLock(redisLockKey, "逾期处理")) {
try{
LambdaQueryWrapper<OrderMainPO> currentOrderWrapper = new LambdaQueryWrapper<>();
currentOrderWrapper.eq(OrderMainPO::getOrderNo, rentCarOrderReq.getOrderNo()).last( " limit 1");
OrderMainPO orderMainPO = orderMainRepo.getOne(currentOrderWrapper);
if(orderMainPO == null){
throw new BizException("订单不存在");
}
//生成子表订单
String paymentType;
if(rentCarOrderReq.getIsAutoDeduct()){
if(StringUtils.equalsIgnoreCase(userInfoDTO.getMiniProgramType(), MiniProgramTypeEnum.WECHAT.getType())){
paymentType = PaymentTypeEnum.WX_DQ.getCode();
}else {
paymentType = PaymentTypeEnum.ZFB_DQ.getCode();
}
} else {
if(StringUtils.equalsIgnoreCase(userInfoDTO.getMiniProgramType(), MiniProgramTypeEnum.WECHAT.getType())){
paymentType = PaymentTypeEnum.WX_PAY.getCode();
}else {
paymentType = PaymentTypeEnum.ZFB_PAY.getCode();
}
}
//生成租车订单
BigDecimal overDueAmount = getOrderOverdueAmount(orderMainPO.getOverdueDays(), orderMainPO.getOverdueFee());
//生成租车子订单
OrderSubPO rentOrder = new OrderSubPO();
rentOrder.setSuborderNo(OrderUtil.generateSubOrderNo(OrderUtil.ZC_PREFIX));
rentOrder.setSuborderType(SubOrderTypeEnum.OVERDUE.getCode());
rentOrder.setAmount(overDueAmount);
rentOrder.setCreatedAt(LocalDateTime.now());
rentOrder.setPaymentMethod(paymentType);
orderSubRepo.save(rentOrder);
//更新订单状态及信息
LambdaUpdateWrapper<OrderMainPO> updateWrapper = new LambdaUpdateWrapper<>();
//TODO 这里应该是支付以后再将状态改为租车中,这里先改为租车中便于演示流程
updateWrapper.set(OrderMainPO::getOrderStatus, OrderStatusEnum.RENT_ING.getCode());
updateWrapper.set(OrderMainPO::getOrderAmount, orderMainPO.getOrderAmount().add(overDueAmount));
updateWrapper.eq(OrderMainPO::getOrderNo, rentCarOrderReq.getOrderNo());
orderMainRepo.update(updateWrapper);
// TODO 发起支付返回预支付信息
UnifiedPaymentInfoDTO unifiedPaymentInfoDTO = new UnifiedPaymentInfoDTO();
//返回订单信息
OrderDTO orderDTO = getOrderInfoByOrderNo(rentCarOrderReq.getOrderNo());
RentCarOrderResultDTO rentCarOrderResultDTO = new RentCarOrderResultDTO();
rentCarOrderResultDTO.setOrderMainInfo(orderDTO);
rentCarOrderResultDTO.setUnifiedPaymentInfo(unifiedPaymentInfoDTO);
return rentCarOrderResultDTO;
}catch (Exception e){
log.warn("下单失败", e);
throw e;
} finally {
redisUtil.deleteRedisLock(redisLockKey);
}
}else {
log.warn("逾期处理失败,锁已被占用");
throw new InnerException("服务器正在处理,请稍后再试");
}
}
@Override
public OrderDTO getOrderInfoByOrderNo(String orderNo) {
LambdaQueryWrapper<OrderMainPO> queryWrapper = new LambdaQueryWrapper<>();
@ -267,9 +428,54 @@ public class OrderServiceImpl implements OrderService {
List<String> orderCarImgList = orderCarImgPOList.stream().map(OrderCarImgPO::getImgUrl).collect(Collectors.toList());
orderDetailDTO.setOrderCarImgList(orderCarImgList);
}
//如果是租车中,需要判断是否逾期了
if(OrderStatusEnum.RENT_ING.getCode().equalsIgnoreCase(orderMainPO.getOrderStatus())){
if(orderMainPO.getEndRentTime()!=null){
Integer overdueDays = getOrderOverdueDays(orderMainPO.getEndRentTime());
//逾期天数>0则改为逾期并且计算逾期天数以及逾期金额
if(overdueDays>0){
orderDetailDTO.setOverdueDays(overdueDays);
orderDetailDTO.setOverdueAmount(getOrderOverdueAmount(overdueDays, orderMainPO.getOverdueFee()));
orderDetailDTO.setOrderStatus(OrderStatusEnum.RENT_OVERDUE.getCode());
LambdaUpdateWrapper<OrderMainPO> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(OrderMainPO::getOrderStatus, OrderStatusEnum.RENT_OVERDUE.getCode());
updateWrapper.set(OrderMainPO::getOverdueDays, overdueDays);
updateWrapper.eq(OrderMainPO::getOrderId, orderMainPO.getOrderId());
orderMainRepo.update(updateWrapper);
}
}
} else if(OrderStatusEnum.RENT_OVERDUE.getCode().equalsIgnoreCase(orderMainPO.getOrderStatus())){
if(orderMainPO.getEndRentTime()!=null){
orderDetailDTO.setOverdueAmount(getOrderOverdueAmount(orderMainPO.getOverdueDays(), orderMainPO.getOverdueFee()));
}
} else if(OrderStatusEnum.WAIT_PAY.getCode().equalsIgnoreCase(orderMainPO.getOrderStatus())||OrderStatusEnum.RERENT_WAIT_PAY.getCode().equalsIgnoreCase(orderMainPO.getOrderStatus())){
//TODO 待支付状态要拉起支付
}
return orderDetailDTO;
}
@Override
public Integer getOrderOverdueDays(LocalDateTime endRentTime) {
if(endRentTime!=null){
LocalDateTime now = LocalDateTime.now();
if(now.isAfter(endRentTime)){
return (int) ChronoUnit.DAYS.between(endRentTime, now);
}
}
return 0;
}
@Override
public BigDecimal getOrderOverdueAmount(Integer overdueDays, BigDecimal overdueFee) {
if(overdueDays!=null&&overdueFee!=null){
BigDecimal overdueDaysBd = new BigDecimal(overdueDays);
return overdueDaysBd.multiply(overdueFee);
}
return null;
}
@Override
public OrderDetailDTO getCurrentNoEndOrder(Long customerId) {
if(customerId==null){
@ -320,10 +526,20 @@ public class OrderServiceImpl implements OrderService {
updateSubWrapper.eq(OrderSubPO::getSuborderId, renOrderSubPO.getSuborderId());
orderSubRepo.update(updateSubWrapper);
//变更订单状态,记录租车时间
LocalDateTime currentTime = LocalDateTime.now();
LocalDateTime endRentTime = null;
//设置预计还车时间
if(StringUtils.equalsIgnoreCase(RentCarTypeEnum.DAILY_RENTAL.getCode(), orderMainPO.getRentalType())){
endRentTime = currentTime.plusDays(1);
} else if(StringUtils.equalsIgnoreCase(RentCarTypeEnum.DAYS_RENTAL.getCode(), orderMainPO.getRentalType())){
endRentTime = currentTime.plusDays(orderMainPO.getRentalDays());
}
LambdaUpdateWrapper<OrderMainPO> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(OrderMainPO::getOrderStatus, OrderStatusEnum.RENT_ING.getCode());
updateWrapper.set(OrderMainPO::getStartRentTime, LocalDateTime.now());
updateWrapper.set(OrderMainPO::getPickCarTime, LocalDateTime.now());
updateWrapper.set(OrderMainPO::getStartRentTime, currentTime);
updateWrapper.set(OrderMainPO::getPickCarTime, currentTime);
updateWrapper.set(endRentTime!=null ,OrderMainPO::getEndRentTime, endRentTime);
updateWrapper.set(OrderMainPO::getVehicleId, carDTO.getId());
updateWrapper.eq(OrderMainPO::getOrderNo, bindCarToOrderReq.getOrderNo());
orderMainRepo.update(updateWrapper);