meeting-room-booking-system / mrbs-code

MRBS application code
Other
120 stars 58 forks source link

limit the duration of each appointment to more than a few hours #3729

Open flyxj opened 3 weeks ago

flyxj commented 3 weeks ago

Is it possible to limit the duration of each appointment to more than a few hours (e.g. 3 hours), appointments of less than 3 hours are not allowed.

flyxj commented 3 weeks ago

not a daily reservation limit, but a reservation limit per time.

flyxj commented 3 weeks ago

I edited the get_slot_selector() function in the edit_entry.php to temporarily increment time by three hours.

Now I have a new question, how to detect the interval between two appointments needs to be in accordance with certain policies (e.g. the interval must be 0 or 3, 6, 9 hours, etc.) Any suggestions?

campbell-m commented 3 weeks ago

What are you trying to do? I don't think editing get_slot_selector() is the best thing to do. I think all you need to do is set the resolution to 180 minutes. Login to MRBS as an admin, go to the Rooms page, select the area in question and then click the Edit icon (little pencil). Then change the resolution and click Save.

flyxj commented 3 weeks ago

I use MRBS to manage equipment rentals, each time period is 3 hours or 6 hours and so on, the original settings are OK, but the user can change the time to choose other times.

campbell-m commented 3 weeks ago

But the rentals can start at any time, for example 08:00, 09:00 or 10:00?

flyxj commented 3 weeks ago

yes,i edit mrbs_sql.inc add these code:

$last_booking_sql = "SELECT id, start_time, end_time
                     FROM " . _tbl('entry') . "
                     WHERE room_id = ?
                       AND end_time < ?
                     ORDER BY end_time DESC
                     LIMIT 1";

$last_booking_res = db()->query($last_booking_sql, [$room_id, $booking['start_time']]);

if ($last_booking_res->count() > 0)
{
  $last_booking = $last_booking_res->next_row_keyed();
  $last_end_time = $last_booking['end_time'];

  $current_time = time();

  if ($current_time >= $last_end_time)
  {
    // continue
  }
  else
  {
    if (($booking['start_time'] - $last_end_time <= 3600) ||
        ($booking['start_time'] - $last_end_time >= 10800))
    {
      // continue
    }
    else
    {
      return ["The previous appointment has not yet ended, you must make an appointment immediately after its end time (within 1 hour) or directly after 3 hours."];
    }
  }
}
else
{
  // continue
}

Looks like it works.

But I found a bug in my get_slot_selector(), which specifically handles zero-hour calculations.

function get_slot_selector(array $area, string $id, string $name, int $current_s, bool $display_none=false, bool $disabled=false, bool $is_start=false) : ElementSelect
{
  // Check that $resolution is positive to avoid an infinite loop below.
  // (Shouldn't be possible, but just in case ...)

  if (empty($area['resolution']) || ($area['resolution'] < 0))
  {
    throw new \Exception("Internal error - resolution is NULL or <= 0");
  }

  if ($area['enable_periods'])
  {
    $base = 12*SECONDS_PER_HOUR;  // The start of the first period of the day
  }

  // Build the options
  $options = array();

  //$first = $area['first'];
  $first = $current_s;

  // If we're using periods then the last slot is actually the start of the last period,
  // or if we're using times and this is the start selector, then we don't show the last
  // time
  if ($area['enable_periods'] || $is_start)
  {
    $last = $area['last'] - $area['resolution'];
  }
  else
  {
    $last = $area['last'];
  }

  //for ($s = $first; $s <= $last; $s += $area['resolution'])
  for ($s = $first; $s <= $last && $count < 3; $s += 3*3600)
  {
    if ($area['enable_periods'])
    {
      $options[$s] = $area['periods'][intval(($s-$base)/60)];
    }
    else
    {
      $options[$s] = hour_min($s);
    }
    $count ++;
  }

  // Make sure that the selected option is within the range of available options.
  $selected = max($current_s, $first);
  $selected = min($selected, $last);

  $field = new ElementSelect();
  $field->setAttributes(array('id'       => $id,
                              'name'     => $name,
                              'disabled' => $disabled || $display_none))
        ->addSelectOptions($options, $selected, true);

  if ($disabled)
  {
    // If $disabled is set, give the element a class so that the JavaScript
    // knows to keep it disabled
    $field->addClass('keep_disabled');
  }
  if ($display_none)
  {
    $field->addClass('none');
  }

  if ($disabled && !$display_none)
  {
    $hidden = new ElementInputHidden();
    $hidden->setAttributes(array('name'  => $name,
                                 'value' => $selected));
    $field->next($hidden);
  }

  return $field;
}

Any suggestions?

campbell-m commented 3 weeks ago

I think I would take a different approach and introduce a new global variable called $booking_resolution or something like that and then modify the bits of code that use $resolution and work out whether they are really using the display resolution or the booking resolution.

Or else I would just introduce a minimum booking length of 3 hours and not worry about making people book for multiples of 3 hours, ie let them book for 4 or 5 hours if they want to.

flyxj commented 3 weeks ago

well, it's too hard for me.

How do I set a minimum booking length?