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.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.errand.constant.DelFlagConstant; import com.ruoyi.errand.domain.AddressBook; import com.ruoyi.errand.domain.AppUser; import com.ruoyi.errand.domain.Community; import com.ruoyi.errand.domain.Order; import com.ruoyi.errand.mapper.AddressBookMapper; import com.ruoyi.errand.mapper.AppUserMapper; import com.ruoyi.errand.mapper.CommunityMapper; import com.ruoyi.errand.mapper.OrderMapper; import com.ruoyi.errand.object.dto.app.ConfirmOrderDTO; import com.ruoyi.errand.object.dto.app.OrderStatsVO; import com.ruoyi.errand.object.dto.app.SetConfirmOrderDTO; import com.ruoyi.errand.object.dto.sys.FinanceStatisticsDTO; import com.ruoyi.errand.object.dto.sys.OrderPageListDTO; import com.ruoyi.errand.object.vo.app.AppUserOrderListVO; import com.ruoyi.errand.object.vo.app.ConfirmOrderVO; import com.ruoyi.errand.object.vo.app.OrderDetailVO; import com.ruoyi.errand.object.vo.app.OrderTopInfoVO; import com.ruoyi.errand.object.vo.sys.FinanceStatisticsVO; import com.ruoyi.errand.object.vo.sys.OrderPageListVO; import com.ruoyi.errand.object.vo.sys.OrderSysDetailVO; import com.ruoyi.errand.object.vo.sys.UserStatsVO; import com.ruoyi.errand.service.OrderService; import com.ruoyi.errand.utils.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; 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.math.RoundingMode; import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalUnit; import java.util.*; import java.util.stream.Collectors; @Slf4j @Service public class OrderServiceImpl extends ServiceImpl implements OrderService { @Resource private AddressBookMapper addressBookMapper; @Resource private CommunityMapper communityMapper; @Autowired private RedisTemplate redisTemplate; @Autowired private AppUserMapper appUserMapper; @Resource private DeliveryWebSocket deliveryWebSocket; @Override public ConfirmOrderVO confirmOrder(ConfirmOrderDTO confirmOrderDTO) { ConfirmOrderVO confirmOrderVO = new ConfirmOrderVO(); BeanUtils.copyProperties(confirmOrderDTO, confirmOrderVO); //小区是否存在 Community community = communityMapper.selectById(confirmOrderDTO.getCommodityId()); if (community==null||community.getDelFlag().equals(DelFlagConstant.DELETE)){ throw new ServiceException("小区不存在"); } if (community.getStatus()==1){ throw new ServiceException("小区已被冻结"); } //将地址簿信息查询出来 AddressBook addressBook = addressBookMapper.selectById(confirmOrderDTO.getAddressBookId()); confirmOrderVO.setRecipientName(addressBook.getRecipientName()); confirmOrderVO.setRecipientPhone(addressBook.getRecipientPhone()); confirmOrderVO.setAddressDetail(addressBook.getAddressDetail()); //查询用户信息,设置用户支付信息 AppUser appuser = (AppUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); confirmOrderVO.setCommunityId(confirmOrderDTO.getCommodityId()); confirmOrderVO.setCommunityName(community.getName()); //两种支付方式 if (confirmOrderDTO.getPayMethod()==0){ confirmOrderVO.setPayMethod(0); //在线支付 confirmOrderVO.setOrderAmount(community.getFeeAmount());//订单金额 confirmOrderVO.setPaymentAmount(community.getFeeAmount());//支付金额 }else if (confirmOrderDTO.getPayMethod()==1){ confirmOrderVO.setPayMethod(1); //会员支付 if (appuser.getEndTime().isBefore(LocalDateTime.now())) { //过期了 throw new ServiceException("支付错误:会员已到期"); } confirmOrderVO.setOrderAmount(community.getFeeAmount()); confirmOrderVO.setPaymentAmount(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));//支付金额 }else { throw new ServiceException("支付方式错误"); } return confirmOrderVO; } @Override public R orderPayment(ConfirmOrderDTO confirmOrderDTO) { Order order = new Order(); BeanUtils.copyProperties(confirmOrderDTO, order); //小区是否存在 Community community = communityMapper.selectById(confirmOrderDTO.getCommodityId()); if (community==null||community.getDelFlag().equals(DelFlagConstant.DELETE)){ throw new ServiceException("小区不存在"); } if (community.getStatus()==1){ throw new ServiceException("小区已被冻结"); } SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); order.setOrderNumber("QJS" + getNumber(3) + sdf.format(new Date())); //将地址簿信息查询出来 AddressBook addressBook = addressBookMapper.selectById(confirmOrderDTO.getAddressBookId()); order.setRecipientName(addressBook.getRecipientName()); order.setRecipientPhone(addressBook.getRecipientPhone()); order.setAddressDetail(addressBook.getAddressDetail()); //查询用户信息,设置用户支付信息 AppUser appuser = (AppUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (appuser.getFirstOrder()==1){ appuser.setFirstOrder(0); appUserMapper.updateById(appuser); } order.setAppUserId(appuser.getId()); order.setCommunityId(confirmOrderDTO.getCommodityId()); order.setCommunityName(community.getName()); order.setPayMethod(confirmOrderDTO.getPayMethod());//支付方式 order.setPayStatus(1);//待付款 //两种支付方式 if (confirmOrderDTO.getPayMethod()==0){ order.setPayMethod(0); //在线支付 order.setOrderAmount(community.getFeeAmount());//订单金额 order.setPaymentAmount(community.getFeeAmount());//支付金额 }else if (confirmOrderDTO.getPayMethod()==1){ order.setPayMethod(1); if (appuser.getEndTime().isBefore(LocalDateTime.now())) { //过期了 throw new ServiceException("支付错误:会员已到期"); } order.setOrderAmount(community.getFeeAmount()); order.setPaymentAmount(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP));//支付金额 }else { throw new ServiceException("支付方式错误"); } this.save(order);//先保存订单 //判断需要支付的金额是否大于0 BigDecimal paymentMoney = order.getPaymentAmount(); if ( BigDecimal.ZERO.compareTo(paymentMoney) < 0){ //调起微信支付 String agencyMatters = order.getAgencyMatters(); UniPayResult uniPayResult = PaymentUtil.uniPay(order.getOrderNumber(), paymentMoney.doubleValue(), "代办事项", agencyMatters, "", "/app/order/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", order.getId().toString()); //将支付数据添加到redis队列中,便于定时任务去校验是否完成支付,没有完成支付支付,15分钟后关闭订单。 long second = LocalDateTime.now().plusMinutes(15).toEpochSecond(ZoneOffset.UTC); redisTemplate.opsForZSet().add("OrderPayment", order.getOrderNumber(), second); return R.ok(jsonObject.toJSONString()); } //会员支付或支付金额为0直接支付成功 order.setOrderStatus(1);//待确认 order.setPayStatus(2);//已支付 order.setOrderTime(LocalDateTime.now());//下单时间 this.updateById(order); Map courier= appUserMapper.getCourierByCommunityId(order.getCommunityId()); if (courier == null || courier.isEmpty()) { log.warn("未找到社区ID={}对应的骑手", order.getCommunityId()); return R.ok(); } //todo 短信通知 sendSmsNotificationToCourier(courier,order); //小程序弹窗通知 notifyDeliveryPerson((Long) courier.get("id"), order,1);//1=新订单 //登录访问 return R.ok(order.getId().toString()); } /** * 发送短信通知给骑手 */ private void sendSmsNotificationToCourier(Map courier, Order order) { try { String phoneNumber = (String) courier.get("phone"); if (StringUtils.isBlank(phoneNumber)) { log.warn("骑手手机号为空,无法发送短信通知"); return; } // String content = String.format("您有新的跑腿订单(订单号:%s),请及时处理!", order.getOrderNumber()); //todo 调用短信服务API // SMSUtil.sendSms(order.getOrderNumber(),phoneNumber, "", ""); log.info("已发送短信通知给骑手: {}", phoneNumber); } catch (Exception e) { log.error("发送短信通知失败", e); } } /** * 发送弹窗通知 */ private void notifyDeliveryPerson(Long deliveryPersonId, Order order,Integer type) { JSONObject message = new JSONObject(); message.put("type",type==1?"new_order":"update_order"); message.put("orderId", order.getId()); message.put("orderTime", order.getOrderTime()); deliveryWebSocket.sendNotification(deliveryPersonId.toString(), message.toJSONString()); } @Override public R orderPaymentCallback(UniPayCallbackResult uniPayCallbackResult) { Order order = this.getBaseMapper().selectOne(new LambdaQueryWrapper().eq(Order::getOrderNumber, uniPayCallbackResult.getR2_OrderNo())); if(null == order || order.getPayStatus() == 2){ return R.ok(); } order.setOrderStatus(1);//待确认 order.setPayStatus(2);//已支付 order.setOrderTime(LocalDateTime.now());//下单时间 String r7TrxNo = uniPayCallbackResult.getR9_BankTrxNo(); order.setSerialNumber(r7TrxNo); this.updateById(order); Map courier= appUserMapper.getCourierByCommunityId(order.getCommunityId()); if (courier == null || courier.isEmpty()) { log.warn("未找到社区ID={}对应的骑手", order.getCommunityId()); return R.ok(); } //todo 短信通知 sendSmsNotificationToCourier(courier,order); //小程序弹窗通知 notifyDeliveryPerson((Long) courier.get("id"), order,1);//1=新订单 return R.ok(); } /** * 定时任务关闭订单 */ @Override public void closeOrder() { //订单支付数据 long second = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC); Set orderPayment = redisTemplate.opsForZSet().rangeByScore("OrderPayment", 0, second); if(orderPayment.size() > 0){ List list = this.getBaseMapper().selectList(new LambdaQueryWrapper().in(Order::getOrderNumber, orderPayment)); for (Order order : list) { if(null == order || order.getPayStatus() != 1){ //不在待支付中的,移除 redisTemplate.opsForZSet().remove("OrderPayment", 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("OrderPayment", order.getOrderNumber(), 0); log.error("关闭订单失败:{}---->{}", order.getOrderNumber(), JSON.toJSONString(closeOrderResult)); } redisTemplate.opsForZSet().remove("OrderPayment", order.getOrderNumber()); //删除订单 order.setDelFlag(DelFlagConstant.DELETE); this.updateById(order); } } } @Override public IPage getAppUserOrderList(Integer pageNum, Integer pageSize, Integer orderStatus) { IPage page = new Page<>(pageNum, pageSize); AppUser appuser = (AppUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); return this.baseMapper.getAppUserOrderList(page,orderStatus,appuser.getId()); } @Override public OrderDetailVO getOrderDetail(Integer id) { return this.baseMapper.getOrderDetail(id); } @Override public void setOrderInfo(SetConfirmOrderDTO setConfirmOrderDTO) { AppUser appuser = (AppUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); //判断订单是否存在 Order order = this.getById(setConfirmOrderDTO.getId()); if (order==null ||order.getDelFlag().equals(DelFlagConstant.DELETE) ||!Objects.equals(order.getAppUserId(), appuser.getId())){ throw new ServiceException("订单id错误"); } if (order.getOrderStatus()!=1){ throw new ServiceException("订单状态错误"); } //判断地址簿id是否存在 if (setConfirmOrderDTO.getAddressBookId()!=null){ AddressBook addressBook = addressBookMapper.selectById(setConfirmOrderDTO.getAddressBookId()); if (addressBook==null||addressBook.getDel_flag().equals(DelFlagConstant.DELETE)){ throw new ServiceException("该地址簿id不存在"); } if (!Objects.equals(addressBook.getCommunityId(), order.getCommunityId())){ throw new ServiceException("不能更改为其他小区"); } order.setRecipientPhone(addressBook.getRecipientPhone()); order.setRecipientName(addressBook.getRecipientName()); order.setAddressDetail(addressBook.getAddressDetail()); } //代办事项等更改 if (setConfirmOrderDTO.getNum()!=null){ order.setNum(setConfirmOrderDTO.getNum()); } if (setConfirmOrderDTO.getRemark()!=null){ order.setRemark(setConfirmOrderDTO.getRemark()); } if (setConfirmOrderDTO.getAgencyMatters()!=null){ order.setAgencyMatters(setConfirmOrderDTO.getAgencyMatters()); } if (setConfirmOrderDTO.getPics()!=null){ order.setPics(setConfirmOrderDTO.getPics()); } //修改 this.updateById(order); Map courier= appUserMapper.getCourierByCommunityId(order.getCommunityId()); if (courier == null || courier.isEmpty()) { log.warn("未找到社区ID={}对应的骑手", order.getCommunityId()); return; } //小程序弹窗通知 notifyDeliveryPerson((Long) courier.get("id"), order,2);//2=修改订单 } @Override public void cancelOrder(Integer id) { //判断订单 AppUser appuser = (AppUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); //判断订单是否存在 Order order = this.getById(id); if (order==null ||order.getDelFlag().equals(DelFlagConstant.DELETE) ||!Objects.equals(order.getAppUserId(), appuser.getId())){ throw new ServiceException("订单id错误"); } //判断状态 if (order.getOrderStatus()!=1){ throw new ServiceException("订单状态错误"); } //判断支付类型 if ( order.getPayMethod()==0){ //在线支付 回退 order.setOrderStatus(3);//已取消 R r = refundPayMoney(order);//退款 if (200 == r.getCode()) { this.updateById(order); } }else { order.setOrderStatus(3);//已取消 this.updateById(order); } } @Override public R refundPayMoneyCallback(RefundCallbackResult refundCallbackResult) { String code = refundCallbackResult.getR3_RefundOrderNo().substring(1); Order order = this.getOne(new LambdaQueryWrapper().eq(Order::getOrderNumber, code)); if (null == order || order.getPayStatus() == 1 || order.getOrderStatus() == 6) { return R.ok(); } order.setRefundCode(refundCallbackResult.getR5_RefundTrxNo()); order.setRefundStatus(2); order.setRefundTime(LocalDateTime.now()); this.updateById(order); return R.ok(); } @Override public OrderTopInfoVO orderTopInfo(Integer communityId) { OrderTopInfoVO orderTopInfoVO = new OrderTopInfoVO(); //总金额 Map total = this.baseMapper.getOrderTopInfoByDate(communityId,null,null); orderTopInfoVO.setTodayOrderNum(Integer.valueOf(String.valueOf(total.get("num"))) ); orderTopInfoVO.setTotalOrderAmount(new BigDecimal(String.valueOf(total.get("amount")))); //今日 LocalDateTime now = LocalDateTime.now(); LocalDateTime start = now.with(LocalTime.MIN); LocalDateTime end = now.with(LocalTime.MAX); Map today = this.baseMapper.getOrderTopInfoByDate(communityId,start,end); orderTopInfoVO.setTodayOrderNum(Integer.valueOf(String.valueOf(today.get("num")))); orderTopInfoVO.setTodayOrderAmount(new BigDecimal(String.valueOf(today.get("amount")))); //当月 YearMonth currentMonth = YearMonth.now(); start = currentMonth.atDay(1).atStartOfDay(); end = currentMonth.atEndOfMonth().atTime(LocalTime.MAX); Map mouth = this.baseMapper.getOrderTopInfoByDate(communityId,start,end); orderTopInfoVO.setMouthOrderNum(Integer.valueOf(String.valueOf(mouth.get("num")))); orderTopInfoVO.setMouthOrderAmount(new BigDecimal(String.valueOf(mouth.get("amount")))); //本季度 YearMonth thisMonth = YearMonth.now(); YearMonth firstMonthOfQuarter = thisMonth.with( Month.of(((thisMonth.getMonthValue() - 1) / 3) * 3 + 1)); YearMonth lastMonthOfQuarter = firstMonthOfQuarter.plusMonths(2); start = firstMonthOfQuarter.atDay(1).atStartOfDay(); end = lastMonthOfQuarter.atEndOfMonth().atTime(LocalTime.MAX) ; Map quarter = this.baseMapper.getOrderTopInfoByDate(communityId,start,end); orderTopInfoVO.setQuarterOrderNum(Integer.valueOf(String.valueOf(quarter.get("num")))); orderTopInfoVO.setQuarterOrderAmount(new BigDecimal(String.valueOf(quarter.get("amount")))); //本年 int year = Year.now().getValue(); start = LocalDateTime.of(year, 1, 1, 0, 0); // 1月1日 end = LocalDateTime.of(year, 12, 31, 23, 59, 59); // 12月31日 Map currentYear = this.baseMapper.getOrderTopInfoByDate(communityId,start,end); orderTopInfoVO.setYearOrderNum(Integer.valueOf(String.valueOf(currentYear.get("num")))); orderTopInfoVO.setYearOrderAmount(new BigDecimal(String.valueOf(currentYear.get("amount")))); return orderTopInfoVO; } @Override public OrderStatsVO getOrderStats(LocalDateTime start, LocalDateTime end, String datePattern, Integer communityId) { OrderStatsVO orderStatsVO = new OrderStatsVO(); // 1. 查询按时间分组的用户数 List> stats = this.getBaseMapper().countGroupByDate(start, end, datePattern , communityId); // 2. 生成完整的日期序列并填充数据 fillDateAndValue(orderStatsVO, start, end, datePattern, stats); return orderStatsVO; } @Override public IPage financeStatistics(FinanceStatisticsDTO dto) { //查询出总的数量 IPage page = new Page<>(); page.setTotal(this.getBaseMapper().selectPageTotal(dto)); List list=this.getBaseMapper().financeStatistics(dto); page.setRecords(list); page.setSize(dto.getPageSize()); page.setCurrent(dto.getPageNum()); return page; } @Override public List export(FinanceStatisticsDTO dto) { return this.getBaseMapper().export(dto); } @Override public IPage getOrderPageList(OrderPageListDTO dto) { IPage page = new Page<>(dto.getPageNum(),dto.getPageSize()); return this.getBaseMapper().getOrderPageList(page,dto); } @Override public OrderSysDetailVO detail(Integer id) { return this.getBaseMapper().detail(id); } @Override public List orderExport(OrderPageListDTO dto) { return this.getBaseMapper().orderExport(dto); } /** * 填充空余时间 */ private void fillDateAndValue(OrderStatsVO vo, LocalDateTime start, LocalDateTime end, String datePattern, List> stats) { List allDates = generateDateRange(start, end, datePattern); Map numMap = convertNumsToMap(stats); Map amountMap = convertAmountToMap(stats); List dates = new ArrayList<>(); List nums = new ArrayList<>(); List amounts = new ArrayList<>(); for (String date : allDates) { dates.add(date); nums.add(numMap.getOrDefault(date, 0)); // 无数据的日期补0 amounts.add(amountMap.getOrDefault(date,BigDecimal.ZERO.setScale(2, BigDecimal.ROUND_HALF_UP))); } vo.setDate(dates); vo.setNumList(nums); vo.setAmountList(amounts); } private Map convertNumsToMap(List> stats) { return stats.stream() .collect(Collectors.toMap( stat -> String.valueOf(stat.get("date")), stat -> Integer.valueOf(String.valueOf(stat.get("num"))) )); } private Map convertAmountToMap(List> stats) { return stats.stream() .collect(Collectors.toMap( stat -> String.valueOf(stat.get("date")), stat -> new BigDecimal(String.valueOf(stat.get("amount"))) )); } private List generateDateRange(LocalDateTime start, LocalDateTime end, String datePattern) { List dates = new ArrayList<>(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern(datePattern); TemporalUnit unit = getTemporalUnit(datePattern); LocalDateTime current = getInitialDateTime(start, datePattern); while (!current.isAfter(end)) { dates.add(current.format(formatter)); current = incrementDateTime(current, unit); } return dates; } private TemporalUnit getTemporalUnit(String datePattern) { switch (datePattern) { case "HH时": return ChronoUnit.HOURS; case "EEEE": case "dd日": case "yyyy-MM-dd": return ChronoUnit.DAYS; case "MM月": return ChronoUnit.MONTHS; default: return ChronoUnit.DAYS; } } private LocalDateTime getInitialDateTime(LocalDateTime datetime, String datePattern) { switch (datePattern) { case "HH时": return datetime.withMinute(0).withSecond(0).withNano(0); case "MM月": return datetime.withDayOfMonth(1); default: return datetime; } } private LocalDateTime incrementDateTime(LocalDateTime current, TemporalUnit unit) { if (unit == ChronoUnit.HOURS) return current.plusHours(1); if (unit == ChronoUnit.DAYS) return current.plusDays(1); if (unit == ChronoUnit.MONTHS) return current.plusMonths(1); return current.plusDays(1); } /** * 返回订单支付金额 */ public R refundPayMoney(Order order) { //开始退款 BigDecimal paymentAmount = order.getPaymentAmount(); if (BigDecimal.ZERO.compareTo(order.getPaymentAmount()) < 0) {//支付的金额是否大于0 //微信退款 RefundResult refund = PaymentUtil.refund(order.getOrderNumber(), "R" + order.getOrderNumber(), paymentAmount.doubleValue(), "/app/order/refundPayMoneyCallback"); if (!"100".equals(refund.getRa_Status())) { return R.fail(refund.getRc_CodeMsg());//退款失败 } } return R.ok(); } 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(); } }