package com.ruoyi.errand.service.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.errand.constant.DelFlagConstant; import com.ruoyi.errand.domain.AppUser; import com.ruoyi.errand.domain.VipOrder; import com.ruoyi.errand.domain.VipSetting; import com.ruoyi.errand.mapper.AppUserMapper; import com.ruoyi.errand.mapper.VipOrderMapper; import com.ruoyi.errand.mapper.VipSettingMapper; import com.ruoyi.errand.object.dto.app.VipPaymentDTO; import com.ruoyi.errand.service.VipOrderService; import com.ruoyi.errand.utils.*; import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Set; @Service @Slf4j public class VipOrderServiceImpl extends ServiceImpl implements VipOrderService { @Resource private VipSettingMapper vipSettingMapper; @Resource private RedisTemplate redisTemplate; @Resource private AppUserMapper appUserMapper; @Override public R vipPayment(VipPaymentDTO vipPaymentDTO) { AppUser appuser = (AppUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); VipOrder vipOrder = new VipOrder(); vipOrder.setAppUserId(appuser.getId()); VipSetting vipSetting = vipSettingMapper.selectById(vipPaymentDTO.getId()); vipOrder.setOrderAmount(vipSetting.getVipPrice()); vipOrder.setPaymentAmount(vipSetting.getVipPrice()); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); vipOrder.setOrderNumber("QJS" + getNumber(3) + sdf.format(new Date())); vipOrder.setPayStatus(1); vipOrder.setVipId(vipPaymentDTO.getId()); this.save(vipOrder); //判断需要支付的金额是否大于0 BigDecimal paymentMoney = vipOrder.getOrderAmount(); if ( BigDecimal.ZERO.compareTo(paymentMoney) < 0){ //调起微信支付 String vipName = vipSetting.getVipName(); UniPayResult uniPayResult = PaymentUtil.uniPay(vipOrder.getOrderNumber(), paymentMoney.doubleValue(), "购买会员", vipName, "", "/app/vipOrder/orderPaymentCallback", appuser.getWxOpenid(), null); if(null == uniPayResult || !"100".equals(uniPayResult.getRa_Code())){ return R.fail(null == uniPayResult ? "支付失败" : uniPayResult.getRb_CodeMsg()); } String rc_result = uniPayResult.getRc_Result(); JSONObject jsonObject = JSON.parseObject(rc_result); jsonObject.put("orderId", vipOrder.getId().toString()); //将支付数据添加到redis队列中,便于定时任务去校验是否完成支付,没有完成支付支付,15分钟后关闭订单。 long second = LocalDateTime.now().plusMinutes(15).toEpochSecond(ZoneOffset.UTC); redisTemplate.opsForZSet().add("VipOrderPayment", vipOrder.getOrderNumber(), second); return R.ok(jsonObject.toJSONString()); } //设置vipOrder信息 vipOrder.setPayStatus(2);//已支付 vipOrder.setOrderTime(LocalDateTime.now());//下单时间 this.updateById(vipOrder); //更新用户信息 Long appUserId = vipOrder.getAppUserId(); AppUser appUser = appUserMapper.selectById(appUserId); appUser.setVipId(vipOrder.getVipId()); LocalDateTime now = LocalDateTime.now(); appUser.setEndTime(appUser.getEndTime()==null?now:appUser.getEndTime()); if (appUser.getEndTime().isBefore(now)) { appUser.setEndTime(now); } // 根据 vipId 计算会员到期时间 LocalDateTime endTime = calculateEndTime(appUser.getEndTime(), vipOrder.getVipId()); appUser.setEndTime(endTime); appUserMapper.updateById(appUser); return R.ok(); } @Override public R orderPaymentCallback(UniPayCallbackResult uniPayCallbackResult) { VipOrder vipOrder = this.getBaseMapper().selectOne(new LambdaQueryWrapper().eq(VipOrder::getOrderNumber, uniPayCallbackResult.getR2_OrderNo())); if(null == vipOrder || vipOrder.getPayStatus() == 2){ return R.ok(); } //设置vipOrder信息 vipOrder.setPayStatus(2);//已支付 vipOrder.setOrderTime(LocalDateTime.now());//下单时间 String r7TrxNo = uniPayCallbackResult.getR9_BankTrxNo(); vipOrder.setSerialNumber(r7TrxNo); this.updateById(vipOrder); //更新用户信息 //检查是否续期的 Long appUserId = vipOrder.getAppUserId(); AppUser appUser = appUserMapper.selectById(appUserId); appUser.setVipId(vipOrder.getVipId()); LocalDateTime now = LocalDateTime.now(); appUser.setEndTime(appUser.getEndTime()==null?now:appUser.getEndTime()); if (appUser.getEndTime().isBefore(now)) { appUser.setEndTime(now); } // 根据 vipId 计算会员到期时间 LocalDateTime endTime = calculateEndTime(appUser.getEndTime(), vipOrder.getVipId()); appUser.setEndTime(endTime); appUserMapper.updateById(appUser); return R.ok(); } @Override public void closeOrder() { //订单支付数据 long second = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC); Set orderPayment = redisTemplate.opsForZSet().rangeByScore("VipOrderPayment", 0, second); if(orderPayment.size() > 0){ List list = this.getBaseMapper().selectList(new LambdaQueryWrapper().in(VipOrder::getOrderNumber, orderPayment)); for (VipOrder order : list) { if(null == order || order.getPayStatus() != 1){ //不在待支付中的,移除 redisTemplate.opsForZSet().remove("VipOrderPayment", order.getOrderNumber()); continue; } //开始执行关闭订单操作 CloseOrderResult closeOrderResult = PaymentUtil.closeOrder(order.getOrderNumber()); if((null == closeOrderResult || !closeOrderResult.getRa_Status().equals("100")) && Arrays.asList("0", "4", "101", "10080000", "10080002", "10083004", "10083005").contains(closeOrderResult.getRb_Code())){ redisTemplate.opsForZSet().add("VipOrderPayment", order.getOrderNumber(), 0); log.error("关闭订单失败:{}---->{}",order.getOrderNumber(), JSON.toJSONString(closeOrderResult)); } redisTemplate.opsForZSet().remove("VipOrderPayment", order.getOrderNumber()); //删除订单 order.setDelFlag(DelFlagConstant.DELETE); this.updateById(order); } } } private LocalDateTime calculateEndTime(LocalDateTime startTime, Integer vipId) { switch (vipId) { case 1: // 月卡 return startTime.plusDays(31).withHour(23).withMinute(59).withSecond(59); case 2: // 季卡 return startTime.plusDays(90).withHour(23).withMinute(59).withSecond(59); case 3: // 半年卡 return startTime.plusDays(180).withHour(23).withMinute(59).withSecond(59); case 4: // 年卡 return startTime.plusDays(365).withHour(23).withMinute(59).withSecond(59); default: // 处理无效的 vipId 情况,例如抛出异常或记录日志 throw new ServiceException("无效的 vipId: " + vipId); } } public String getNumber(Integer size){ StringBuilder str = new StringBuilder(); for (int i = 0; i < size; i++) { str.append(Double.valueOf(Math.random() * 10).intValue()); } return str.toString(); } }