diff --git a/src/main/java/com/sczx/order/common/constant/RedisKeyConstants.java b/src/main/java/com/sczx/order/common/constant/RedisKeyConstants.java index d9444d0..0a2c4de 100644 --- a/src/main/java/com/sczx/order/common/constant/RedisKeyConstants.java +++ b/src/main/java/com/sczx/order/common/constant/RedisKeyConstants.java @@ -4,4 +4,5 @@ public interface RedisKeyConstants { String SERVICE_PREFIX = "sczxOrder:"; String ORDER_SUB_KEY = SERVICE_PREFIX + "orderSub:"; + } diff --git a/src/main/java/com/sczx/order/common/enums/OrderStatusEnum.java b/src/main/java/com/sczx/order/common/enums/OrderStatusEnum.java index 645da8d..6e4cc60 100644 --- a/src/main/java/com/sczx/order/common/enums/OrderStatusEnum.java +++ b/src/main/java/com/sczx/order/common/enums/OrderStatusEnum.java @@ -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", "逾期"), diff --git a/src/main/java/com/sczx/order/common/enums/RentCarTypeEnum.java b/src/main/java/com/sczx/order/common/enums/RentCarTypeEnum.java index 4fd0b0f..51f17fb 100644 --- a/src/main/java/com/sczx/order/common/enums/RentCarTypeEnum.java +++ b/src/main/java/com/sczx/order/common/enums/RentCarTypeEnum.java @@ -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", "以租代售"), diff --git a/src/main/java/com/sczx/order/common/enums/SubOrderTypeEnum.java b/src/main/java/com/sczx/order/common/enums/SubOrderTypeEnum.java index 559e643..633cb27 100644 --- a/src/main/java/com/sczx/order/common/enums/SubOrderTypeEnum.java +++ b/src/main/java/com/sczx/order/common/enums/SubOrderTypeEnum.java @@ -14,6 +14,7 @@ public enum SubOrderTypeEnum { DEPOSIT("DEPOSIT", "押金订单"), RENTCAR("RENTCAR", "租车订单"), RENTBATTEY("RENTBATTEY", "租电订单"), + OVERDUE("OVERDUE", "逾期订单"), ; private final String code; diff --git a/src/main/java/com/sczx/order/controller/ClientOrderController.java b/src/main/java/com/sczx/order/controller/ClientOrderController.java index dfea5f8..5aad729 100644 --- a/src/main/java/com/sczx/order/controller/ClientOrderController.java +++ b/src/main/java/com/sczx/order/controller/ClientOrderController.java @@ -44,6 +44,18 @@ public class ClientOrderController { return Result.ok(orderService.submitRentCarOrder(rentCarOrderReq)); } + @ApiOperation(value = "续租车") + @PostMapping("/reRentalCarOrder") + public Result reRentalCarOrder(@Valid @RequestBody RentCarOrderReq rentCarOrderReq){ + return Result.ok(orderService.reRentalCarOrder(rentCarOrderReq)); + } + + @ApiOperation(value = "逾期处理") + @PostMapping("/overDueRentalCarOrder") + public Result overDueRentalCarOrder(@Valid @RequestBody RentCarOrderReq rentCarOrderReq){ + return Result.ok(orderService.reRentalCarOrder(rentCarOrderReq)); + } + @ApiOperation(value = "申请还车") @PostMapping("/requestReturnCar") public Result requestReturnCar(@RequestBody ReturnCarReq returnCarReq){ diff --git a/src/main/java/com/sczx/order/dto/OrderDetailDTO.java b/src/main/java/com/sczx/order/dto/OrderDetailDTO.java index 4a2a4a6..87ab602 100644 --- a/src/main/java/com/sczx/order/dto/OrderDetailDTO.java +++ b/src/main/java/com/sczx/order/dto/OrderDetailDTO.java @@ -126,7 +126,8 @@ public class OrderDetailDTO { private Integer overdueDays; @ApiModelProperty("逾期金额") - private Integer overdueAmount; + private BigDecimal overdueAmount; + @ApiModelProperty("续租次数") private Integer renewalTimes; diff --git a/src/main/java/com/sczx/order/dto/RentCarOrderReq.java b/src/main/java/com/sczx/order/dto/RentCarOrderReq.java index 4748f73..c576915 100644 --- a/src/main/java/com/sczx/order/dto/RentCarOrderReq.java +++ b/src/main/java/com/sczx/order/dto/RentCarOrderReq.java @@ -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; diff --git a/src/main/java/com/sczx/order/service/OrderService.java b/src/main/java/com/sczx/order/service/OrderService.java index 06826d4..8a4971a 100644 --- a/src/main/java/com/sczx/order/service/OrderService.java +++ b/src/main/java/com/sczx/order/service/OrderService.java @@ -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 diff --git a/src/main/java/com/sczx/order/service/impl/OrderServiceImpl.java b/src/main/java/com/sczx/order/service/impl/OrderServiceImpl.java index 47951d3..28af612 100644 --- a/src/main/java/com/sczx/order/service/impl/OrderServiceImpl.java +++ b/src/main/java/com/sczx/order/service/impl/OrderServiceImpl.java @@ -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 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 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 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 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 queryWrapper = new LambdaQueryWrapper<>(); @@ -267,9 +428,54 @@ public class OrderServiceImpl implements OrderService { List 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 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 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);