package com.chuanghai.ihotel.service.impl; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.metadata.WriteSheet; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.chuanghai.ihotel.aop.LoginCheckAspect; import com.chuanghai.ihotel.common.exception.BizCodeEnume; import com.chuanghai.ihotel.common.exception.RRException; import com.chuanghai.ihotel.common.utils.MyQuery; import com.chuanghai.ihotel.common.utils.PageParam; import com.chuanghai.ihotel.common.utils.PageUtils; import com.chuanghai.ihotel.component.PayComponent; import com.chuanghai.ihotel.component.WaterElectricComponent; import com.chuanghai.ihotel.component.WeiXiaoComponent; import com.chuanghai.ihotel.config.JXNXSPayConfig; import com.chuanghai.ihotel.config.RabbitMQConfig; import com.chuanghai.ihotel.constant.TimeConstant; import com.chuanghai.ihotel.controller.request.ConfrimOrderRequest; import com.chuanghai.ihotel.controller.request.OrderQueryRequest; import com.chuanghai.ihotel.controller.request.StatisticalReportRequest; import com.chuanghai.ihotel.controller.request.SubmitOrderRequest; import com.chuanghai.ihotel.dao.HotelOrderDao; import com.chuanghai.ihotel.dto.*; import com.chuanghai.ihotel.entity.*; import com.chuanghai.ihotel.enums.*; import com.chuanghai.ihotel.service.*; import com.chuanghai.ihotel.util.CellStyleModel; import com.chuanghai.ihotel.util.CommonUtil; import com.chuanghai.ihotel.util.FiledUtil; import com.chuanghai.ihotel.vo.*; import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.usermodel.*; import org.apache.xmlbeans.impl.piccolo.util.DuplicateKeyException; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.net.URLEncoder; import java.sql.SQLIntegrityConstraintViolationException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAdjusters; import java.util.*; import java.util.stream.Collectors; @Slf4j @Service("hotelOrderService") public class HotelOrderServiceImpl extends ServiceImpl implements HotelOrderService { @Autowired private SystemSettingService systemSettingService; @Autowired private RoomTypeService roomTypeService; @Autowired private RoomRealtimeStatuService roomRealtimeStatuService; @Autowired private HotelUserService hotelUserService; @Autowired private RoomService roomService; @Autowired private HotelOrderBillService orderBillService; @Autowired private RoomDoorLockDataService doorLockService; @Autowired private RoomDoorLockDataService roomDoorLockDataService; @Autowired private SystemNoticeService systemNoticeService; @Autowired private RoomThirdSettingService roomThirdSettingService; @Autowired private PayComponent payComponent; @Autowired private WeiXiaoComponent weiXiaoComponent; @Autowired WaterElectricComponent waterElectricComponent; @Autowired private JXNXSPayConfig jxnxsPayConfig; @Autowired private RabbitTemplate rabbitTemplate; @Autowired private RabbitMQConfig rabbitMQConfig; @Autowired private StatisticalReportService statisticalReportService; private DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); private String noticeTemplate = "办理入住成功,您的房号为【%s】,房间锁密码为:【%s】,密码有效时间为【%s】,请妥善保管,退房后密码自动失效。"; @Override public PageUtils queryPage(PageParam pageParam, OrderQueryRequest request) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq(request.getOrderId() != null, "id", request.getOrderId()); queryWrapper.eq(StringUtils.hasText(request.getDeleteFlag()), "delete_flag", request.getDeleteFlag()); if (StringUtils.hasText(request.getKeyWord())) { queryWrapper.and(e -> e.like("order_no", request.getKeyWord()).or().like("room_no", request.getKeyWord())); } //queryWrapper.like(StringUtils.hasText(request.getOrderNo()), "order_no", request.getOrderNo()); queryWrapper.eq(StringUtils.hasText(request.getUserFlag()), "user_flag", request.getUserFlag()); queryWrapper.eq(StringUtils.hasText(request.getUserName()), "user_name", request.getUserName()); queryWrapper.eq(StringUtils.hasText(request.getUserPhone()), "user_phone", request.getUserPhone()); queryWrapper.eq(StringUtils.hasText(request.getRoomNo()), "room_no", request.getRoomNo()); queryWrapper.eq(request.getRoomTypeId() != null, "room_type_id", request.getRoomTypeId()); String statu = request.getStatu(); if (StringUtils.hasText(statu)) { if (statu.contains("-")) { String[] split = statu.split("-"); queryWrapper.eq("order_statu", split[0]); queryWrapper.eq("biz_statu", split[1]); } else { queryWrapper.eq("order_statu", statu); } } queryWrapper.ge(request.getEnableStartTime() != null, "enable_start_time", request.getEnableStartTime()); queryWrapper.le(request.getEnableStartTime() != null, "enable_end_time", request.getEnableStartTime()); queryWrapper.ge(request.getPayTime1() != null, "pay_time", request.getPayTime1()); queryWrapper.le(request.getPayTime2() != null, "pay_time", request.getPayTime2()); queryWrapper.ge(request.getCreateTime1() != null, "create_time", request.getCreateTime1()); queryWrapper.le(request.getCreateTime2() != null, "create_time", request.getCreateTime2()); IPage page = this.page( new MyQuery().getPage(pageParam), queryWrapper ); return new PageUtils(page); } @Override public List queryList(OrderQueryRequest request) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq(request.getOrderId() != null, "id", request.getOrderId()); queryWrapper.eq(StringUtils.hasText(request.getDeleteFlag()), "delete_flag", request.getDeleteFlag()); if (StringUtils.hasText(request.getKeyWord())) { queryWrapper.and(e -> e.like("order_no", request.getKeyWord()).or().like("room_no", request.getKeyWord())); } //queryWrapper.like(StringUtils.hasText(request.getOrderNo()), "order_no", request.getOrderNo()); queryWrapper.eq(StringUtils.hasText(request.getUserFlag()), "user_flag", request.getUserFlag()); queryWrapper.eq(StringUtils.hasText(request.getUserName()), "user_name", request.getUserName()); queryWrapper.eq(StringUtils.hasText(request.getUserPhone()), "user_phone", request.getUserPhone()); queryWrapper.eq(StringUtils.hasText(request.getRoomNo()), "room_no", request.getRoomNo()); queryWrapper.eq(request.getRoomTypeId() != null, "room_type_id", request.getRoomTypeId()); String statu = request.getStatu(); if (StringUtils.hasText(statu)) { if (statu.contains("-")) { String[] split = statu.split("-"); queryWrapper.eq("order_statu", split[0]); queryWrapper.eq("biz_statu", split[1]); } else { queryWrapper.eq("order_statu", statu); } } queryWrapper.ge(request.getEnableStartTime() != null, "enable_start_time", request.getEnableStartTime()); queryWrapper.le(request.getEnableStartTime() != null, "enable_end_time", request.getEnableStartTime()); queryWrapper.ge(request.getPayTime1() != null, "pay_time", request.getPayTime1()); queryWrapper.le(request.getPayTime2() != null, "pay_time", request.getPayTime2()); queryWrapper.ge(request.getCreateTime1() != null, "create_time", request.getCreateTime1()); queryWrapper.le(request.getCreateTime2() != null, "create_time", request.getCreateTime2()); List list = this.list(queryWrapper); return list; } @Override public List listForAdmin( OrderQueryRequest request) { request.setDeleteFlag("1"); // 1未删除 List orderList = this.queryList(request); Set ids = orderList.stream().map(order -> order.getId()).collect(Collectors.toSet()); if (ids.size() > 0) { List orderBillList = orderBillService.findByOrderIds(ids); Map orderBillMap = orderBillList.stream().collect(Collectors.toMap(HotelOrderBillEntity::getHotelOrderId, e -> e)); List voList = orderList.stream().map(order -> { AdminOrderIndexVO vo = new AdminOrderIndexVO(); vo.setOrder(order); vo.setOrderBill(orderBillMap.get(order.getId())); return vo; }).collect(Collectors.toList()); List objectVOList = new ArrayList<>(); voList.forEach(adminOrderIndexVO -> { BigDecimal waterPayment = BigDecimal.ZERO; BigDecimal electricPayment = BigDecimal.ZERO; BigDecimal totalPayment = BigDecimal.ZERO; //住房总押金 单价 * 天数 int housDay = 0; HotelOrderEntity order = adminOrderIndexVO.getOrder(); HotelOrderBillEntity orderBill = adminOrderIndexVO.getOrderBill(); //电费计算 String startOfElectric = this.check(orderBill, "startOfElectric"); String endOfElectric = this.check(orderBill, "endOfElectric"); String priceOfElectric = this.check(orderBill, "priceOfElectric"); String calculateElectric = this.calculate(startOfElectric, endOfElectric, priceOfElectric); electricPayment = electricPayment.add(new BigDecimal(calculateElectric)).setScale(2, BigDecimal.ROUND_UP); //水费计算 String startOfWater = this.check(orderBill, "startOfWater"); String endOfWater = this.check(orderBill, "endOfWater"); String priceOfWater = this.check(orderBill, "priceOfWater"); String calculateWater = this.calculate(startOfWater, endOfWater, priceOfWater); waterPayment = waterPayment.add(new BigDecimal(calculateWater)).setScale(2, BigDecimal.ROUND_UP); //收款总计 totalPayment = totalPayment.add(order.getPayAmount()).setScale(2, BigDecimal.ROUND_UP); housDay = order.getEnableEndTime().getDayOfMonth() - order.getEnableStartTime().getDayOfMonth(); SystemSettingEntity systemSetting = systemSettingService.get(); //住房总押金 单价 * 天数 BigDecimal totalHousDeposit = systemSetting.getDeposit().multiply(new BigDecimal(housDay)).setScale(2, BigDecimal.ROUND_UP); adminOrderIndexVO.setAllOfElectricPayment(electricPayment); adminOrderIndexVO.setAllOfWaterAmount(waterPayment); adminOrderIndexVO.setAllOfReceiveAmount(totalHousDeposit); BigDecimal refundPayment = totalPayment.add(totalHousDeposit).subtract(electricPayment).subtract(waterPayment).setScale(2, BigDecimal.ROUND_UP); adminOrderIndexVO.setRefundPayment(refundPayment); objectVOList.add(adminOrderIndexVO); }); return objectVOList; } return null; } @Override public PageUtils userOrderPage(PageParam pageParam, OrderQueryRequest request) { pageParam.setOrderField("create_time"); pageParam.setOrder("desc"); LoginUserDTO loginUserVO = LoginCheckAspect.threadLocal.get(); request.setUserFlag(loginUserVO.getCardNumber()); request.setDeleteFlag("1"); // 1未删除 PageUtils pageUtils = this.queryPage(pageParam, request); List list = pageUtils.getList(); List collect = list.stream().map(e -> { UserOrderIndexVO vo = new UserOrderIndexVO(); BeanUtils.copyProperties(e, vo); return vo; }).collect(Collectors.toList()); pageUtils.setList(collect); return pageUtils; } @Override public PageUtils pageForAdmin(PageParam pageParam, OrderQueryRequest request) { pageParam.setOrderField("create_time"); pageParam.setOrder("desc"); request.setDeleteFlag("1"); // 1未删除 PageUtils pageUtils = this.queryPage(pageParam, request); List orderList = pageUtils.getList(); Set ids = orderList.stream().map(order -> order.getId()).collect(Collectors.toSet()); if (ids.size() > 0) { List orderBillList = orderBillService.findByOrderIds(ids); Map orderBillMap = orderBillList.stream().collect(Collectors.toMap(HotelOrderBillEntity::getHotelOrderId, e -> e)); List voList = orderList.stream().map(order -> { AdminOrderIndexVO vo = new AdminOrderIndexVO(); vo.setOrder(order); vo.setOrderBill(orderBillMap.get(order.getId())); return vo; }).collect(Collectors.toList()); List objectVOList = new ArrayList<>(); voList.forEach(adminOrderIndexVO -> { BigDecimal waterPayment = BigDecimal.ZERO; BigDecimal electricPayment = BigDecimal.ZERO; BigDecimal totalPayment = BigDecimal.ZERO; //住房总押金 单价 * 天数 int housDay = 0; HotelOrderEntity order = adminOrderIndexVO.getOrder(); HotelOrderBillEntity orderBill = adminOrderIndexVO.getOrderBill(); //电费计算 String startOfElectric = this.check(orderBill, "startOfElectric"); String endOfElectric = this.check(orderBill, "endOfElectric"); String priceOfElectric = this.check(orderBill, "priceOfElectric"); String calculateElectric = this.calculate(startOfElectric, endOfElectric, priceOfElectric); electricPayment = electricPayment.add(new BigDecimal(calculateElectric)).setScale(2, BigDecimal.ROUND_UP); //水费计算 String startOfWater = this.check(orderBill, "startOfWater"); String endOfWater = this.check(orderBill, "endOfWater"); String priceOfWater = this.check(orderBill, "priceOfWater"); String calculateWater = this.calculate(startOfWater, endOfWater, priceOfWater); waterPayment = waterPayment.add(new BigDecimal(calculateWater)).setScale(2, BigDecimal.ROUND_UP); //收款总计 totalPayment = totalPayment.add(order.getPayAmount()).setScale(2, BigDecimal.ROUND_UP); housDay = order.getEnableEndTime().getDayOfMonth() - order.getEnableStartTime().getDayOfMonth(); SystemSettingEntity systemSetting = systemSettingService.get(); //住房总押金 单价 * 天数 BigDecimal totalHousDeposit = systemSetting.getDeposit().multiply(new BigDecimal(housDay)).setScale(2, BigDecimal.ROUND_UP); adminOrderIndexVO.setAllOfElectricPayment(electricPayment); adminOrderIndexVO.setAllOfWaterAmount(waterPayment); adminOrderIndexVO.setAllOfReceiveAmount(totalHousDeposit); BigDecimal refundPayment = totalPayment.add(totalHousDeposit).subtract(electricPayment).subtract(waterPayment).setScale(2, BigDecimal.ROUND_UP); adminOrderIndexVO.setRefundPayment(refundPayment); objectVOList.add(adminOrderIndexVO); }); pageUtils.setList(objectVOList); } return pageUtils; } /** * 导出订单 * * @param request */ @Override public void downOrder(HttpServletResponse response, OrderQueryRequest request) { List hotelAndBillVOList = new ArrayList<>(); List list = this.listForAdmin(request); list.forEach(orderAndBill -> { HotelAndBillVO hotelAndBillVO = new HotelAndBillVO(); HotelOrderEntity order = orderAndBill.getOrder(); HotelOrderBillEntity orderBill = orderAndBill.getOrderBill(); hotelAndBillVO.setOrderNo(order.getOrderNo()); hotelAndBillVO.setRoomNo(order.getRoomNo()); hotelAndBillVO.setOrderStatu(order.getOrderStatu()); hotelAndBillVO.setPayTime(order.getPayTime()); //电费计算 String startOfElectric = this.check(orderBill, "startOfElectric"); String endOfElectric = this.check(orderBill, "endOfElectric"); String priceOfElectric = this.check(orderBill, "priceOfElectric"); String calculateElectric = this.calculate(startOfElectric, endOfElectric, priceOfElectric); hotelAndBillVO.setElectricity(calculateElectric); //水费计算 String startOfWater = this.check(orderBill, "startOfWater"); String endOfWater = this.check(orderBill, "endOfWater"); String priceOfWater = this.check(orderBill, "priceOfWater"); String calculateWater = this.calculate(startOfWater, endOfWater, priceOfWater); hotelAndBillVO.setWaterBill(calculateWater); SystemSettingEntity systemSetting = systemSettingService.get(); //收预付款 hotelAndBillVO.setAcceptPayment(systemSetting.getFreeTotal()); //退预付款 BigDecimal refundPayment = systemSetting.getFreeTotal().subtract(order.getPayAmount()); hotelAndBillVO.setRefundPayment(refundPayment); hotelAndBillVO.setCreateTime(order.getCreateTime()); hotelAndBillVO.setPayTime(order.getPayTime()); hotelAndBillVOList.add(hotelAndBillVO); }); String fileName; try { fileName = URLEncoder.encode("订单管理" + new Date().getTime(), "UTF-8"); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); EasyExcel.write(response.getOutputStream(), HotelAndBillVO.class).sheet("订单管理").doWrite(hotelAndBillVOList); } catch (Exception e) { e.printStackTrace(); } } /** * 获取上月第一天 * * @return */ public String getLastMonthFirstDayStr() { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); int year = cal.get(Calendar.YEAR); int month = cal.get(Calendar.MONTH); int date = cal.get(Calendar.DATE); cal.set(year, month, date, 0, 0, 1); //获取当前时间上一个月 cal.add(Calendar.MONTH, -1); //获取上个月的第一天 cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DAY_OF_MONTH)); return df.format(cal.getTime()); } /** * 获取上月最后一天 * * @return */ public String getLastMonthLastDayStr() { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Calendar cal = Calendar.getInstance(); cal.setTime(new Date()); int year = cal.get(Calendar.YEAR); int month = cal.get(Calendar.MONTH); int date = cal.get(Calendar.DATE); cal.set(year, month, date, 23, 59, 59); //获取当前时间上一个月 cal.add(Calendar.MONTH, -1); //获取上个月的最后一天 cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH)); return df.format(cal.getTime()); } /** * 统计报表 */ @Override public void statisticalReport() { String lastMonthFirstDayStr = this.getLastMonthFirstDayStr(); String lastMonthLastDayStr = this.getLastMonthLastDayStr(); DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); LocalDateTime firstDayOfMonth = LocalDateTime.parse(lastMonthFirstDayStr, df); LocalDateTime lastDayOfMonth = LocalDateTime.parse(lastMonthLastDayStr, df); List voList = this.queryByMonthHotelOrder(firstDayOfMonth, lastDayOfMonth); BigDecimal waterPayment = BigDecimal.ZERO; BigDecimal electricPayment = BigDecimal.ZERO; BigDecimal totalPayment = BigDecimal.ZERO; //住房总押金 单价 * 天数 int housDay = 0; StatisticalReportEntity statisticalReport = new StatisticalReportEntity(); for (AdminOrderIndexVO orderAndBill : voList) { HotelOrderEntity order = orderAndBill.getOrder(); HotelOrderBillEntity orderBill = orderAndBill.getOrderBill(); //电费计算 String startOfElectric = this.check(orderBill, "startOfElectric"); String endOfElectric = this.check(orderBill, "endOfElectric"); String priceOfElectric = this.check(orderBill, "priceOfElectric"); String calculateElectric = this.calculate(startOfElectric, endOfElectric, priceOfElectric); electricPayment = electricPayment.add(new BigDecimal(calculateElectric)).setScale(2, BigDecimal.ROUND_UP); //水费计算 String startOfWater = this.check(orderBill, "startOfWater"); String endOfWater = this.check(orderBill, "endOfWater"); String priceOfWater = this.check(orderBill, "priceOfWater"); String calculateWater = this.calculate(startOfWater, endOfWater, priceOfWater); waterPayment = waterPayment.add(new BigDecimal(calculateWater)).setScale(2, BigDecimal.ROUND_UP); //收款总计 totalPayment = totalPayment.add(order.getPayAmount()).setScale(2, BigDecimal.ROUND_UP); housDay = order.getEnableEndTime().getDayOfMonth() - order.getEnableStartTime().getDayOfMonth(); } StatisticalReportEntity statisticalReportEntity = new StatisticalReportEntity(); // statisticalReportEntity = queryByMonth(firstDayOfMonth); // if (statisticalReportEntity != null) { // statisticalReport.setId(statisticalReportEntity.getId()); // } SystemSettingEntity systemSetting = systemSettingService.get(); //住房总押金 单价 * 天数 BigDecimal totalHousDeposit = systemSetting.getDeposit().multiply(new BigDecimal(housDay)).setScale(2, BigDecimal.ROUND_UP); statisticalReport.setTime(firstDayOfMonth); statisticalReport.setElectricPayment(electricPayment); statisticalReport.setWaterPayment(waterPayment); //退预付款 = 水电减免 + 住房押金 - 水费总额 - 电费总额 statisticalReport.setRefundPayment(systemSetting.getFreeTotal().add(totalHousDeposit).subtract(electricPayment).subtract(waterPayment)); statisticalReport.setTotalPayment(totalPayment); statisticalReportService.save(statisticalReport); } @Override public String check(HotelOrderBillEntity orderBill, String field) { String result = "0.0"; boolean isPWaterNull = FiledUtil.checkObjFieldsIsNull(orderBill, field); if (!isPWaterNull) { switch (field){ case "startOfWater" : result = orderBill.getStartOfWater(); break; case "endOfWater" : result = orderBill.getEndOfWater(); break; case "priceOfWater" : result = orderBill.getPriceOfWater(); break; case "startOfElectric" : result = orderBill.getStartOfElectric(); break; case "endOfElectric" : result = orderBill.getEndOfElectric(); break; case "priceOfElectric" : result = orderBill.getPriceOfElectric(); break; } result = result.equals("0E-8") ? "0.0" : result; } return result; } public StatisticalReportEntity queryByMonth(LocalDateTime dateTime) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("time", dateTime); return statisticalReportService.getOne(wrapper); } @Override public List queryByMonthHotelOrder(LocalDateTime startTime, LocalDateTime endTime) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("order_statu", "5"); if (startTime != null && endTime != null) { wrapper.between("pay_time", startTime, endTime); } List orderList = this.list(wrapper); List voList = new ArrayList<>(); Set ids = orderList.stream().map(order -> order.getId()).collect(Collectors.toSet()); if (ids.size() > 0) { List orderBillList = orderBillService.findByOrderIds(ids); Map orderBillMap = orderBillList.stream().collect(Collectors.toMap(HotelOrderBillEntity::getHotelOrderId, e -> e)); voList = orderList.stream().map(order -> { AdminOrderIndexVO vo = new AdminOrderIndexVO(); vo.setOrder(order); vo.setOrderBill(orderBillMap.get(order.getId())); return vo; }).collect(Collectors.toList()); } return voList; } /** * 计算水电费用 * * @param start * @param end * @param price * @return */ @Override public String calculate(String start, String end, String price) { Double sum = Double.parseDouble(end) - Double.parseDouble(start); String result = String.valueOf(sum * Double.parseDouble(price)); result = result.equals("-0.0") ? "0.0" : result; return result; } @Override public HotelOrderEntity findByOrderNo(String orderNo) { QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("order_no", orderNo); queryWrapper.last("limit 1"); return this.getOne(queryWrapper); } @Override public ConfirmOrderVO confirmOrder(ConfrimOrderRequest request) { SystemSettingEntity systemSetting = systemSettingService.get(); // 入住日期校验 Integer preDay = systemSetting.getPreDay(); if (Math.abs(ChronoUnit.DAYS.between(request.getStartTime(), LocalDate.now())) > preDay) { throw new RRException(BizCodeEnume.PARAMETER_ERROR, "只能预定" + preDay + "天之内的房源"); } // 查询房源是否充足 Long roomTypeId = request.getRoomTypeId(); RoomTypeEntity roomType = roomTypeService.myGetById(roomTypeId); if (roomType == null) { throw new RRException(BizCodeEnume.PARAMETER_ERROR, "房型不存在"); } else { if (roomType.getRoomNum() < 1) { throw new RRException(BizCodeEnume.PARAMETER_ERROR, "该房型客房不足"); } else { roomService.queryRoomNum(roomTypeId); } } LocalDateTime startTime = CommonUtil.localDateToTime(request.getStartTime(), TimeConstant.INTO_TIME); LocalDateTime endTime = CommonUtil.localDateToTime(request.getEndTime(), TimeConstant.OUT_TIME); long days = ChronoUnit.DAYS.between(request.getStartTime(), request.getEndTime()); int busyNum = roomRealtimeStatuService.getBusyNum(roomTypeId, startTime, endTime); int enableNum = roomType.getRoomNum() - busyNum; // 查询房型价格 BigDecimal discountPrice = roomType.getDiscountPrice(); // 查询押金 //BigDecimal deposit = systemSetting.getDeposit(); //BigDecimal totalAmount = discountPrice.add(deposit).multiply(new BigDecimal(Long.toString(days))); //2023-06-30 更改为 押金 -(水费补助 + 电费补助) BigDecimal totalAmount = systemSetting.getDeposit().subtract(systemSetting.getFreeQuotaOfElectric().multiply(systemSetting.getPriceOfElectric()).add(systemSetting.getFreeQuotaOfWater().multiply(systemSetting.getPriceOfWater()))); // 封装确认订单vo ConfirmOrderVO vo = new ConfirmOrderVO(); vo.setStartTime(startTime); vo.setEndTime(endTime); vo.setNums(Integer.valueOf((int) days)); vo.setRoomTypeId(roomTypeId); vo.setRoomTypeName(roomType.getTypeName()); vo.setFreeNum(enableNum >= 0 ? enableNum : 0); vo.setDiscountPrice(roomType.getDiscountPrice()); vo.setDeposit(systemSetting.getDeposit()); vo.setPriceOfWater(systemSetting.getPriceOfWater()); vo.setPriceOfElectric(systemSetting.getPriceOfElectric()); vo.setFreeQuotaOfElectric(systemSetting.getPriceOfElectric()); vo.setFreeQuotaOfWater(systemSetting.getFreeQuotaOfWater()); vo.setFreeQuotaOfElectric(systemSetting.getFreeQuotaOfElectric()); vo.setFreeTotal(systemSetting.getFreeTotal()); vo.setTotalAmount(totalAmount.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : totalAmount); return vo; } @Override public void orderPaySuccess(Long orderId, String orderNo, String realPayAmount, LocalDateTime payTime) { HotelOrderEntity order = null; if (orderId != null) { order = this.getById(orderId); } else { if (StringUtils.hasText(orderNo)) { order = this.findByOrderNo(orderNo); } } if (order == null) { log.warn("修改订单状态:订单【{}】不存在", orderId); return; } if (OrderStatuEnum.WAIT_PAY.getCode().equalsIgnoreCase(order.getOrderStatu())) { if (Math.abs(order.getPayAmount().subtract(new BigDecimal(realPayAmount)).doubleValue()) < 0.01) { // 订单最终支付金额验证成功 if (payTime == null) { order.setPayTime(LocalDateTime.now()); } else { order.setPayTime(payTime); } order.setOrderStatu(OrderStatuEnum.FINISH_PAY.getCode()); this.updateById(order); } } } @Transactional @Override public OrderSubmitVO submitOrder(SubmitOrderRequest request) { LoginUserDTO loginUserVO = LoginCheckAspect.threadLocal.get(); String cardNumber = loginUserVO.getCardNumber(); // 身份校验 HotelUserEntity hotelUser = hotelUserService.findByCardNumber(cardNumber); if (hotelUser == null) { throw new RRException(BizCodeEnume.PERMISSION_DENIED, "非法用户"); } String identityType = hotelUser.getIdentityType(); if (!UserIdentityTypeEnum.STAFF_OF_TEACHER.getCode().equals(identityType)) { throw new RRException(BizCodeEnume.PERMISSION_DENIED, "非法用户-非教职工"); } SystemSettingEntity systemSetting = systemSettingService.get(); // 入住时间校验 Integer preDay = systemSetting.getPreDay(); if (Math.abs(ChronoUnit.DAYS.between(request.getEnableStartTime().toLocalDate(), LocalDate.now())) > preDay) { throw new RRException(BizCodeEnume.PARAMETER_ERROR, "只能预定" + preDay + "天之内的房源"); } // 校验房型 RoomTypeEntity roomType = roomTypeService.myGetById(request.getRoomTypeId()); if (roomType == null) { throw new RRException(BizCodeEnume.PARAMETER_ERROR, "房型不存在"); } // 金额校验 SystemSettingEntity data = systemSettingService.get(); long days = ChronoUnit.DAYS.between(request.getEnableStartTime().toLocalDate(), request.getEnableEndTime().toLocalDate()); BigDecimal deposit =data.getDeposit().subtract(data.getFreeQuotaOfElectric().multiply(data.getPriceOfElectric()).add(data.getFreeQuotaOfWater().multiply(data.getPriceOfWater()))); BigDecimal totalAmount = deposit.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : deposit; if (Math.abs(totalAmount.subtract(request.getPayAmount()).doubleValue()) > 0.01) { throw new RRException(BizCodeEnume.ORDER_SUBMIT_ERROR, "订单金额校验失败"); } // 锁定房源 long orderId = IdWorker.getId(); LockRoomDTO lockRoomDTO = LockRoomDTO.builder() .roomTypeId(roomType.getId()) .bizId(orderId) .startTime(request.getEnableStartTime()) .endTime(request.getEnableEndTime()) .build(); Long roomId = roomRealtimeStatuService.lockRoomByRoomTypeId(lockRoomDTO); if (roomId == null) { throw new RRException(BizCodeEnume.ORDER_SUBMIT_ERROR, "【" + roomType.getTypeName() + "】房型房源不足,锁定房源失败"); } RoomEntity room = roomService.getById(roomId); if (room == null) { throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "系统异常,根据id查询房间失败"); } // 订单落库 HotelOrderEntity hotelOrder = new HotelOrderEntity(); BeanUtils.copyProperties(request, hotelOrder); hotelOrder.setId(orderId); hotelOrder.setOrderNo(IdWorker.getTimeId()); hotelOrder.setUserFlag(cardNumber); hotelOrder.setRoomId(roomId); hotelOrder.setRoomNo(room.getRoomNo()); hotelOrder.setRoomTypeName(roomType.getTypeName()); hotelOrder.setRoomTypeMasterImg(roomType.getTypeImage().split(",")[0]); hotelOrder.setCreateTime(LocalDateTime.now()); if (totalAmount.doubleValue() == 0) { hotelOrder.setOrderStatu(OrderStatuEnum.FINISH_PAY.getCode()); hotelOrder.setBizStatu(OrderBillStatuEnum.FINISH.getCode()); } else { hotelOrder.setOrderStatu(OrderStatuEnum.WAIT_PAY.getCode()); hotelOrder.setBizStatu(OrderBillStatuEnum.WAIT_HANDLE.getCode()); } hotelOrder.setDeleteFlag("1"); // 0删除、1正常 this.save(hotelOrder); if (totalAmount.doubleValue() != 0) { // 发送延迟消息 EventMessageDTO eventMessage = EventMessageDTO.builder() .eventMessageType(EventMessageTypeEnum.PRODUCT_ORDER_NEW.name()) .accountNo(loginUserVO.getCardNumber()) .bizId(orderId) .build(); rabbitTemplate.convertAndSend(rabbitMQConfig.getOrderEventExchange(), rabbitMQConfig.getOrderCloseDelayRoutingKey(), eventMessage); } // 返回支付参数 String payUrl = null; if (totalAmount.doubleValue() > 0) { payUrl = String.format(jxnxsPayConfig.getPayUrl(), hotelOrder.getId(), request.getPayAmount()); } return OrderSubmitVO.builder().orderId(hotelOrder.getId()).payAmount(totalAmount).payUrl(payUrl).build(); } @Override public void handleOrderMessage(EventMessageDTO eventMessageDTO) { String messageType = eventMessageDTO.getEventMessageType(); try { if (EventMessageTypeEnum.PRODUCT_ORDER_NEW.name().equalsIgnoreCase(messageType)) { // 关单消息 this.closeOrder(eventMessageDTO); } } catch (Exception e) { log.error("订单消费者消费失败:{}", eventMessageDTO); throw new RRException(BizCodeEnume.MQ_CONSUME_EXCEPTION); } } @Override public void closeOrder(EventMessageDTO eventMessageDTO) { Long orderId = eventMessageDTO.getBizId(); String cardNumber = eventMessageDTO.getAccountNo(); HotelOrderEntity orderEntity = this.getById(orderId); if (orderEntity == null) { log.warn("关单:订单【{}】不存在", orderId); return; } // 判断订单状态 if (!orderEntity.getOrderStatu().equalsIgnoreCase(OrderStatuEnum.WAIT_PAY.getCode())) { log.info("关单:订单不是初始状态待支付:{}", eventMessageDTO); return; } // 未支付,向第三方支付平台查询状态 Map map = payComponent.queryOrderStatus(orderEntity.getId().toString()); log.info("关单:订单支付状态查询结果,【{}】"+"订单号:"+orderEntity.getId().toString(), map); String payStatus = map.get("status"); if ("1".equalsIgnoreCase(payStatus)) { // 已经完成支付 String amount = map.get("trade_amount"); String payTimeStr = map.get("trade_pay_time"); LocalDateTime payTime = LocalDateTime.parse(payTimeStr, TimeConstant.DEFAULT_DTF); String realPayAmount = new BigDecimal(amount).divide(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_UP).toString(); // 分转成元 this.orderPaySuccess(orderId, orderEntity.getOrderNo(), realPayAmount, payTime); } else { // 未支付,取消订单 this.cancelOrder(cardNumber, orderId); } } @Override public boolean cancelOrder(String userFlag, Long orderId) { HotelOrderEntity orderEntity = this.getById(orderId); if (orderEntity == null) { log.warn("取消订单:订单【{}】不存在", orderId); return false; } if (!orderEntity.getUserFlag().equalsIgnoreCase(userFlag)) { log.warn("取消订单:操作越权,非法取消订单,订单原用户【】,操作用户【】", orderEntity.getUserFlag(), userFlag); throw new RRException(BizCodeEnume.PERMISSION_DENIED, "不能取消非自己的订单"); } orderEntity.setOrderStatu(OrderStatuEnum.CANCEL.getCode()); this.updateById(orderEntity); // 释放库存 roomRealtimeStatuService.releaseByBizId(orderEntity.getId()); return true; } @Override public UserOrderDetailVO userOrderDetail(Long orderId) { HotelOrderEntity orderEntity = userGetOrderById(orderId); UserOrderDetailVO detailVO = new UserOrderDetailVO(); detailVO.setOrderId(orderId); BeanUtils.copyProperties(orderEntity, detailVO); RoomTypeEntity roomType = roomTypeService.myGetById(orderEntity.getRoomTypeId()); detailVO.setRoomTypeUsualPrice(roomType.getUsualPrice()); detailVO.setRoomTypeDiscountPrice(roomType.getDiscountPrice()); // 订单状态为已入住之后,查询水电等相关信息 String orderStatu = orderEntity.getOrderStatu(); if (Integer.valueOf(orderStatu).intValue() >= Integer.valueOf(OrderStatuEnum.HOLD_ON.getCode()).intValue()) { HotelOrderBillEntity orderBill = orderBillService.findByOrderId(orderId); if (orderBill == null) { throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "用户订单详情-订单状态错误"); } BeanUtils.copyProperties(orderBill, detailVO); } // 订单状态为已入住,查询密码锁等相关信息 if (OrderStatuEnum.HOLD_ON.getCode().equals(orderStatu)) { RoomDoorLockDataEntity lockData = roomDoorLockDataService.queryByOrderId(orderId); if (lockData == null) { throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "用户订单详情-锁密码获取失败"); } detailVO.setLockRealtimePassword(lockData.getLockRealtimePassword()); detailVO.setPasswordStartTime(lockData.getStartTime()); detailVO.setPasswordEndTime(lockData.getEndTime()); } return detailVO; } @Override public OrderSubmitVO getOrderPayParam(Long orderId) { HotelOrderEntity orderEntity = userGetOrderById(orderId); if (!OrderStatuEnum.WAIT_PAY.getCode().equalsIgnoreCase(orderEntity.getOrderStatu())) { throw new RRException(BizCodeEnume.PARAMETER_ERROR, "当前订单状态为非待支付状态"); } // 支付参数 String payUrl = String.format(jxnxsPayConfig.getPayUrl(), orderEntity.getId(), orderEntity.getPayAmount()); return OrderSubmitVO.builder().orderId(orderId).payUrl(payUrl).build(); } @Override public OrderBillHandleVO getOrderBillInfo(Long orderId) { HotelOrderEntity order = userGetOrderById(orderId); if (!OrderStatuEnum.WAIT_BILL.getCode().equals(order.getOrderStatu())) { throw new RRException(BizCodeEnume.PARAMETER_ERROR, "当前订单不是带结账状态"); } BillHandleResultDTO dto = orderBillService.getBill(orderId); OrderBillHandleVO vo = new OrderBillHandleVO(); vo.setOrderId(orderId); vo.setBillId(dto.getBillId()); vo.setFlag(dto.getResultFlag()); vo.setSupperFee(dto.getRealFee()); vo.setRefundFee(dto.getReturnFee()); return vo; } @Override public void userDeleteOrder(Long orderId) { HotelOrderEntity order = userGetOrderById(orderId); deleteOrder(order); } @Override public boolean adminDeleteOrder(Long orderId) { HotelOrderEntity orderEntity = this.getById(orderId); return deleteOrder(orderEntity); } private boolean deleteOrder(HotelOrderEntity orderEntity) { String orderStatu = orderEntity.getOrderStatu(); // 已取消、待支付、已完成订单才可以被删除 if (!(OrderStatuEnum.CANCEL.getCode().equalsIgnoreCase(orderStatu) || OrderStatuEnum.WAIT_PAY.getCode().equalsIgnoreCase(orderStatu) || OrderStatuEnum.FINISH.getCode().equalsIgnoreCase(orderStatu))) { throw new RRException(BizCodeEnume.PERMISSION_DENIED, "当前订单不可删除"); } UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("id", orderEntity.getId()); updateWrapper.set("delete_flag", "0"); // 0表示删除 updateWrapper.last("limit 1"); return this.update(null, updateWrapper); } @Override public void userCancelOrder(Long orderId) { HotelOrderEntity order = userGetOrderById(orderId); // 待支付订单才可以被取消 if (!OrderStatuEnum.WAIT_PAY.getCode().equalsIgnoreCase(order.getOrderStatu())) { throw new RRException(BizCodeEnume.PERMISSION_DENIED, "当前订单不可取消"); } // 释放房间锁定 roomRealtimeStatuService.releaseByBizId(orderId); UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("id", orderId); updateWrapper.set("order_statu", OrderStatuEnum.CANCEL.getCode()); updateWrapper.last("limit 1"); this.update(null, updateWrapper); } @Transactional @Override public void userHoldOrder(Long orderId) { HotelOrderEntity order = userGetOrderById(orderId); LocalDateTime nowTime= LocalDateTime.now(); //订单必须要在到了最早入住时间才能办理入住 if(nowTime.isBefore(order.getEnableStartTime())){ throw new RRException(BizCodeEnume.PARAMETER_ERROR, "未到入住时间,无法办理入住"); } // 支付完成状态的订单才可以办理入住 if (!OrderStatuEnum.FINISH_PAY.getCode().equalsIgnoreCase(order.getOrderStatu())) { throw new RRException(BizCodeEnume.PERMISSION_DENIED, "订单状态异常"); } // 订单有效时间校验 LocalDateTime now = LocalDateTime.now(); if (now.isAfter(order.getEnableEndTime())) { throw new RRException(BizCodeEnume.PERMISSION_DENIED, "订单超过有效时间"); } Long roomId = order.getRoomId(); // 水电抄表 => 生成结账单 orderBillService.generateBill(orderId, roomId); // 门锁密码 RoomDoorLockDataEntity roomDoorLockDataEntity = doorLockService.generatePassword(order); // 更新房态状态 roomRealtimeStatuService.userHoldOrder(orderId); // 更新订单状态 UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("id", orderId); updateWrapper.set("order_statu", OrderStatuEnum.HOLD_ON.getCode()); updateWrapper.last("limit 1"); this.update(null, updateWrapper); // 发送通知(优化:可以使用异步的方式发送通知) try { String lockRealtimePassword = roomDoorLockDataEntity.getLockRealtimePassword(); LocalDateTime startTime = roomDoorLockDataEntity.getStartTime(); LocalDateTime endTime = roomDoorLockDataEntity.getEndTime(); String content = String.format(noticeTemplate, order.getRoomNo(), lockRealtimePassword, dtf.format(startTime) + "-" + dtf.format(endTime)); weiXiaoComponent.sendNotice(Arrays.asList(order.getUserFlag()), "公寓办理入住成功", "办理入住成功", content, null); RoomThirdSettingEntity roomThird = roomThirdSettingService.findByRoomId(order.getRoomId()); if (roomThird == null) { throw new RRException(BizCodeEnume.UNKNOW_EXCEPTION, "门锁不存在"); } if (roomThird != null) { //开电表 waterElectricComponent.remoteDisconnect(roomThird.getElectricId(), OpenElectricStatuEnum.OPEN.getCode()); System.out.println("办理入住-开电成功,订单编号"+order.getOrderNo()+"电表码:"+roomThird.getElectricId()); } } catch (Exception e) { throw new RRException(BizCodeEnume.THIRD_PARTY_SERVICE_CALL_FAILED, "办理入住失败"); } } String returnOrderTemplate = "订单id【%s】,用户【%s】,房间号【%s】已退房,需要清扫"; @Override public OrderBillHandleVO userReturnOrder(Long orderId) { HotelOrderEntity order = userGetOrderById(orderId); // 入住状态的订单才可以办理退房 if (!OrderStatuEnum.HOLD_ON.getCode().equalsIgnoreCase(order.getOrderStatu())) { throw new RRException(BizCodeEnume.PERMISSION_DENIED, "订单状态异常"); } // 结算订单 BigDecimal payAmount = order.getPayAmount(); String orderStatu = OrderStatuEnum.WAIT_BILL.getCode(); BillHandleResultDTO billHandleResult = orderBillService.calcBill(orderId); if ("1".equals(billHandleResult.getResultFlag())) { // 待退款 if (billHandleResult.getReturnFee().doubleValue() > 0) { // TODO 发起退款 } else { // 自动完结订单 orderStatu = OrderStatuEnum.FINISH.getCode(); } }else{//待结账 orderStatu = OrderStatuEnum.WAIT_BILL.getCode(); } // 密码锁密码删除 roomDoorLockDataService.deleteByOrderId(orderId); // 更新房态状态 roomRealtimeStatuService.userReturnOrder(orderId); // 更新订单状态 UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.eq("id", orderId); updateWrapper.set("order_statu", orderStatu); if(orderStatu.equals(OrderStatuEnum.WAIT_BILL.getCode())){ updateWrapper.set("order_statu", orderStatu); } updateWrapper.last("limit 1"); this.update(null, updateWrapper); // 发送通知消息 优化:可以使用异步的方式 String format = String.format(returnOrderTemplate, orderId, order.getUserName(), order.getRoomNo()); systemNoticeService.addNotice("用户退房通知", format, SystemNoticeTypeEnum.USER_RETURN); OrderBillHandleVO vo = new OrderBillHandleVO(); vo.setOrderId(orderId); vo.setBillId(billHandleResult.getBillId()); if (OrderStatuEnum.FINISH.getCode().equals(orderStatu)) { vo.setFlag("3"); } else { vo.setFlag(billHandleResult.getResultFlag()); vo.setRefundFee(billHandleResult.getReturnFee()); vo.setSupperFee(billHandleResult.getRealFee()); } return vo; } @Override public List getRoomUseInfoByOrderIds(Set orderIds) { if (orderIds.size() <= 0) { return null; } return this.baseMapper.getRoomUseInfoByOrderIds(orderIds); } @Override public void autoReturnOrder() { // 查询都有已经到退房时间但是未退房订单 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("order_statu", OrderStatuEnum.HOLD_ON.getCode()); queryWrapper.le("enable_end_time", CommonUtil.localDateToTime(LocalDate.now(), TimeConstant.OUT_TIME)); List orderEntityList = this.list(queryWrapper); if (orderEntityList.size() > 0) { List waitBillOrderIdList = new ArrayList<>(); List finishOrderIdList = new ArrayList<>(); orderEntityList.forEach(order -> { Long orderId = order.getId(); // 结算订单 BigDecimal payAmount = order.getPayAmount(); if (payAmount.doubleValue() == 0) { finishOrderIdList.add(orderId); } else { BillHandleResultDTO billHandleResult = orderBillService.calcBill(orderId); if ("1".equals(billHandleResult.getResultFlag()) && billHandleResult.getReturnFee().doubleValue() == 0) { // 待退款 finishOrderIdList.add(orderId); } else { waitBillOrderIdList.add(orderId); } } // 密码锁密码删除 roomDoorLockDataService.deleteByOrderId(orderId); // 更新房态状态 roomRealtimeStatuService.userReturnOrder(orderId); // 发送通知消息 优化:可以使用异步的方式 String format = String.format(returnOrderTemplate, orderId, order.getUserName(), order.getRoomNo()); systemNoticeService.addNotice("用户退房通知", format, SystemNoticeTypeEnum.USER_RETURN); }); if (waitBillOrderIdList.size() > 0) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.in("id", orderEntityList.stream().map(e -> e.getId()).collect(Collectors.toList())); updateWrapper.set("order_statu", OrderStatuEnum.WAIT_BILL.getCode()); this.update(null, updateWrapper); } if (finishOrderIdList.size() > 0) { UpdateWrapper updateWrapper = new UpdateWrapper<>(); updateWrapper.in("id", orderEntityList.stream().map(e -> e.getId()).collect(Collectors.toList())); updateWrapper.set("order_statu", OrderStatuEnum.FINISH.getCode()); this.update(null, updateWrapper); } } } /** * 用户根据订单id获取订单 * * @param orderId * @return */ private HotelOrderEntity userGetOrderById(Long orderId) { HotelOrderEntity orderEntity = this.getById(orderId); if (orderEntity == null) { throw new RRException(BizCodeEnume.PARAMETER_ERROR, "订单不存在,无效的orderId"); } if ("0".equalsIgnoreCase(orderEntity.getDeleteFlag())) { throw new RRException(BizCodeEnume.PARAMETER_ERROR, "订单不存在,订单已删除"); } LoginUserDTO loginUserVO = LoginCheckAspect.threadLocal.get(); String userFlag = loginUserVO.getCardNumber(); if (!orderEntity.getUserFlag().equalsIgnoreCase(userFlag)) { throw new RRException(BizCodeEnume.PERMISSION_DENIED, "非自己的订单"); } return orderEntity; } }