1. 联调

This commit is contained in:
邱贞招 2024-06-05 09:16:59 +08:00
parent 156e7f33a4
commit a4b28c47dd
7 changed files with 235 additions and 134 deletions

View File

@ -71,7 +71,6 @@ public class AppVerifyController extends BaseController
private IEtOperatingAreaService etOperatingAreaService;
/**
* 故障上报
*/
@ -144,12 +143,10 @@ public class AppVerifyController extends BaseController
if(order.getRuleId()==null){
return error("=============================================ruleId未传=============================================");
}
// //设备是否在线
// if(!asDeviceService.isOnline(order.getSn())){
// return error("设备不在线");
// }
AsDevice asDevice = asDeviceService.selectAsDeviceBySn(order.getSn());
EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(asDevice.getAreaId());
//实名判断
if(!asUserService.checkIsAuthentication(order.getUserId())){
if(area.getAuthentication().equals(ServiceConstants.IS_AUTHENTICATION_YES) && !asUserService.checkIsAuthentication(order.getUserId())){
return error("您还未实名,请先实名");
}
//运营时间判断
@ -157,9 +154,9 @@ public class AppVerifyController extends BaseController
return error("不在营业时间内,不得骑行");
}
//非正常状态不得骑行
AsDevice asDevice = asDeviceService.selectAsDeviceBySn(order.getSn());
String status = asDevice.getStatus();
if(!ServiceConstants.VEHICLE_STATUS_NORMAL.equals(status)){
EtOrder order1 = etOrderService.selectEtOrderByOrderNo(order.getOrderNo());
if(!ServiceConstants.VEHICLE_STATUS_NORMAL.equals(status) && !order1.getSn().equals(order.getSn())){
//根据状态值返回不同的提示
return error(CommonUtil.format(status));
}
@ -301,10 +298,16 @@ public class AppVerifyController extends BaseController
public AjaxResult deviceAppointment(EtOrderVo appointmentVo)
{
logger.info("【车辆预约信息】:{}", JSON.toJSON(appointmentVo));
AsDevice asDevice = asDeviceService.selectAsDeviceBySn(appointmentVo.getSn());
//设备是否在线
if(!asDeviceService.isOnline(appointmentVo.getSn())){
return error("设备不在线");
}
EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(asDevice.getAreaId());
//实名判断
if(area.getAuthentication().equals(ServiceConstants.IS_AUTHENTICATION_YES) && !asUserService.checkIsAuthentication(appointmentVo.getUserId())){
return error("您还未实名,请先实名");
}
//运营时间判断
if(!asDeviceService.isOperatingTime(appointmentVo.getSn())){
return error("不在营业时间内,不得骑行");
@ -321,7 +324,6 @@ public class AppVerifyController extends BaseController
throw new ServiceException("您有预约中的订单,请务重复操作");
}
appointmentVo.setType("2");
AsDevice asDevice = asDeviceService.selectAsDeviceBySn(appointmentVo.getSn());
String status = asDevice.getStatus();
if(!ServiceConstants.VEHICLE_STATUS_NORMAL.equals(status)){
//根据状态值返回不同的提示

View File

@ -216,6 +216,23 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
return minutes;
}
/**
* 计算时间差只返回秒数
*
* @param endDate 结束时间
* @param startTime 开始时间
* @return 时间差
*/
public static int timeDifferenceInSeconds(Date endDate, Date startTime) {
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - startTime.getTime();
// 直接计算差多少秒
int seconds = (int) Math.abs(diff / 1000);
return seconds;
}
/**
* 增加 LocalDateTime ==> Date
*/

View File

@ -10,7 +10,7 @@ import lombok.Data;
@Data
public class EtOrderVo {
/** 用户id Cannot deserialize value of type `long` from String "union select 1,md5(3141592657)--": not a valid `long` value */
/** 用户id */
private Long userId;
/** 设备编码 */

View File

@ -207,4 +207,9 @@ public interface EtOrderMapper
* 最近一笔订单
*/
EtOrder selectLatestOrder(EtOrder etOrder);
/**
* 预约未完成订单处理
*/
List<EtOrder> selectAppointmentUnfinished();
}

View File

@ -161,130 +161,13 @@ public class CallbackServiceImpl implements CallbackService {
// 新增资金流水记录
capitalFlowRecords(order,ServiceConstants.FLOW_TYPE_INCOME,ServiceConstants.ORDER_TYPE_RIDING);
// 还车结算___小时后自动退押金---创建一个定时器TimerTask计算出退还时间后执行退款操作
EtFeeRule rule = etFeeRuleService.selectEtFeeRuleByRuleId(order.getRuleId());
Integer autoRefundDeposit = rule.getAutoRefundDeposit();
EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(order.getAreaId());
if(autoRefundDeposit!=null && autoRefundDeposit>0){
//创建一个定时器计算出退还时间后执行退款操作
// 往后推autoRefundDeposit小时执行
scheduledExecutorService.schedule(() -> {
// 如果退款成功直接返回
EtRefund refund2 = etRefundMapper.selectEtRefundByOrderNo(order.getOrderNo());
if(ObjectUtil.isNotNull(refund2) && refund2.getRefundResult().equals(Constants.SUCCESS2)){
return;
}
logger.info("【微信支付回调】退还押金定时任务开始");
// 退款
Long userId = order.getUserId();
EtOrder etOrder = new EtOrder();
etOrder.setUserId(userId);
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.isNull(etOrders) ) {
throw new ServiceException("押金充值记录不存在");
}
Optional<EtOrder> latestOrder = etOrders.stream()
.max(Comparator.comparing(EtOrder::getPayTime));
if (latestOrder.isPresent()) {
EtOrder newestOrder = latestOrder.get();
logger.info("【微信支付回调】最后一次押金充值记录 : " + JSON.toJSONString(newestOrder));
// 处理找到的最新支付时间的订单
String deposit = area.getDeposit();
if(newestOrder.getTotalFee().compareTo(new BigDecimal(deposit))!=0){
throw new ServiceException("押金充值记录与当前运营区的押金不同");
}
String reason = autoRefundDeposit + "个小时后自动退押金";
Refund refund = wxPayService.refund(newestOrder,reason, newestOrder.getTotalFee());
newestOrder.setReason(reason);
EtRefund refund1= orderService.createRefund(newestOrder, newestOrder.getTotalFee(), null, null, null, null, refund,ServiceConstants.REFUND_TYPE_DEPOSIT);
int i = etRefundService.insertEtRefund(refund1);
if(i>0){
logger.info("【自动退款】保存退款对象成功");
}
// 新增资金流水记录
capitalFlowRecords(newestOrder,ServiceConstants.FLOW_TYPE_DISBURSE,ServiceConstants.ORDER_TYPE_DEPOSIT_REFUND);
// 退还押金处理
refundDeposit(area.getDeposit(), order, asUser);
// 更新用户信息清除缓存
asUser.setBalance(BigDecimal.ZERO);
int updateUser = userService.updateUser(asUser);
if(updateUser>0){
Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
redisCache.deleteObject(keys);
logger.info("【微信支付回调】退还押金,更新用户余额成功!");
}
logger.info("=================【微信支付回调】退还押金定时任务结束!!!==================");
} else {
throw new ServiceException("没有找到押金充值记录");
}
}, autoRefundDeposit , TimeUnit.HOURS);
}
List<EtDividendDetail> etDividendDetails = dividendDetailService.selectEtDividendDetailByOrderNo(order.getOrderNo());
if(ObjectUtil.isNotNull(etDividendDetails) && etDividendDetails.size()>0){
return;
}
logger.info("=================【微信支付回调】开始请求分账==================");
logger.info("区域对象====="+JSON.toJSONString(area));
logger.info("订单对象====="+JSON.toJSONString(order));
// 请求分账
List<CreateOrderReceiver> receivers = new ArrayList<>();
// 获取到合伙人的openid
SysUser sysUser = new SysUser();
sysUser.setUserType("03");
sysUser.setAreaId(area.getAreaId());
List<SysUser> sysUsers = userMapper.selectUserList(sysUser);
// 请求分账处理
if (dividendHandle(transactionId, order, area)) return;
for (SysUser sysUser1 : sysUsers){
EtDividendDetail etDividendDetail = new EtDividendDetail();
AsUser asUser1 = asUserMapper.selectUserById(sysUser1.getAppUserId());
if(asUser1!=null && asUser1.getWxopenid()!=null){
BigDecimal dividendAmount = BigDecimal.ZERO;
logger.info("=============系统用户sysUser1============"+JSON.toJSONString(sysUser1));
CreateOrderReceiver receiver = new CreateOrderReceiver();
receiver.setType(ReceiverType.PERSONAL_OPENID.name());
receiver.setAccount(asUser1.getWxopenid());
String dividendItem = sysUser1.getDividendItem();
logger.info("=================分账项目dividendItem=================="+dividendItem);
if(dividendItem.contains("1")){
logger.info("=================骑行费(骑行费+预约费)==================");
dividendAmount = dividendAmount.add(order.getRidingFee().add(order.getAppointmentFee()));//1-骑行费骑行费+预约费
}
if(dividendItem.contains("2")){
logger.info("=================调度费(调度费+管理费)==================");
dividendAmount = dividendAmount.add(order.getManageFee().add(order.getDispatchFee()));//2-调度费调度费+管理费
}
logger.info("=================分账金额dividendAmount=================="+dividendAmount);
BigDecimal divide = new BigDecimal(sysUser1.getDividendProportion()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
logger.info("=================分账比例%=================="+divide);
BigDecimal multiply = dividendAmount.multiply(divide);
logger.info(sysUser1.getUserName()+"分账比例:"+sysUser1.getDividendProportion()+"%,分账金额:"+multiply);
receiver.setAmount(multiply.multiply(new BigDecimal(100)).longValue());
receiver.setDescription(area.getAreaName()+"共享电动车自动分账");
receivers.add(receiver);
etDividendDetail.setAreaId(area.getAreaId());
etDividendDetail.setPartnerId(sysUser1.getUserId());
etDividendDetail.setOrderNo(order.getOrderNo());
etDividendDetail.setTotalAmount(order.getTotalFee());
etDividendDetail.setCreateTime(DateUtils.getNowDate());
etDividendDetail.setDividendProportion(sysUser1.getDividendProportion());
etDividendDetail.setDividendAmount(multiply);
etDividendDetail.setDividendItem(dividendItem);
logger.info("【微信支付回调】保存分账明细 === " + JSON.toJSONString(etDividendDetail));
int i = dividendDetailService.insertEtDividendDetail(etDividendDetail);
if(i==0){
throw new ServiceException("保存分账明细失败");
}
}
}
OrdersEntity ordersEntity = wxPayService.createOrder(transactionId,receivers);
if(ordersEntity!=null){
logger.info("【微信支付回调】发起分账响应:【{}】",JSON.toJSON(ordersEntity));
}else{
logger.info("【微信支付回调】发起分账失败");
throw new ServiceException("发起分账失败");
}
}else if(attachVo.getType().equals(ServiceConstants.BUSINESS_TYPE_APPOINTMENT)){
logger.info("【微信支付回调】取消预约支付");
// 2-取消预约支付
@ -336,6 +219,139 @@ public class CallbackServiceImpl implements CallbackService {
}
}
private boolean dividendHandle(String transactionId, EtOrder order, EtOperatingArea area) {
List<EtDividendDetail> etDividendDetails = dividendDetailService.selectEtDividendDetailByOrderNo(order.getOrderNo());
if(ObjectUtil.isNotNull(etDividendDetails) && etDividendDetails.size()>0){
return true;
}
logger.info("=================【微信支付回调】开始请求分账==================");
logger.info("区域对象====="+JSON.toJSONString(area));
logger.info("订单对象====="+JSON.toJSONString(order));
// 请求分账
List<CreateOrderReceiver> receivers = new ArrayList<>();
// 获取到合伙人的openid
SysUser sysUser = new SysUser();
sysUser.setUserType("03");
sysUser.setAreaId(area.getAreaId());
List<SysUser> sysUsers = userMapper.selectUserList(sysUser);
for (SysUser sysUser1 : sysUsers){
EtDividendDetail etDividendDetail = new EtDividendDetail();
AsUser asUser1 = asUserMapper.selectUserById(sysUser1.getAppUserId());
if(asUser1!=null && asUser1.getWxopenid()!=null){
BigDecimal dividendAmount = BigDecimal.ZERO;
logger.info("=============系统用户sysUser1============"+JSON.toJSONString(sysUser1));
CreateOrderReceiver receiver = new CreateOrderReceiver();
receiver.setType(ReceiverType.PERSONAL_OPENID.name());
receiver.setAccount(asUser1.getWxopenid());
String dividendItem = sysUser1.getDividendItem();
logger.info("=================分账项目dividendItem=================="+dividendItem);
if(dividendItem.contains("1")){
logger.info("=================骑行费(骑行费+预约费)==================");
dividendAmount = dividendAmount.add(order.getRidingFee().add(order.getAppointmentFee()));//1-骑行费骑行费+预约费
}
if(dividendItem.contains("2")){
logger.info("=================调度费(调度费+管理费)==================");
dividendAmount = dividendAmount.add(order.getManageFee().add(order.getDispatchFee()));//2-调度费调度费+管理费
}
logger.info("=================分账金额dividendAmount=================="+dividendAmount);
BigDecimal divide = new BigDecimal(sysUser1.getDividendProportion()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
logger.info("=================分账比例%=================="+divide);
BigDecimal multiply = dividendAmount.multiply(divide);
logger.info(sysUser1.getUserName()+"分账比例:"+sysUser1.getDividendProportion()+"%,分账金额:"+multiply);
receiver.setAmount(multiply.multiply(new BigDecimal(100)).longValue());
receiver.setDescription(area.getAreaName()+"共享电动车自动分账");
receivers.add(receiver);
etDividendDetail.setAreaId(area.getAreaId());
etDividendDetail.setPartnerId(sysUser1.getUserId());
etDividendDetail.setOrderNo(order.getOrderNo());
etDividendDetail.setTotalAmount(order.getTotalFee());
etDividendDetail.setCreateTime(DateUtils.getNowDate());
etDividendDetail.setDividendProportion(sysUser1.getDividendProportion());
etDividendDetail.setDividendAmount(multiply);
etDividendDetail.setDividendItem(dividendItem);
logger.info("【微信支付回调】保存分账明细 === " + JSON.toJSONString(etDividendDetail));
int i = dividendDetailService.insertEtDividendDetail(etDividendDetail);
if(i==0){
throw new ServiceException("保存分账明细失败");
}
}
}
OrdersEntity ordersEntity = wxPayService.createOrder(transactionId,receivers);
if(ordersEntity!=null){
logger.info("【微信支付回调】发起分账响应:【{}】",JSON.toJSON(ordersEntity));
}else{
logger.info("【微信支付回调】发起分账失败");
throw new ServiceException("发起分账失败");
}
return false;
}
/**
* 退还押金定时任务
*/
private void refundDeposit(String deposit, EtOrder order, AsUser asUser) {
EtFeeRule rule = etFeeRuleService.selectEtFeeRuleByRuleId(order.getRuleId());
Integer autoRefundDeposit = rule.getAutoRefundDeposit();
if(autoRefundDeposit!=null && autoRefundDeposit>0){
//创建一个定时器计算出退还时间后执行退款操作
// 往后推autoRefundDeposit小时执行
scheduledExecutorService.schedule(() -> {
// 如果退款成功直接返回
EtRefund refund2 = etRefundMapper.selectEtRefundByOrderNo(order.getOrderNo());
if(ObjectUtil.isNotNull(refund2) && refund2.getRefundResult().equals(Constants.SUCCESS2)){
return;
}
logger.info("【微信支付回调】退还押金定时任务开始");
// 退款
Long userId = order.getUserId();
EtOrder etOrder = new EtOrder();
etOrder.setUserId(userId);
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.isNull(etOrders) ) {
throw new ServiceException("押金充值记录不存在");
}
Optional<EtOrder> latestOrder = etOrders.stream()
.max(Comparator.comparing(EtOrder::getPayTime));
if (latestOrder.isPresent()) {
EtOrder newestOrder = latestOrder.get();
logger.info("【微信支付回调】最后一次押金充值记录 : " + JSON.toJSONString(newestOrder));
// 处理找到的最新支付时间的订单
if(newestOrder.getTotalFee().compareTo(new BigDecimal(deposit))!=0){
throw new ServiceException("押金充值记录与当前运营区的押金不同");
}
String reason = autoRefundDeposit + "个小时后自动退押金";
Refund refund = wxPayService.refund(newestOrder,reason, newestOrder.getTotalFee());
newestOrder.setReason(reason);
EtRefund refund1= orderService.createRefund(newestOrder, newestOrder.getTotalFee(), null, null, null, null, refund,ServiceConstants.REFUND_TYPE_DEPOSIT);
int i = etRefundService.insertEtRefund(refund1);
if(i>0){
logger.info("【自动退款】保存退款对象成功");
}
// 新增资金流水记录
capitalFlowRecords(newestOrder,ServiceConstants.FLOW_TYPE_DISBURSE,ServiceConstants.ORDER_TYPE_DEPOSIT_REFUND);
// 更新用户信息清除缓存
asUser.setBalance(BigDecimal.ZERO);
int updateUser = userService.updateUser(asUser);
if(updateUser>0){
Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
redisCache.deleteObject(keys);
logger.info("【微信支付回调】退还押金,更新用户余额成功!");
}
logger.info("=================【微信支付回调】退还押金定时任务结束!!!==================");
} else {
throw new ServiceException("没有找到押金充值记录");
}
}, autoRefundDeposit , TimeUnit.HOURS);
}
}
/**
* 资金流水记录
* */

View File

@ -6,9 +6,11 @@ import com.ruoyi.common.constant.ServiceConstants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.domain.AsDevice;
import com.ruoyi.system.domain.EtDividendDetail;
import com.ruoyi.system.domain.EtOperatingArea;
import com.ruoyi.system.domain.EtOrder;
import com.ruoyi.system.mapper.AsDeviceMapper;
import com.ruoyi.system.mapper.EtOrderMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.IEtDividendDetailService;
@ -24,7 +26,10 @@ import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
/**
@ -48,14 +53,67 @@ public class EtTask {
@Autowired
private IEtDividendDetailService dividendDetailService;
@Autowired
private ScheduledExecutorService scheduledExecutorService;
@Autowired
private IEtOrderService etOrderService;
@Resource
private AsDeviceMapper asDeviceMapper;
/**
* 启动时判断是否有未取消预约的订单已完成的订单未退还押金的
* 1.启动时判断是否有未取消预约的订单
* 2.判断已完成的订单未退还押金的
*/
@PostConstruct
public void init() {
log.info("websocket====>init方法被执行");
log.info("=========启动时判断是否有未取消预约的订单、已完成的订单未退还押金的==========");
List<EtOrder> orders= etOrderMapper.selectAppointmentUnfinished();
log.info("预约未完成的订单 = " + JSON.toJSONString(orders));
for (EtOrder order:orders) {
EtOperatingArea area = etOperatingAreaService.selectEtOperatingAreaByAreaId(order.getAreaId());
AsDevice asDevice = asDeviceMapper.selectAsDeviceBySn(order.getSn());
Date appointmentEndTime = DateUtils.getTimeAfterXMinutes(order.getAppointmentStartTime(), area.getTimeoutMinutes());//预约结束时间
int timeDifferenceInSeconds = DateUtils.timeDifferenceInSeconds(appointmentEndTime, order.getAppointmentStartTime());//超时时间-开始时间的秒数
int differenceInSeconds = DateUtils.timeDifferenceInSeconds(new Date(), order.getAppointmentStartTime());//当前时间-开始时间的秒数
int delay = timeDifferenceInSeconds - differenceInSeconds;
log.info("【定时取消预约】延迟:【{}】秒", delay);
//定时取消预约
scheduledExecutorService.schedule(() -> {
log.error("【车辆超时预约】系统自动取消");
EtOrder order1 = etOrderService.selectEtOrderByOrderNo(order.getOrderNo());
log.info("【定时取消预约】重新获取订单信息:{}",JSON.toJSON(order1));
if(order1.getPaid().equals(ServiceConstants.ORDER_PAY_STATUS_PAID)){//已支付订单跳过
log.error("【车辆超时预约】订单已支付,跳过");
return;
}
log.error("【车辆超时预约】订单未支付,系统自动处理");
//未支付 订单更新最后预约时间并结束订单做超出预约时间标记
order.setStatus(ServiceConstants.ORDER_STATUS_CANCEL_APPOINTMENT);
order.setAppointmentEndTime(new Date());
order.setAppointmentTimeout("1");
//计算预约费
BigDecimal appointmentServiceFee = area.getAppointmentServiceFee();
BigDecimal fee = appointmentServiceFee.multiply(new BigDecimal(area.getTimeoutMinutes()).divide(new BigDecimal(10)));
order.setAppointmentFee(fee);
order.setTotalFee(fee);
int update = etOrderService.updateEtOrder(order);
if(update==0){
throw new ServiceException("【车辆超时预约】:更新订单状态失败");
}
// 改变车辆状态
asDevice.setStatus(ServiceConstants.VEHICLE_STATUS_NORMAL);
asDevice.setLockStatus(ServiceConstants.LOCK_STATUS_OPEN);
int device = asDeviceMapper.updateAsDevice(asDevice);
if(device==0){
log.error("【车辆超时预约】更新车辆状态失败");
throw new ServiceException("【车辆超时预约】更新车辆状态失败");
}
}, delay, TimeUnit.SECONDS);
}
}
/**
* 每天凌晨0点5分执行计算分账结果

View File

@ -295,6 +295,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
ORDER BY create_time DESC
LIMIT 1
</select>
<select id="selectAppointmentUnfinished" resultType="com.ruoyi.system.domain.EtOrder">
select * from et_order where appointment_start_time is not null and appointment_start_time != '' AND appointment_end_time IS NULL
</select>
<insert id="insertEtOrder" parameterType="EtOrder" useGeneratedKeys="true" keyProperty="orderId">
insert into et_order