Преглед изворни кода

线上预订 商家端 加时修改效验

qinxuyang пре 1 месец
родитељ
комит
306ea68dd7

+ 241 - 0
alien-store/src/main/java/shop/alien/store/service/impl/StoreReservationServiceImpl.java

@@ -12,14 +12,21 @@ import shop.alien.entity.store.UserReservation;
 import shop.alien.entity.store.UserReservationTable;
 import shop.alien.entity.store.UserReservationOrder;
 import shop.alien.entity.store.vo.StoreReservationListVo;
+import shop.alien.entity.store.StoreBookingBusinessHours;
+import shop.alien.entity.store.StoreBookingSettings;
+import shop.alien.entity.store.EssentialHolidayComparison;
+import shop.alien.entity.store.vo.StoreBusinessInfoVo;
 import shop.alien.mapper.StoreReservationMapper;
 import shop.alien.mapper.UserReservationTableMapper;
+import shop.alien.mapper.EssentialHolidayComparisonMapper;
 import shop.alien.store.config.BaseRedisService;
 import shop.alien.store.listener.RedisKeyExpirationHandler;
 import shop.alien.store.service.StoreBookingTableService;
 import shop.alien.store.service.StoreInfoService;
 import shop.alien.store.service.StoreReservationService;
 import shop.alien.store.service.UserReservationOrderService;
+import shop.alien.store.service.StoreBookingBusinessHoursService;
+import shop.alien.store.service.StoreBookingSettingsService;
 import shop.alien.store.strategy.merchantPayment.MerchantPaymentStrategy;
 import shop.alien.store.strategy.merchantPayment.MerchantPaymentStrategyFactory;
 import shop.alien.store.util.ali.AliSms;
@@ -61,6 +68,9 @@ public class StoreReservationServiceImpl extends ServiceImpl<StoreReservationMap
     private final LifeNoticeMapper lifeNoticeMapper;
     private final LifeUserMapper lifeUserMapper;
     private final MerchantPaymentStrategyFactory merchantPaymentStrategyFactory;
+    private final StoreBookingBusinessHoursService storeBookingBusinessHoursService;
+    private final StoreBookingSettingsService storeBookingSettingsService;
+    private final EssentialHolidayComparisonMapper essentialHolidayComparisonMapper;
 
     /** 预约状态:已取消 */
     private static final int STATUS_CANCELLED = 3;
@@ -572,6 +582,9 @@ public class StoreReservationServiceImpl extends ServiceImpl<StoreReservationMap
         // 校验:不能超过下一个已确认预约的开始时间
         validateAddTimeNotExceedNextReservation(reservation, normalizedAddTimeStart, newEndTime);
 
+        // 校验:不能超过营业时间的结束时间
+        validateAddTimeNotExceedBusinessHours(reservation, newEndTime);
+
         // 更新预约结束时间
         reservation.setEndTime(newEndTime);
         boolean updateResult = this.updateById(reservation);
@@ -855,6 +868,234 @@ public class StoreReservationServiceImpl extends ServiceImpl<StoreReservationMap
     }
 
     /**
+     * 校验加时不能超过营业时间的结束时间
+     * 
+     * @param reservation 预约信息
+     * @param newEndTime 新的结束时间(yyyy-MM-dd HH:mm:ss格式)
+     */
+    private void validateAddTimeNotExceedBusinessHours(UserReservation reservation, String newEndTime) {
+        try {
+            if (reservation == null || reservation.getStoreId() == null || reservation.getReservationDate() == null) {
+                log.warn("预约信息不完整,跳过营业时间校验");
+                return;
+            }
+
+            // 查询门店的预订设置
+            StoreBookingSettings settings = storeBookingSettingsService.getByStoreId(reservation.getStoreId());
+            if (settings == null || settings.getId() == null) {
+                log.warn("门店未配置预订设置,跳过营业时间校验,storeId={}", reservation.getStoreId());
+                return;
+            }
+
+            // 查询营业时间列表
+            List<StoreBookingBusinessHours> businessHoursList = storeBookingBusinessHoursService.getListBySettingsId(settings.getId());
+            if (businessHoursList == null || businessHoursList.isEmpty()) {
+                log.warn("门店未配置营业时间,跳过营业时间校验,storeId={}", reservation.getStoreId());
+                return;
+            }
+
+            // 解析预约日期
+            Date reservationDate = reservation.getReservationDate();
+            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+            String reservationDateStr = dateFormat.format(reservationDate);
+
+            // 查找匹配的营业时间
+            StoreBookingBusinessHours matchedBusinessHours = null;
+
+            // 先查找特殊营业时间(business_type=2,兼容旧值1)
+            // 特殊营业时间的特征:有 holidayDate 或 essentialId 或 holidayType 不为空
+            for (StoreBookingBusinessHours businessHours : businessHoursList) {
+                Integer businessType = businessHours.getBusinessType();
+                // 判断是否为特殊营业时间:新值2,或旧值1且有关联的节假日信息
+                boolean isSpecialBusinessHours = false;
+                if (businessType != null) {
+                    if (businessType == 2) {
+                        // 新值:2 表示特殊营业时间
+                        isSpecialBusinessHours = true;
+                    } else if (businessType == 1) {
+                        // 旧值:1 可能是特殊营业时间,需要检查是否有节假日信息
+                        if (businessHours.getEssentialId() != null || 
+                            businessHours.getHolidayDate() != null || 
+                            (businessHours.getHolidayType() != null && !businessHours.getHolidayType().trim().isEmpty())) {
+                            isSpecialBusinessHours = true;
+                        }
+                    }
+                }
+                
+                if (isSpecialBusinessHours) {
+                    // 特殊营业时间:需要匹配 essential_holiday_comparison 表中的日期范围
+                    if (businessHours.getEssentialId() != null) {
+                        EssentialHolidayComparison holiday = essentialHolidayComparisonMapper.selectById(businessHours.getEssentialId());
+                        if (holiday != null && holiday.getStartTime() != null && holiday.getEndTime() != null) {
+                            // 判断预约日期是否在节假日的日期范围内
+                            Date startTime = holiday.getStartTime();
+                            Date endTime = holiday.getEndTime();
+                            if (!reservationDate.before(startTime) && !reservationDate.after(endTime)) {
+                                matchedBusinessHours = businessHours;
+                                break;
+                            }
+                        }
+                    } else if (businessHours.getHolidayDate() != null) {
+                        // 如果没有 essentialId,使用 holidayDate 匹配
+                        if (reservationDateStr.equals(businessHours.getHolidayDate())) {
+                            matchedBusinessHours = businessHours;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            // 如果没有匹配到特殊营业时间,使用正常营业时间(business_type=1,兼容旧值0)
+            if (matchedBusinessHours == null) {
+                matchedBusinessHours = businessHoursList.stream()
+                        .filter(h -> {
+                            Integer businessType = h.getBusinessType();
+                            // 兼容旧值:0 和新值:1 都表示正常营业时间
+                            return businessType != null && (businessType == 1 || businessType == 0);
+                        })
+                        .findFirst()
+                        .orElse(null);
+            }
+
+            // 如果 store_booking_business_hours 中没有找到匹配的营业时间,则从 store_business_info 查询
+            if (matchedBusinessHours == null) {
+                log.info("store_booking_business_hours 中未找到匹配的营业时间,尝试从 store_business_info 查询,storeId={}", reservation.getStoreId());
+                matchedBusinessHours = findBusinessHoursFromStoreBusinessInfo(reservation, reservationDate, reservationDateStr);
+            }
+
+            if (matchedBusinessHours == null) {
+                log.warn("未找到匹配的营业时间,跳过营业时间校验");
+                return;
+            }
+
+            // 如果是全天营业(booking_time_type=1),不限制结束时间
+            if (matchedBusinessHours.getBookingTimeType() != null && matchedBusinessHours.getBookingTimeType() == 1) {
+                log.info("全天营业,不限制结束时间");
+                return;
+            }
+
+            // 获取营业时间的结束时间
+            String businessEndTime = matchedBusinessHours.getEndTime();
+            if (businessEndTime == null || businessEndTime.trim().isEmpty()) {
+                log.warn("营业时间结束时间为空,跳过校验");
+                return;
+            }
+
+            // 标准化新的结束时间,提取日期部分
+            String normalizedNewEndTime = normalizeDateTime(newEndTime);
+            if (normalizedNewEndTime == null) {
+                log.warn("新的结束时间格式错误,跳过校验,newEndTime={}", newEndTime);
+                return;
+            }
+
+            // 从新的结束时间中提取日期部分(用于构建营业时间的完整日期时间)
+            // normalizedNewEndTime 格式:yyyy-MM-dd HH:mm:ss
+            String newEndTimeDateStr = normalizedNewEndTime.substring(0, 10); // 提取 yyyy-MM-dd
+
+            // 将营业时间的结束时间转换为完整的日期时间格式
+            // businessEndTime 是 HH:mm 格式,需要结合新结束时间的日期
+            String businessEndDateTimeStr = newEndTimeDateStr + " " + businessEndTime.trim() + ":00";
+            String normalizedBusinessEndTime = normalizeDateTime(businessEndDateTimeStr);
+            if (normalizedBusinessEndTime == null) {
+                log.warn("营业时间结束时间格式错误,跳过校验,businessEndTime={}", businessEndTime);
+                return;
+            }
+
+            // 比较新的结束时间和营业时间的结束时间
+            int comparison = compareTime(normalizedNewEndTime, normalizedBusinessEndTime);
+            if (comparison > 0) {
+                // 新的结束时间超过了营业时间的结束时间
+                throw new RuntimeException("加时后结束时间不能超过营业时间,营业结束时间为:" + businessEndTime);
+            }
+
+            log.info("加时校验通过,新的结束时间={},营业结束时间={}", normalizedNewEndTime, normalizedBusinessEndTime);
+        } catch (Exception e) {
+            if (e instanceof RuntimeException) {
+                throw e;
+            }
+            log.error("校验加时是否超过营业时间失败", e);
+            // 校验失败时,抛出异常以阻止加时操作
+            throw new RuntimeException("校验营业时间失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 从 store_business_info 表中查找匹配的营业时间
+     * 
+     * @param reservation 预约信息
+     * @param reservationDate 预约日期
+     * @param reservationDateStr 预约日期字符串(yyyy-MM-dd格式)
+     * @return 匹配的营业时间对象(包装为 StoreBookingBusinessHours 格式),未找到返回 null
+     */
+    private StoreBookingBusinessHours findBusinessHoursFromStoreBusinessInfo(
+            UserReservation reservation, Date reservationDate, String reservationDateStr) {
+        try {
+            // 查询门店的营业时间列表
+            List<StoreBusinessInfoVo> storeBusinessInfoList = storeInfoService.getStoreInfoBusinessHours(reservation.getStoreId());
+            if (storeBusinessInfoList == null || storeBusinessInfoList.isEmpty()) {
+                log.warn("门店未配置 store_business_info 营业时间,storeId={}", reservation.getStoreId());
+                return null;
+            }
+
+            StoreBusinessInfoVo matchedBusinessInfo = null;
+
+            // 先查找特殊营业时间(business_type=2)
+            for (StoreBusinessInfoVo businessInfo : storeBusinessInfoList) {
+                if (businessInfo.getBusinessType() != null && businessInfo.getBusinessType() == 2) {
+                    // 特殊营业时间:需要匹配 essential_holiday_comparison 表中的日期范围
+                    if (businessInfo.getEssentialId() != null && !businessInfo.getEssentialId().trim().isEmpty()) {
+                        try {
+                            Integer essentialId = Integer.parseInt(businessInfo.getEssentialId().trim());
+                            EssentialHolidayComparison holiday = essentialHolidayComparisonMapper.selectById(essentialId);
+                            if (holiday != null && holiday.getStartTime() != null && holiday.getEndTime() != null) {
+                                // 判断预约日期是否在节假日的日期范围内
+                                Date startTime = holiday.getStartTime();
+                                Date endTime = holiday.getEndTime();
+                                if (!reservationDate.before(startTime) && !reservationDate.after(endTime)) {
+                                    matchedBusinessInfo = businessInfo;
+                                    break;
+                                }
+                            }
+                        } catch (NumberFormatException e) {
+                            log.warn("门店营业时间关联的节假日ID格式错误,storeId={}, essentialId={}", 
+                                    reservation.getStoreId(), businessInfo.getEssentialId());
+                        }
+                    } else if (businessInfo.getBusinessDate() != null) {
+                        // 如果没有 essentialId,使用 businessDate 匹配
+                        if (reservationDateStr.equals(businessInfo.getBusinessDate())) {
+                            matchedBusinessInfo = businessInfo;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            // 如果没有匹配到特殊营业时间,使用正常营业时间(business_type=1)
+            if (matchedBusinessInfo == null) {
+                matchedBusinessInfo = storeBusinessInfoList.stream()
+                        .filter(h -> h.getBusinessType() != null && h.getBusinessType() == 1)
+                        .findFirst()
+                        .orElse(null);
+            }
+
+            if (matchedBusinessInfo == null) {
+                log.warn("store_business_info 中未找到匹配的营业时间,storeId={}", reservation.getStoreId());
+                return null;
+            }
+
+            // 将 StoreBusinessInfoVo 转换为 StoreBookingBusinessHours 格式(仅用于返回 endTime)
+            StoreBookingBusinessHours result = new StoreBookingBusinessHours();
+            result.setEndTime(matchedBusinessInfo.getEndTime());
+            result.setBookingTimeType(null); // store_business_info 没有 booking_time_type,设为 null 表示非全天
+            log.info("从 store_business_info 找到匹配的营业时间,endTime={}", matchedBusinessInfo.getEndTime());
+            return result;
+        } catch (Exception e) {
+            log.error("从 store_business_info 查询营业时间失败", e);
+            return null;
+        }
+    }
+
+    /**
      * 校验预约是否过期
      * 判断当前时间是否超过预约日期 + 结束时间
      */