Compare commits

...

5 Commits

Author SHA1 Message Date
90559cff06 免押下单和免押支付 2025-09-26 18:20:44 +08:00
b07726c866 Merge branch 'main' into zhangli/2025-9-26_my 2025-09-26 16:51:14 +08:00
c55b433bcc 冻结 2025-09-26 15:23:53 +08:00
9c4113cb43 Merge branch 'main' into zhangli/2025-9-26_my 2025-09-26 15:17:21 +08:00
1330b8cb68 免押接口实现 2025-09-26 14:26:11 +08:00
7 changed files with 253 additions and 6 deletions

View File

@ -53,6 +53,18 @@ public class ClientOrderController {
return Result.ok(orderService.submitRentCarOrder(rentCarOrderReq));
}
@ApiOperation(value = "免押生成租车订单")
@PostMapping("/depositFreeSubmitRentCarOrder")
public Result<RentCarOrderResultDTO> depositFreeSubmitRentCarOrder(@Valid @RequestBody RentCarOrderReq rentCarOrderReq){
return Result.ok(orderService.depositFreeSubmitRentCarOrder(rentCarOrderReq));
}
@ApiOperation(value = "免押支付")
@PostMapping("/depositFreePayRentCarOrder")
public Result<RentCarOrderResultDTO> depositFreePayRentCarOrder(@Valid @RequestBody RentCarOrderReq rentCarOrderReq){
return Result.ok(orderService.depositFreePayRentCarOrder(rentCarOrderReq));
}
@ApiOperation(value = "续租车")
@PostMapping("/reRentalCarOrder")
public Result<RentCarOrderResultDTO> reRentalCarOrder(@Valid @RequestBody ReRentCarReq rentCarOrderReq){

View File

@ -74,6 +74,9 @@ public class OrderSubPO implements Serializable {
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("平台流水号")
private String transactionId;
@ApiModelProperty("删除标志0代表存在 2代表删除")
private String delFlag;

View File

@ -29,6 +29,13 @@ public interface OrderService {
*/
RentCarOrderResultDTO depositFreeSubmitRentCarOrder(RentCarOrderReq rentCarOrderReq);
/**
* 免押支付
* @param rentCarOrderReq
* @return
*/
RentCarOrderResultDTO depositFreePayRentCarOrder(RentCarOrderReq rentCarOrderReq);
/**
* 续租车
* @param rentCarOrderReq

View File

@ -28,4 +28,14 @@ public interface PayService {
* @param refundFee
*/
String refundOrder(String payType,Long companyId,String outTradeNo, BigDecimal totalFee, BigDecimal refundFee);
/**
* 冻结
* @param companyId
* @param outOrderNo
* @param freezeFee
* @return
*/
UnifiedPaymentInfoDTO freezeOrder(Long companyId,String outOrderNo, BigDecimal freezeFee);
}

View File

@ -19,6 +19,7 @@ import com.sczx.order.service.PayService;
import com.sczx.order.thirdpart.dto.*;
import com.sczx.order.thirdpart.dto.req.AlipayCloseRequest;
import com.sczx.order.thirdpart.dto.req.AlipayFundFreezeRequest;
import com.sczx.order.thirdpart.dto.req.AlipayQueryFreezeRequest;
import com.sczx.order.thirdpart.dto.req.CarQueryConditionReq;
import com.sczx.order.thirdpart.integration.CarInteg;
import com.sczx.order.thirdpart.integration.PayInteg;
@ -239,8 +240,208 @@ public class OrderServiceImpl implements OrderService {
@Override
public RentCarOrderResultDTO depositFreeSubmitRentCarOrder(RentCarOrderReq rentCarOrderReq) {
//TODO - 免押冻结
return null;
log.info("开始发起免押 : {}", rentCarOrderReq);
SimpleUserInfoDTO userInfoDTO = jwtUtil.getUserInfoFromToken();
if(!(rentCarOrderReq.getIsDepositFree() && StringUtils.equalsIgnoreCase(userInfoDTO.getMiniProgramType(), MiniProgramTypeEnum.ALIPAY.getType()))){
throw new BizException("不满足支付宝免押条件");
}
String redisLockKey = RedisKeyConstants.ORDER_SUB_KEY + userInfoDTO.getUserId();
if(redisUtil.getRedisLock(redisLockKey, "租车下单")) {
try{
//判断是否还有未完成的订单
LambdaQueryWrapper<OrderMainPO> currentOrderWrapper = new LambdaQueryWrapper<>();
currentOrderWrapper.eq(OrderMainPO::getCustomerId, userInfoDTO.getUserId())
.notIn(OrderMainPO::getOrderStatus, Arrays.asList(OrderStatusEnum.AUTO_END.getCode(), OrderStatusEnum.MANUAL_END.getCode()))
.eq(OrderMainPO::getDelFlag, "0");
List<OrderMainPO> currentOrderList = orderMainRepo.list(currentOrderWrapper);
OrderMainPO waitPayOrder = currentOrderList.stream().filter(order -> order.getOrderStatus().equals(OrderStatusEnum.WAIT_PAY.getCode())).findFirst().orElse(null);
if(!currentOrderList.isEmpty() && waitPayOrder==null){
throw new BizException("您有未完成的订单,请先完成订单");
}
if(waitPayOrder!=null){
log.info("存在待支付的订单,取消订单");
PayOrderReq payOrderReq = new PayOrderReq();
payOrderReq.setOrderNo(waitPayOrder.getOrderNo());
cancelOrder(payOrderReq);
}
//判断是否存有空闲车辆可用
LambdaQueryWrapper<CarPO> carWrapper = new LambdaQueryWrapper<>();
carWrapper.eq(CarPO::getModelId, rentCarOrderReq.getCarModelId())
.eq(CarPO::getDelFlag, "0")
.eq(CarPO::getBrsStatus, "0")
.eq(CarPO::getStoreId, rentCarOrderReq.getStoreId());
List<CarPO> carPOList = carRepo.list(carWrapper);
if(CollectionUtils.isEmpty(carPOList)){
throw new BizException("门店没有该车型的车辆可租");
}
//获取门店信息
CompanyStoreDTO companyStoreDTO = storeInteg.getStoreById(Integer.valueOf(rentCarOrderReq.getStoreId().toString()));
CarModelSimpleDTO carModelSimpleDTO = carInteg.getCarModelByModelId(rentCarOrderReq.getCarModelId());
RentCarRuleDTO rentCarRuleDTO = carInteg.getRentCarRuleByCarRuleId(rentCarOrderReq.getRentCarRuleId());
RentBatteyRuleDTO rentBatteyRuleDTO = null;
if(rentCarOrderReq.getRentBatteyRuleId()!=null){
rentBatteyRuleDTO = carInteg.getRentBatteyRuleByBatteyRuleId(rentCarOrderReq.getRentBatteyRuleId());
}
//生成订单主表
OrderMainPO orderMainPO = OrderConvert.INSTANCE.subOrderToPo(rentCarOrderReq, userInfoDTO, rentCarRuleDTO);
orderMainPO.setOperatorId(Long.valueOf(companyStoreDTO.getOperatingCompanyId()));
orderMainPO.setOrderNo(OrderUtil.generateOrderNo());
orderMainPO.setOrderStatus(OrderStatusEnum.WAIT_PAY.getCode());
orderMainPO.setFirstOrderTime(LocalDateTime.now());
//设置预计还车时间
LocalDateTime endRentTime = OrderUtil.getEndRentTime(orderMainPO.getFirstOrderTime(),1,rentCarRuleDTO.getRentalDays(), rentCarRuleDTO.getRentalType());
orderMainPO.setEndRentTime(endRentTime);
//生成子表订单
String paymentType = PaymentTypeEnum.ZFB_PAY.getCode();
List<OrderSubPO> orderSubPOList = new ArrayList<>();
//生成免押订单
OrderSubPO noDepositOrder = new OrderSubPO();
noDepositOrder.setSuborderNo(OrderUtil.generateSubOrderNo(OrderUtil.MY_PREFIX));
noDepositOrder.setPaymentId(OrderUtil.generateSubOrderNo(OrderUtil.FZ_PREFIX));
noDepositOrder.setSuborderType(SubOrderTypeEnum.NO_DEPOSIT.getCode());
noDepositOrder.setAmount(orderMainPO.getDepositPrice());
noDepositOrder.setCreatedAt(LocalDateTime.now());
noDepositOrder.setPaymentMethod(paymentType);
noDepositOrder.setPayStatus(PayStatusEnum.USERPAYING.getCode());
orderSubPOList.add(noDepositOrder);
String paymentId = OrderUtil.generateSubOrderNo(OrderUtil.ZF_PREFIX);
//如果选择了租电套餐,则还需要生成租电子订单
if(rentBatteyRuleDTO!=null){
rentBatteyRuleDTO = carInteg.getRentBatteyRuleByBatteyRuleId(rentCarOrderReq.getRentBatteyRuleId());
OrderSubPO rentBatteyRuleOrder = new OrderSubPO();
rentBatteyRuleOrder.setSuborderNo(OrderUtil.generateSubOrderNo(OrderUtil.ZD_PREFIX));
rentBatteyRuleOrder.setSuborderType(SubOrderTypeEnum.RENTBATTEY.getCode());
rentBatteyRuleOrder.setAmount(rentBatteyRuleDTO.getRentPrice());
rentBatteyRuleOrder.setCreatedAt(LocalDateTime.now());
rentBatteyRuleOrder.setPaymentMethod(paymentType);
rentBatteyRuleOrder.setPayStatus(PayStatusEnum.INIT.getCode());
rentBatteyRuleOrder.setPaymentId(paymentId);
orderSubPOList.add(rentBatteyRuleOrder);
}
//生成租车订单
BigDecimal rentCarOrderAmount = OrderUtil.getRentCarAmount(rentCarRuleDTO.getRentalType(), rentCarRuleDTO.getRentalPrice(), rentCarRuleDTO.getRentalDays());
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);
rentOrder.setReturnTime(endRentTime);
rentOrder.setPayStatus(PayStatusEnum.INIT.getCode());
rentOrder.setPaymentId(paymentId);
orderSubPOList.add(rentOrder);
//计算订单金额除开免押订单的金额
BigDecimal orderAmount = orderSubPOList.stream().filter(x->!StringUtils.equalsIgnoreCase(x.getSuborderType(),SubOrderTypeEnum.NO_DEPOSIT.getCode())).map(OrderSubPO::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
orderMainPO.setOrderAmount(orderAmount);
//发起支付返回预支付信息
UnifiedPaymentInfoDTO unifiedPaymentInfoDTO = payService.freezeOrder(Long.valueOf(companyStoreDTO.getOperatingCompanyId()),noDepositOrder.getPaymentId(),noDepositOrder.getAmount());
//保存订单
orderMainRepo.save(orderMainPO);
orderSubPOList.forEach(orderSubPO -> {
orderSubPO.setOrderId(orderMainPO.getOrderId());
});
orderSubRepo.saveBatch(orderSubPOList);
//返回订单信息
OrderDTO orderDTO = OrderConvert.INSTANCE.poToDto(orderMainPO);
orderDTO.setCompanyStoreDTO(companyStoreDTO);
orderDTO.setCarModelSimpleDTO(carModelSimpleDTO);
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 depositFreePayRentCarOrder(RentCarOrderReq rentCarOrderReq) {
SimpleUserInfoDTO userInfoDTO = jwtUtil.getUserInfoFromToken();
OrderMainPO orderMainPO = queryOrderMainPoByOrderNo(rentCarOrderReq.getOrderNo(), "0");
if(orderMainPO == null || OrderStatusEnum.WAIT_PAY.getCode().equals(orderMainPO.getOrderStatus())){
throw new BizException("订单不存在或订单状态不正确");
}
LambdaQueryWrapper<OrderSubPO> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(OrderSubPO::getOrderId, orderMainPO.getOrderId()).eq(OrderSubPO::getDelFlag, "0");
List<OrderSubPO> orderSubPOList = orderSubRepo.list(queryWrapper);
OrderSubPO noDepositOrder = orderSubPOList.stream().filter(x->StringUtils.equalsIgnoreCase(x.getSuborderType(),SubOrderTypeEnum.NO_DEPOSIT.getCode())).findFirst().orElse(null);
if(noDepositOrder == null){
throw new BizException("未做免押,支付失败");
}
String redisLockKey = RedisKeyConstants.ORDER_SUB_KEY + userInfoDTO.getUserId();
if(redisUtil.getRedisLock(redisLockKey, "免押支付")) {
try{
if(PayStatusEnum.USERPAYING.getCode().equals(noDepositOrder.getPayStatus())){
log.info("查询支付宝冻结订单结果,并更新状态");
AlipayQueryFreezeRequest alipayQueryFreezeRequest = new AlipayQueryFreezeRequest();
alipayQueryFreezeRequest.setOutOrderNo(noDepositOrder.getPaymentId());
alipayQueryFreezeRequest.setOperationType("FREEZE");
alipayQueryFreezeRequest.setCompanyId(orderMainPO.getOperatorId().toString());
AlipayQueryFreezeResponse queryFreezeResponse = payInteg.queryFundFreeze(alipayQueryFreezeRequest);
LambdaUpdateWrapper<OrderSubPO> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(OrderSubPO::getSuborderId, noDepositOrder.getSuborderId())
.set(OrderSubPO::getPayStatus, PayStatusEnum.SUCCESS.getCode())
.set(OrderSubPO::getTransactionId, queryFreezeResponse.getAuthNo());
orderSubRepo.update(updateWrapper);
}
OrderSubPO rentCarOrder = orderSubPOList.stream().filter(x->StringUtils.equalsIgnoreCase(x.getSuborderType(),SubOrderTypeEnum.RENTCAR.getCode())).findFirst().orElse(null);
if(rentCarOrder == null){
throw new BizException("无租车待支付单,支付失败");
}
//开始发起支付
UnifiedPaymentInfoDTO unifiedPaymentInfoDTO = payService.prepayOrder(rentCarOrder.getPaymentMethod(),orderMainPO.getRentCarRuleId().toString(),orderMainPO.getOperatorId(),rentCarOrder.getPaymentId(),userInfoDTO
,orderMainPO.getOrderAmount());
LambdaUpdateWrapper<OrderSubPO> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(OrderSubPO::getSuborderId, noDepositOrder.getSuborderId())
.eq(OrderSubPO::getDelFlag, "0")
.in(OrderSubPO::getSuborderType, Arrays.asList(SubOrderTypeEnum.RENTCAR.getCode(), SubOrderTypeEnum.RENTBATTEY.getCode()))
.in(OrderSubPO::getPayStatus, PayStatusEnum.INIT.getCode())
.set(OrderSubPO::getPayStatus, PayStatusEnum.USERPAYING.getCode());
orderSubRepo.update(updateWrapper);
//返回订单信息
OrderDTO orderDTO = OrderConvert.INSTANCE.poToDto(orderMainPO);
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("免押支付失败,请稍后再试");
}
}

View File

@ -3,11 +3,9 @@ package com.sczx.order.service.impl;
import com.sczx.order.common.enums.PaymentTypeEnum;
import com.sczx.order.dto.SimpleUserInfoDTO;
import com.sczx.order.service.PayService;
import com.sczx.order.thirdpart.dto.AlipayFundFreezeResponse;
import com.sczx.order.thirdpart.dto.UnifiedPaymentInfoDTO;
import com.sczx.order.thirdpart.dto.req.AlipayCreateRequest;
import com.sczx.order.thirdpart.dto.req.AlipayRefundRequest;
import com.sczx.order.thirdpart.dto.req.PaymentRequest;
import com.sczx.order.thirdpart.dto.req.RefundRequest;
import com.sczx.order.thirdpart.dto.req.*;
import com.sczx.order.thirdpart.integration.PayInteg;
import com.sczx.order.utils.OrderUtil;
import lombok.extern.slf4j.Slf4j;
@ -89,4 +87,17 @@ public class PayServiceImpl implements PayService {
}
return null;
}
@Override
public UnifiedPaymentInfoDTO freezeOrder(Long companyId, String outOrderNo, BigDecimal freezeFee) {
AlipayFundFreezeRequest request = new AlipayFundFreezeRequest();
request.setCompanyId(companyId.toString());
request.setOutOrderNo(outOrderNo);
request.setTitle("租车免押");
request.setAmount(freezeFee.toString());
AlipayFundFreezeResponse result = payInteg.fundFreeze(request);
UnifiedPaymentInfoDTO unifiedPaymentInfoDTO = new UnifiedPaymentInfoDTO();
unifiedPaymentInfoDTO.setOrderStr(result.getOrderStr());
return unifiedPaymentInfoDTO;
}
}

View File

@ -15,6 +15,7 @@ public class OrderUtil {
public static final String ORDER_PREFIX = "OC";
public static final String MY_PREFIX = "MY";
public static final String YJ_PREFIX = "YJ";
public static final String ZD_PREFIX = "ZD";
@ -27,6 +28,8 @@ public class OrderUtil {
public static final String FD_PREFIX = "FD";
public static final String FZ_PREFIX = "FZ";
/**
* 生成订单号的方法
* @return 唯一订单号字符串