1. 启动时判断是否分账

2. 判断已完成的订单未退还押金的
This commit is contained in:
邱贞招 2024-06-05 18:12:19 +08:00
parent a4b28c47dd
commit 6a4c3baf94
14 changed files with 361 additions and 40 deletions

View File

@ -7,6 +7,10 @@ import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.CommonUtil; import com.ruoyi.common.utils.CommonUtil;
import com.ruoyi.system.domain.*; import com.ruoyi.system.domain.*;
import com.ruoyi.system.service.*; import com.ruoyi.system.service.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -39,6 +43,9 @@ public class AppController extends BaseController
@Autowired @Autowired
private IEtOrderService etOrderService; private IEtOrderService etOrderService;
@Autowired
private IWxPayService wxPayService;
/** /**
@ -287,4 +294,26 @@ public class AppController extends BaseController
return AjaxResult.success("操作成功", address); return AjaxResult.success("操作成功", address);
} }
/**
* 查询退款是否成功
*/
@GetMapping("/queryByOutRefundNo")
public AjaxResult queryByOutRefundNo(String outRefundNo)
{
logger.info("查询退款是否成功【outRefundNo="+outRefundNo+"");
Refund refund = wxPayService.queryByOutRefundNo(outRefundNo);
return AjaxResult.success(refund);
}
/**
* 通过商户订单号查询订单信息
*/
@GetMapping("/queryOrderByOutTradeNo")
public AjaxResult queryOrderByOutTradeNo(String outTradeNo)
{
logger.info("查询支付订单信息【outTradeNo="+outTradeNo+"");
Transaction transaction = wxPayService.queryOrderByOutTradeNo(outTradeNo);
return AjaxResult.success(transaction);
}
} }

View File

@ -133,7 +133,7 @@ xss:
# 过滤开关 # 过滤开关
enabled: true enabled: true
# 排除链接(多个用逗号分隔) # 排除链接(多个用逗号分隔)
excludes: /system/notice excludes: /system/notice,/system/area
# 匹配链接 # 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/* urlPatterns: /system/*,/monitor/*,/tool/*
# 阿里云短信 # 阿里云短信

View File

@ -199,6 +199,23 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
return day + "" + hour + "小时" + min + "分钟"; return day + "" + hour + "小时" + min + "分钟";
} }
/**
* 计算时间差只返回小时数
*
* @param endDate 结束时间
* @param startTime 开始时间
* @return 时间差小时
*/
public static int timeDifferenceInHours(Date endDate, Date startTime) {
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - startTime.getTime();
// 直接计算差多少小时
int hours = (int) Math.abs(diff / (1000 * 60 * 60));
return hours;
}
/** /**
* 计算时间差只返回分钟数 * 计算时间差只返回分钟数
* *

View File

@ -212,4 +212,19 @@ public interface EtOrderMapper
* 预约未完成订单处理 * 预约未完成订单处理
*/ */
List<EtOrder> selectAppointmentUnfinished(); List<EtOrder> selectAppointmentUnfinished();
/**
* 押金未退还订单处理
*/
List<EtOrder> selectUnrefundableDepositOrder();
/**
* 已完成订单的用户列表
*/
List<EtOrder> selectUserListFinishOrder();
/**
* 待结算订单
*/
List<EtOrder> selectNeedDividendOrder();
} }

View File

@ -1,5 +1,8 @@
package com.ruoyi.system.service; package com.ruoyi.system.service;
import com.ruoyi.system.domain.EtOperatingArea;
import com.ruoyi.system.domain.EtOrder;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
/** /**
@ -21,4 +24,22 @@ public interface CallbackService {
*/ */
void weChatRefund(HttpServletRequest request); void weChatRefund(HttpServletRequest request);
/**
* 新增资金流水记录
* @param order 订单
* @param type 类型
* @param busType 业务类型
* @return void
*/
public void capitalFlowRecords(EtOrder order, String type, String busType);
/**
* 分红处理
* @param transactionId 订单号
* @param order 订单
* @param area 运营区域
* @return boolean
*/
public boolean dividendHandle(String transactionId, EtOrder order, EtOperatingArea area);
} }

View File

@ -74,4 +74,12 @@ public interface IEtDividendDetailService
* @return 结果 * @return 结果
*/ */
boolean isDividendComputed(String date); boolean isDividendComputed(String date);
/**
* 根据订单号判断是否已经计算过分账结果
*
* @param orderNo 订单号
* @return 结果
*/
boolean isDividendComputedByOrderNo(String orderNo);
} }

View File

@ -41,11 +41,11 @@ public interface IWxPayService {
Transaction queryOrderById(String prePayId); Transaction queryOrderById(String prePayId);
/** /**
* 通过订单号查询订单信息 * 通过商户订单号查询订单信息
* @param billNo 订单编 * @param outTradeNo 商户订单
* @return 订单信息 * @return 订单信息
*/ */
Transaction queryOrderByOutTradeNo(String billNo); Transaction queryOrderByOutTradeNo(String outTradeNo);
/** /**
* 退款 * 退款
@ -55,6 +55,12 @@ public interface IWxPayService {
*/ */
Refund refund(EtOrder etOrder, String reason, BigDecimal amount); Refund refund(EtOrder etOrder, String reason, BigDecimal amount);
/**
* 根据退款单号查询退款信息
* @param outRefundNo 退款单号
*/
Refund queryByOutRefundNo(String outRefundNo);
/** /**
* 请求分账API * 请求分账API

View File

@ -160,13 +160,17 @@ public class CallbackServiceImpl implements CallbackService {
// 新增资金流水记录 // 新增资金流水记录
capitalFlowRecords(order,ServiceConstants.FLOW_TYPE_INCOME,ServiceConstants.ORDER_TYPE_RIDING); capitalFlowRecords(order,ServiceConstants.FLOW_TYPE_INCOME,ServiceConstants.ORDER_TYPE_RIDING);
// 还车结算___小时后自动退押金---创建一个定时器TimerTask计算出退还时间后执行退款操作 // 还车结算___小时后自动退押金---创建一个定时器TimerTask计算出退还时间后执行退款操作
EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(order.getAreaId()); EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(order.getAreaId());
// 退还押金处理 // 退还押金处理
refundDeposit(area.getDeposit(), order, asUser); refundDeposit(area.getDeposit(), order, asUser);
// 请求分账处理 // 24小时后发起分账
if (dividendHandle(transactionId, order, area)) return; scheduledExecutorService.schedule(() -> {
// 请求分账处理
if (dividendHandle(transactionId, order, area)) return;
}, 24 , TimeUnit.HOURS);
}else if(attachVo.getType().equals(ServiceConstants.BUSINESS_TYPE_APPOINTMENT)){ }else if(attachVo.getType().equals(ServiceConstants.BUSINESS_TYPE_APPOINTMENT)){
logger.info("【微信支付回调】取消预约支付"); logger.info("【微信支付回调】取消预约支付");
@ -219,12 +223,19 @@ public class CallbackServiceImpl implements CallbackService {
} }
} }
private boolean dividendHandle(String transactionId, EtOrder order, EtOperatingArea area) { /**
* 分账处理
* 1.根据订单号查询分账记录如果有记录直接返回
* 2.根据区域id查询合伙人列表根据合伙人分红比例分账保存分账明细表
* 3.请求分账
*/
@Override
public boolean dividendHandle(String transactionId, EtOrder order, EtOperatingArea area) {
List<EtDividendDetail> etDividendDetails = dividendDetailService.selectEtDividendDetailByOrderNo(order.getOrderNo()); List<EtDividendDetail> etDividendDetails = dividendDetailService.selectEtDividendDetailByOrderNo(order.getOrderNo());
if(ObjectUtil.isNotNull(etDividendDetails) && etDividendDetails.size()>0){ if(ObjectUtil.isNotNull(etDividendDetails) && etDividendDetails.size()>0){
return true; return true;
} }
logger.info("=================【微信支付回调】开始请求分账=================="); logger.info("=================【微信支付回调】24小时后开始请求分账==================");
logger.info("区域对象====="+JSON.toJSONString(area)); logger.info("区域对象====="+JSON.toJSONString(area));
logger.info("订单对象====="+JSON.toJSONString(order)); logger.info("订单对象====="+JSON.toJSONString(order));
// 请求分账 // 请求分账
@ -355,7 +366,8 @@ public class CallbackServiceImpl implements CallbackService {
/** /**
* 资金流水记录 * 资金流水记录
* */ * */
private void capitalFlowRecords(EtOrder order,String type,String busType) { @Override
public void capitalFlowRecords(EtOrder order,String type,String busType) {
if(ObjectUtil.isNotNull(etCapitalFlowService.selectEtCapitalFlowByOutTradeNo(order.getOutTradeNo()))){ if(ObjectUtil.isNotNull(etCapitalFlowService.selectEtCapitalFlowByOutTradeNo(order.getOutTradeNo()))){
return; return;
} }
@ -399,6 +411,8 @@ public class CallbackServiceImpl implements CallbackService {
int i = etCapitalFlowService.insertEtCapitalFlow(capitalFlow); int i = etCapitalFlowService.insertEtCapitalFlow(capitalFlow);
if(i==0){ if(i==0){
throw new ServiceException("保存资金流水记录失败"); throw new ServiceException("保存资金流水记录失败");
}else {
logger.info("【微信支付回调】保存资金流水记录成功");
} }
} }

View File

@ -1,6 +1,8 @@
package com.ruoyi.system.service.impl; package com.ruoyi.system.service.impl;
import java.util.List; import java.util.List;
import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -8,6 +10,8 @@ import com.ruoyi.system.mapper.EtDividendDetailMapper;
import com.ruoyi.system.domain.EtDividendDetail; import com.ruoyi.system.domain.EtDividendDetail;
import com.ruoyi.system.service.IEtDividendDetailService; import com.ruoyi.system.service.IEtDividendDetailService;
import javax.annotation.Resource;
/** /**
* 分账明细Service业务层处理 * 分账明细Service业务层处理
* *
@ -17,7 +21,7 @@ import com.ruoyi.system.service.IEtDividendDetailService;
@Service @Service
public class EtDividendDetailServiceImpl implements IEtDividendDetailService public class EtDividendDetailServiceImpl implements IEtDividendDetailService
{ {
@Autowired @Resource
private EtDividendDetailMapper etDividendDetailMapper; private EtDividendDetailMapper etDividendDetailMapper;
/** /**
@ -111,5 +115,19 @@ public class EtDividendDetailServiceImpl implements IEtDividendDetailService
return false; return false;
} }
/**
* 判断是否已经计算过
* @param orderNo
* @return
*/
@Override
public boolean isDividendComputedByOrderNo(String orderNo) {
List<EtDividendDetail> etDividendDetails = etDividendDetailMapper.selectEtDividendDetailByOrderNo(orderNo);
if(ObjectUtil.isNotNull(etDividendDetails) && etDividendDetails.size() > 0){
return true;
}
return false;
}
} }

View File

@ -64,9 +64,6 @@ public class EtOrderServiceImpl implements IEtOrderService
@Autowired @Autowired
private IAsDeviceService deviceService; private IAsDeviceService deviceService;
@Autowired
private ISysConfigService sysConfigService;
@Autowired @Autowired
private IEtFeeRuleService etFeeRuleService; private IEtFeeRuleService etFeeRuleService;
@ -76,9 +73,6 @@ public class EtOrderServiceImpl implements IEtOrderService
@Autowired @Autowired
private IAsDeviceService asDeviceService; private IAsDeviceService asDeviceService;
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired @Autowired
private IEtRefundService etRefundService; private IEtRefundService etRefundService;
@ -86,16 +80,10 @@ public class EtOrderServiceImpl implements IEtOrderService
private IEtTripLogService etTripLogService; private IEtTripLogService etTripLogService;
@Autowired @Autowired
private RedisCache redisCache; private IEtDividendDetailService dividendDetailService;
// @Autowired
// private TokenService tokenService;
// 令牌有效期默认30分钟
@Value("${token.expireTime}")
private int expireTime;
@Autowired
private CallbackService callbackService;
/** /**
* 查询订单 * 查询订单
@ -689,6 +677,9 @@ public class EtOrderServiceImpl implements IEtOrderService
if(ServiceConstants.ORDER_PAY_STATUS_NON_PAYMENT.equals(etOrder1.getPaid())){ if(ServiceConstants.ORDER_PAY_STATUS_NON_PAYMENT.equals(etOrder1.getPaid())){
throw new ServiceException("订单未支付,不能退款"); throw new ServiceException("订单未支付,不能退款");
} }
if(dividendDetailService.isDividendComputedByOrderNo(etOrder.getOrderNo())){
throw new ServiceException("订单【{}】已经分账,不能退款");
}
/** 1.退款*/ /** 1.退款*/
//退款金额 //退款金额
BigDecimal refundAmount = new BigDecimal("0"); BigDecimal refundAmount = new BigDecimal("0");
@ -716,6 +707,8 @@ public class EtOrderServiceImpl implements IEtOrderService
if(i>0){ if(i>0){
log.info("保存退款对象成功"); log.info("保存退款对象成功");
} }
// 新增资金流水记录
callbackService.capitalFlowRecords(etOrder1,ServiceConstants.FLOW_TYPE_DISBURSE,ServiceConstants.ORDER_TYPE_RIDING_REFUND);
return i; return i;
} }

View File

@ -28,6 +28,7 @@ import com.wechat.pay.java.service.profitsharing.model.*;
import com.wechat.pay.java.service.refund.RefundService; import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq; import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest; import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.QueryByOutRefundNoRequest;
import com.wechat.pay.java.service.refund.model.Refund; import com.wechat.pay.java.service.refund.model.Refund;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -142,11 +143,16 @@ public class WxPayService implements IWxPayService {
return jsapiService.queryOrderById(request); return jsapiService.queryOrderById(request);
} }
/**
* 根据订单号查询订单
* @param outTradeNo 商户订单号
* @return
*/
@Override @Override
public Transaction queryOrderByOutTradeNo(String billNo) { public Transaction queryOrderByOutTradeNo(String outTradeNo) {
QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest(); QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
request.setMchid(wxPayConfig.getMerchantId()); request.setMchid(wxPayConfig.getMerchantId());
request.setOutTradeNo(billNo); request.setOutTradeNo(outTradeNo);
return jsapiService.queryOrderByOutTradeNo(request); return jsapiService.queryOrderByOutTradeNo(request);
} }
@ -170,6 +176,13 @@ public class WxPayService implements IWxPayService {
return refund; return refund;
} }
@Override
public Refund queryByOutRefundNo(String outRefundNo) {
QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
request.setOutRefundNo(outRefundNo);
return refundService2.queryByOutRefundNo(request);
}
/** 请求分账API */ /** 请求分账API */
public OrdersEntity createOrder(String transactionId,List<CreateOrderReceiver> receivers) { public OrdersEntity createOrder(String transactionId,List<CreateOrderReceiver> receivers) {
CreateOrderRequest request = new CreateOrderRequest(); CreateOrderRequest request = new CreateOrderRequest();
@ -177,7 +190,7 @@ public class WxPayService implements IWxPayService {
request.setTransactionId(transactionId);// 微信订单号 request.setTransactionId(transactionId);// 微信订单号
request.setOutOrderNo(IdUtils.getOrderNo("fz"));// 商户系统内部分账单号 request.setOutOrderNo(IdUtils.getOrderNo("fz"));// 商户系统内部分账单号
request.setReceivers(receivers); request.setReceivers(receivers);
request.setUnfreezeUnsplit(false); request.setUnfreezeUnsplit(true);
return profitsharingService.createOrder(request); return profitsharingService.createOrder(request);
} }

View File

@ -1,33 +1,35 @@
package com.ruoyi.system.task; package com.ruoyi.system.task;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.ServiceConstants; import com.ruoyi.common.constant.ServiceConstants;
import com.ruoyi.common.core.domain.entity.AsUser;
import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.domain.AsDevice; import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.domain.EtDividendDetail; import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.EtOperatingArea;
import com.ruoyi.system.domain.EtOrder;
import com.ruoyi.system.mapper.AsDeviceMapper; import com.ruoyi.system.mapper.AsDeviceMapper;
import com.ruoyi.system.mapper.AsUserMapper;
import com.ruoyi.system.mapper.EtOrderMapper; import com.ruoyi.system.mapper.EtOrderMapper;
import com.ruoyi.system.mapper.SysUserMapper; import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.IEtDividendDetailService; import com.ruoyi.system.service.*;
import com.ruoyi.system.service.IEtOperatingAreaService; import com.wechat.pay.java.service.payments.model.Transaction;
import com.ruoyi.system.service.IEtOrderService; import com.wechat.pay.java.service.refund.model.Refund;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Date; import java.util.*;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -62,15 +64,176 @@ public class EtTask {
@Resource @Resource
private AsDeviceMapper asDeviceMapper; private AsDeviceMapper asDeviceMapper;
@Autowired
private IWxPayService wxPayService;
@Autowired
private IEtFeeRuleService etFeeRuleService;
@Autowired
private IEtRefundService etRefundService;
@Autowired
private RedisCache redisCache;
@Resource
private AsUserMapper asUserMapper;
@Autowired
private CallbackService callbackService;
/** /**
* 1.启动时判断是否有未取消预约的订单 * 1.启动时判断是否有未取消预约的订单
* 2.判断已完成的订单未退还押金的 * 2.判断已完成的订单未退还押金的
* 3.启动时判断是否分账
*/ */
@Transactional
@PostConstruct @PostConstruct
public void init() { public void init() {
log.info("=========启动时判断是否有未取消预约的订单、已完成的订单未退还押金的=========="); log.info("=========================启动业务处理=========================");
log.info("=========================开始=========================");
/** 1.启动时判断是否有未取消预约的订单*/
uncancelledAppointmentHandle();
/** 2.判断已完成的订单未退还押金的(根据et_refund表中的refund_result结果判断是否已经退款) */
/** 找出所有已完成的订单 status=4 type = 1 r.refund_result IS NULL
* 根据用户查询最后一次押金充值记录
*/
List<EtOrder> orders = etOrderMapper.selectUserListFinishOrder();
for(EtOrder order:orders){
EtFeeRule rule = etFeeRuleService.selectEtFeeRuleByRuleId(order.getRuleId());
if(ObjectUtil.isNull(rule)){
throw new ServiceException("骑行订单:【"+order.getOrderNo()+"】未找到该套餐【"+order.getRuleId()+"");
}
EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(order.getAreaId());
AsUser asUser = asUserMapper.selectUserById(order.getUserId());
Integer autoRefundDeposit = rule.getAutoRefundDeposit();
// 根据用户查询最后一次押金充值订单
EtOrder etOrder = new EtOrder();
etOrder.setUserId(order.getUserId());
etOrder.setPaid(ServiceConstants.ORDER_PAY_STATUS_PAID);
etOrder.setType(ServiceConstants.ORDER_TYPE_DEPOSIT);
etOrder.setStatus(ServiceConstants.ORDER_STATUS_ORDER_END);
List<EtOrder> etOrders = etOrderMapper.selectEtOrderList(etOrder);
if (etOrders.size() > 0 || ObjectUtil.isNotNull(etOrders) ) {
Optional<EtOrder> latestOrderOptional = etOrders.stream()
.max(Comparator.comparing(EtOrder::getPayTime));
if (latestOrderOptional.isPresent()) {
EtOrder lastOrder = latestOrderOptional.get();
log.info("【系统启动】用户【{}】最后一次押金充值订单 : " + JSON.toJSONString(lastOrder),asUser.getUserId());
if(lastOrder.getTotalFee().compareTo(new BigDecimal(area.getDeposit()))!=0){
log.info("【系统启动】最后一次押金充值记录 金额与押金不一致,订单押金:【{}】,区域押金:【{}】",lastOrder.getTotalFee(),area.getDeposit());
}else{
// 根据最新的订单号查询是否有退款记录
EtRefund etRefund = etRefundService.selectEtRefundByOrderNo(lastOrder.getOrderNo());
// 没有退款记录,发起退款
if(ObjectUtil.isNull(etRefund)){
// 根据订单支付时间 autoRefundDeposit个小时后退押金
String reason = autoRefundDeposit + "个小时后自动退押金";
Date payTime = order.getPayTime();
Date refundDepositTime = DateUtils.getTimeAfterXHours(payTime, autoRefundDeposit);
Date nowDate = DateUtils.getNowDate();
if (nowDate.after(refundDepositTime)) {
log.info("【系统启动】用户【{}】押金充值订单【{}】已过期,开始自动退押金",asUser.getUserId(),lastOrder.getOrderNo());
refundDeposit(asUser, lastOrder, reason);
}else{
int timeDifferenceInMinutes = DateUtils.timeDifferenceInMinutes(payTime, nowDate);
int i = autoRefundDeposit * 60;
int delay = i - timeDifferenceInMinutes;
log.info("【系统启动】用户【{}】押金充值订单【{}】未过期,【{}】分钟后退押金",asUser.getUserId(),lastOrder.getOrderNo(),delay);
scheduledExecutorService.schedule(() -> {
refundDeposit(asUser, lastOrder, reason);
}, delay, TimeUnit.MINUTES);
}
}else{
// 有退款记录判断是否成功
if(!Constants.SUCCESS2.equals(etRefund.getRefundResult())){
log.info("【系统启动】押金退款未成功回调,退款单号:【{}】",etRefund.getRefundNo());
// 根据退款单号查询退款信息
Refund refund = wxPayService.queryByOutRefundNo(etRefund.getRefundNo());
if(ObjectUtil.isNotNull(refund) && Constants.SUCCESS2.equals(refund.getStatus().name())){
// 更新退款记录
etRefund.setRefundResult(Constants.SUCCESS2);
etRefund.setUpdateTime(new Date());
etRefundService.updateEtRefund(etRefund);
log.info("【系统启动】更新押金退款回调成功,退款单号:【{}】",refund.getOutRefundNo());
}
}
}
}
}
}
}
/** 3.启动时判断是否分账(根据订单号查询分账明细表是否有记录来判断是否分账) */
/** 找出所有已完成的骑行订单 status=4 type = 1 r.refund_result IS NULL
* 根据订单号查询分账明细表是否有记录
* 有记录则已经分账过
* 没值代表还未分账
* 判断是否已过分账时间
* 未过计算出多少小时后分账
* 已过直接分账记录分账明细表
*/
// 查询所有待分账的订单
List<EtOrder> needDividendOrders = etOrderMapper.selectNeedDividendOrder();
for(EtOrder order: needDividendOrders){
log.info("【系统启动】待分账订单:【{}】",order.getOrderNo());
EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(order.getAreaId());
if(dividendDetailService.isDividendComputedByOrderNo(order.getOrderNo())){
log.info("订单【{}】已经分账",order.getOrderNo());
break;
}
log.info("【系统启动】骑行订单【{}】未分账,开始分账",order.getOrderNo());
Date payTime = order.getPayTime();
Date dividendTime = DateUtils.getTimeAfterXHours(payTime, 24);//分账时间
Date nowDate = DateUtils.getNowDate();
if (nowDate.after(dividendTime)) {
log.info("【系统启动】骑行订单【{}】已过分账时间,开始分账",order.getOrderNo());
// 请求分账处理
Transaction transaction = wxPayService.queryOrderByOutTradeNo(order.getOrderNo());
if (callbackService.dividendHandle(transaction.getTransactionId(), order, area)) break;
}else{
int timeDifferenceInHours = DateUtils.timeDifferenceInHours(payTime, nowDate);
int delay = 24 - timeDifferenceInHours;
log.info("【系统启动】骑行订单【{}】未过分账时间,【{}】小时后开始分账",order.getOrderNo(),delay);
// 24小时后发起分账
scheduledExecutorService.schedule(() -> {
// 请求分账处理
Transaction transaction = wxPayService.queryOrderByOutTradeNo(order.getOrderNo());
if (callbackService.dividendHandle(transaction.getTransactionId(), order, area)) return;
}, delay , TimeUnit.HOURS);
}
}
log.info("=========================结束=========================");
}
private void refundDeposit(AsUser asUser, EtOrder lastOrder, String reason) {
Refund refund = wxPayService.refund(lastOrder, reason, lastOrder.getTotalFee());
lastOrder.setReason(reason);
EtRefund refund1= etOrderService.createRefund(lastOrder, lastOrder.getTotalFee(), null, null, null, null, refund,ServiceConstants.REFUND_TYPE_DEPOSIT);
if(etRefundService.insertEtRefund(refund1)>0){
log.info("【自动退款】保存退款对象成功");
// 新增资金流水记录
callbackService.capitalFlowRecords(lastOrder,ServiceConstants.FLOW_TYPE_DISBURSE,ServiceConstants.ORDER_TYPE_DEPOSIT_REFUND);
// 更新用户信息清除缓存
asUser.setBalance(BigDecimal.ZERO);
int updateUser = asUserMapper.updateUser(asUser);
if(updateUser>0){
Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
redisCache.deleteObject(keys);
log.info("【系统启动】退还押金,更新用户余额成功!");
}
log.info("=================【系统启动】退还押金定时任务结束!!!==================");
}else{
throw new ServiceException("【系统启动】保存退款对象失败");
}
}
private void uncancelledAppointmentHandle() {
List<EtOrder> orders= etOrderMapper.selectAppointmentUnfinished(); List<EtOrder> orders= etOrderMapper.selectAppointmentUnfinished();
log.info("预约未完成的订单 = " + JSON.toJSONString(orders)); log.info("预约未完成的订单 = " + JSON.toJSONString(orders));
for (EtOrder order:orders) { for (EtOrder order:orders) {

View File

@ -47,7 +47,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
boundary_str, longitude, latitude, create_by, create_time, boundary_str, longitude, latitude, create_by, create_time,
contact, phone, status, area_time, service_phone, slogan, province,city, contact, phone, status, area_time, service_phone, slogan, province,city,
county, area_out_outage, parking_out_dispatch, area_out_dispatch, county, area_out_outage, parking_out_dispatch, area_out_dispatch,
no_riding_outage, authentication, msg_switch, undercharge, error, agreement, deposit, no_riding_outage, authentication, msg_switch, undercharge, error, cast(agreement as char) as agreement, deposit,
outage, appointment_service_fee, dispatch_fee, vehicle_management_fee, timeout_minutes, outage, appointment_service_fee, dispatch_fee, vehicle_management_fee, timeout_minutes,
auto_replacement_order, area_time_start, area_time_end from et_operating_area auto_replacement_order, area_time_start, area_time_end from et_operating_area
</sql> </sql>

View File

@ -299,6 +299,30 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select * from et_order where appointment_start_time is not null and appointment_start_time != '' AND appointment_end_time IS NULL select * from et_order where appointment_start_time is not null and appointment_start_time != '' AND appointment_end_time IS NULL
</select> </select>
<select id="selectUnrefundableDepositOrder" resultMap="EtOrderResult">
select * from et_order o
left JOIN et_refund r on r.order_no = o.order_no
where o.status ='4' and o.paid = '1' and o.type = 2 and r.refund_result IS NULL
</select>
<select id="selectUserListFinishOrder" resultMap="EtOrderResult">
select * from et_order o
where o.status ='4' and o.paid = '1' and o.type = 1
GROUP BY o.user_id
</select>
<select id="selectNeedDividendOrder" resultType="com.ruoyi.system.domain.EtOrder">
SELECT
*
FROM
et_order o
WHERE
o.STATUS = '4'
AND o.paid = '1'
AND o.type = 1
AND o.pay_type != 'sys'
AND o.total_fee != 0
</select>
<insert id="insertEtOrder" parameterType="EtOrder" useGeneratedKeys="true" keyProperty="orderId"> <insert id="insertEtOrder" parameterType="EtOrder" useGeneratedKeys="true" keyProperty="orderId">
insert into et_order insert into et_order
<trim prefix="(" suffix=")" suffixOverrides=","> <trim prefix="(" suffix=")" suffixOverrides=",">