Пример #1
0
 public Map<String, DatePickerDayConfig> getDayConfigMap(
     LocalDate firstDay, LocalDate lastDay, List<CalendarConfig> calendarConfigs) {
   Map<String, DatePickerDayConfig> dayConfigs = new HashMap<>();
   for (LocalDate date = firstDay; date.isBefore(lastDay); date = date.plusDays(1)) {
     DatePickerDayConfig dayConfig = new DatePickerDayConfig();
     dayConfig.setSelectable(Boolean.FALSE);
     for (CalendarConfig calendarConfig : calendarConfigs) {
       for (CalendarWeekDay weekDay : calendarConfig.getCalendarWeekDays()) {
         if (weekDay.ordinal() + 1 == date.getDayOfWeek()) {
           if (!isHoliday(date, calendarConfig)) {
             if (calendarConfig.getStartDate().compareTo(date) <= 0
                 && calendarConfig.getEndDate().compareTo(date) >= 0) {
               dayConfig.setSelectable(Boolean.TRUE);
             }
           }
         }
       }
     }
     dayConfigs.put(date.toString(), dayConfig);
   }
   return dayConfigs;
 }
Пример #2
0
  public boolean isHoliday(LocalDate date, CalendarConfig calendarConfig) {
    String holidayKey = calendarConfig.getHolidayKey();
    boolean isHoliday = false;
    if (!holidayKey.equals(NO_HOLIDAY_KEY)) {
      String[] holidayKeySplit = holidayKey.split("-");
      String country = holidayKeySplit[0];
      String region = holidayKeySplit[1];

      HolidayManager countryHolidays =
          HolidayManager.getInstance(ManagerParameters.create(HolidayCalendar.valueOf(country)));
      isHoliday = countryHolidays.isHoliday(date, region);
    }
    return isHoliday;
  }
Пример #3
0
  private void addTimeSlot(
      List<TimeSlot> timeSlots,
      LocalDateTime time,
      CalendarConfig config,
      BigDecimal pricePerMinDuration) {
    TimeSlot timeSlot = new TimeSlot();
    timeSlot.setDate(time.toLocalDate());
    timeSlot.setStartTime(time.toLocalTime());
    timeSlot.setEndTime(time.toLocalTime().plusMinutes(config.getMinDuration()));
    timeSlot.setConfig(config);
    timeSlot.setPricePerMinDuration(pricePerMinDuration);

    // only add timeSlot if timeSlots does not already contain an entry that overlaps
    if (!overlaps(timeSlot, timeSlots)) {
      timeSlots.add(timeSlot);
    }
  }
Пример #4
0
  public List<TimeSlot> getTimeSlotsForDate(
      LocalDate selectedDate,
      List<CalendarConfig> allCalendarConfigs,
      List<Booking> existingBookings,
      Boolean onlyFutureTimeSlots,
      Boolean preventOverlapping)
      throws CalendarConfigException {

    List<CalendarConfig> calendarConfigs =
        calendarConfigUtil.getCalendarConfigsMatchingDate(allCalendarConfigs, selectedDate);
    Iterator<CalendarConfig> iterator = calendarConfigs.iterator();
    while (iterator.hasNext()) {
      CalendarConfig calendarConfig = iterator.next();
      if (isHoliday(selectedDate, calendarConfig)) {
        iterator.remove();
      }
    }

    List<TimeSlot> timeSlots = new ArrayList<>();
    if (calendarConfigs.size() > 0) {
      LocalDate today = new LocalDate(DEFAULT_TIMEZONE);

      // sort all calendar configurations for selected date by start time
      Collections.sort(calendarConfigs);

      CalendarConfig previousConfig = null;
      LocalDateTime time = null;
      LocalDateTime now = new LocalDateTime(DEFAULT_TIMEZONE);

      // generate list of bookable time slots
      for (CalendarConfig config : calendarConfigs) {
        LocalDateTime startDateTime = getLocalDateTime(selectedDate, config.getStartTime());
        if (time == null) {
          // on first iteration
          time = startDateTime;
        } else {
          if (time.plusMinutes(previousConfig.getMinInterval()).equals(startDateTime)) {
            // contiguous bookings possible
            // time = time;
          } else {
            // reset basePriceLastConfig as this is a non contiguous offer
            previousConfig = null;
            time = startDateTime;
          }
        }
        LocalDateTime endDateTime = getLocalDateTime(selectedDate, config.getEndTime());
        while (time.plusMinutes(config.getMinDuration()).compareTo(endDateTime) <= 0) {
          BigDecimal pricePerMinDuration;
          if (previousConfig == null) {
            pricePerMinDuration = config.getBasePrice();
          } else {
            BigDecimal previousConfigBasePricePerMinute = getPricePerMinute(previousConfig);
            pricePerMinDuration =
                previousConfigBasePricePerMinute.multiply(
                    new BigDecimal(previousConfig.getMinInterval()), MathContext.DECIMAL128);
            BigDecimal basePricePerMinute = getPricePerMinute(config);
            pricePerMinDuration =
                pricePerMinDuration.add(
                    basePricePerMinute.multiply(
                        new BigDecimal(config.getMinDuration() - previousConfig.getMinInterval()),
                        MathContext.DECIMAL128));
            previousConfig = null;
          }
          pricePerMinDuration = pricePerMinDuration.setScale(2, RoundingMode.HALF_EVEN);
          if (onlyFutureTimeSlots) {
            if (selectedDate.isAfter(today) || time.isAfter(now)) {
              addTimeSlot(timeSlots, time, config, pricePerMinDuration);
            }
          } else {
            addTimeSlot(timeSlots, time, config, pricePerMinDuration);
          }
          time = time.plusMinutes(config.getMinInterval());
        }
        previousConfig = config;
      }
      // sort time slots by time
      Collections.sort(timeSlots);

      // decrease court count for every blocking booking
      for (TimeSlot timeSlot : timeSlots) {
        checkForBookedCourts(timeSlot, existingBookings, preventOverlapping);
      }
    }
    return timeSlots;
  }
Пример #5
0
  public OfferDurationPrice getOfferDurationPrice(
      LocalDate selectedDate, LocalTime selectedTime, Offer selectedOffer)
      throws CalendarConfigException {
    List<CalendarConfig> configs = calendarConfigDAO.findFor(selectedDate);
    List<Booking> confirmedBookings = bookingDAO.findBlockedBookingsForDate(selectedDate);

    // convert to required data structure
    Map<Offer, List<CalendarConfig>> offerConfigMap = new HashMap<>();
    for (CalendarConfig config : configs) {
      for (Offer offer : config.getOffers()) {
        if (offer.equals(selectedOffer)) {
          List<CalendarConfig> list = offerConfigMap.get(offer);
          if (list == null) {
            list = new ArrayList<>();
          }
          list.add(config);

          // sort by start time
          Collections.sort(list);
          offerConfigMap.put(offer, list);
        }
      }
    }

    OfferDurationPrice offerDurationPrices = null;

    Iterator<Map.Entry<Offer, List<CalendarConfig>>> iterator =
        offerConfigMap.entrySet().iterator();
    // for every offer
    while (iterator.hasNext()) {
      Map.Entry<Offer, List<CalendarConfig>> entry = iterator.next();
      Offer offer = entry.getKey();
      List<CalendarConfig> configsForOffer = entry.getValue();

      // make sure the first configuration starts before the requested booking time
      if (selectedTime.compareTo(configsForOffer.get(0).getStartTime()) < 0) {
        continue;
      }

      LocalDateTime endTime = null;
      Integer duration = configsForOffer.get(0).getMinDuration();
      BigDecimal pricePerMinute;
      BigDecimal price = null;
      CalendarConfig previousConfig = null;
      Map<Integer, BigDecimal> durationPriceMap = new TreeMap<>();
      Boolean isContiguous = true;
      for (CalendarConfig config : configsForOffer) {

        // make sure there is no gap between calendar configurations
        if (endTime == null) {
          // first run
          endTime =
              getLocalDateTime(selectedDate, selectedTime).plusMinutes(config.getMinDuration());
        } else {
          // break if there are durations available and calendar configs are not contiguous
          if (!durationPriceMap.isEmpty()) {
            // we substract min interval before the comparison as it has been added during the last
            // iteration
            LocalDateTime configStartDateTime =
                getLocalDateTime(selectedDate, config.getStartTime());
            if (!endTime.minusMinutes(config.getMinInterval()).equals(configStartDateTime)) {
              break;
            }
          }
        }

        Integer interval = config.getMinInterval();

        pricePerMinute = getPricePerMinute(config);

        // as long as the endTime is before the end time configured in the calendar
        LocalDateTime configEndDateTime = getLocalDateTime(selectedDate, config.getEndTime());
        while (endTime.compareTo(configEndDateTime) <= 0) {
          TimeSlot timeSlot = new TimeSlot();
          timeSlot.setDate(selectedDate);
          timeSlot.setStartTime(selectedTime);
          timeSlot.setEndTime(endTime.toLocalTime());
          timeSlot.setConfig(config);
          Long bookingSlotsLeft = getBookingSlotsLeft(timeSlot, offer, confirmedBookings);

          // we only allow contiguous bookings for any given offer
          if (bookingSlotsLeft < 1) {
            isContiguous = false;
            break;
          }

          if (price == null) {
            // see if previousConfig endTime - minInterval matches the selected time. if so, take
            // half of the previous config price as a basis
            if (previousConfig != null
                && previousConfig
                    .getEndTime()
                    .minusMinutes(previousConfig.getMinInterval())
                    .equals(selectedTime)) {
              BigDecimal previousConfigPricePerMinute = getPricePerMinute(previousConfig);
              price =
                  previousConfigPricePerMinute.multiply(
                      new BigDecimal(previousConfig.getMinInterval()), MathContext.DECIMAL128);
              price =
                  price.add(
                      pricePerMinute.multiply(
                          new BigDecimal(duration - previousConfig.getMinInterval()),
                          MathContext.DECIMAL128));
            } else {
              price =
                  pricePerMinute.multiply(
                      new BigDecimal(duration.toString()), MathContext.DECIMAL128);
            }
          } else {
            // add price for additional interval
            price =
                price.add(
                    pricePerMinute.multiply(
                        new BigDecimal(interval.toString()), MathContext.DECIMAL128));
          }
          price = price.setScale(2, RoundingMode.HALF_EVEN);
          durationPriceMap.put(duration, price);

          // increase the duration by the configured minimum interval and determine the new end time
          // for the next iteration
          duration += interval;
          endTime = endTime.plusMinutes(interval);
        }

        if (!durationPriceMap.isEmpty()) {
          OfferDurationPrice odp = new OfferDurationPrice();
          odp.setOffer(offer);
          odp.setDurationPriceMap(durationPriceMap);
          odp.setConfig(config);
          offerDurationPrices = odp;
        }

        if (!isContiguous) {
          // we only allow coniguous bookings for one offer. process next offer
          //                    previousConfig = null;
          break;
        }
        previousConfig = config;
      }
    }
    return offerDurationPrices;
  }
Пример #6
0
 public BigDecimal getPricePerMinute(CalendarConfig config) {
   return config
       .getBasePrice()
       .divide(new BigDecimal(config.getMinDuration().toString()), MathContext.DECIMAL128);
 }