You are here

rooms_availability.module in Rooms - Drupal Booking for Hotels, B&Bs and Vacation Rentals 7

Manages availability for Bookable Units and displaying dates on the jquery FullCalendar plugin.

File

modules/rooms_availability/rooms_availability.module
View source
<?php

/**
 * @file
 * Manages availability for Bookable Units and displaying dates on the jquery
 * FullCalendar plugin.
 */
define('ROOMS_AVAILABILITY_ADMIN_STYLE', 1);
define('ROOMS_AVAILABILITY_GENERIC_STYLE', 2);

/**
 * Implements hook_permission().
 */
function rooms_availability_permission() {
  $permissions = array(
    'administer rooms_unit availability' => array(
      'title' => t('Administer unit availability'),
      'description' => t('Allows users to access bulk availability operations for bookable units.'),
      'restrict access' => TRUE,
    ),
    'view anonymous availability information' => array(
      'title' => t('View anonymous availability information'),
      'description' => t('Allow users to view anonymous availability info (especially via availability reference field).'),
    ),
    'view named availability information' => array(
      'title' => t('View named availability information'),
      'description' => t('Allow users to view named availability info (especially via availability reference field).'),
    ),
    'view past availability information' => array(
      'title' => t('View past availability information'),
      'description' => t('Allow users to view availability info in the past (especially via availability reference field).'),
    ),
    'update availability own rooms_unit entities' => array(
      'title' => t('Edit availability own bookable units of any type'),
    ),
    'update availability any rooms_unit entity' => array(
      'title' => t('Edit availability any bookable unit of any type'),
    ),
  );

  // Generate permissions per room type.
  foreach (rooms_unit_get_types() as $type) {
    $type_name = check_plain($type->type);
    $permissions += array(
      'update availability own rooms_unit entities of bundle ' . $type_name => array(
        'title' => t('Edit availability own %type_name bookable units', array(
          '%type_name' => $type->label,
        )),
      ),
      'update availability any rooms_unit entity of bundle ' . $type_name => array(
        'title' => t('Edit availability any %type_name bookable unit', array(
          '%type_name' => $type->label,
        )),
      ),
    );
  }
  return $permissions;
}

/**
 * Implements hook_menu().
 */
function rooms_availability_menu() {
  $items = array();
  $items['admin/rooms/units/unit/%rooms_unit/availability'] = array(
    'title' => 'Manage Availability',
    'page callback' => 'rooms_availability_page',
    'page arguments' => array(
      4,
      6,
      7,
    ),
    'access callback' => 'rooms_unit_access',
    'access arguments' => array(
      'update availability',
      4,
    ),
    'type' => MENU_LOCAL_TASK,
    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
    'weight' => '20',
  );
  $items['rooms/units/unit/%rooms_unit/availability/json/%/%'] = array(
    'title' => 'Availability Event',
    'page callback' => 'rooms_availability_event',
    'page arguments' => array(
      3,
      6,
      7,
    ),
    'access callback' => 'rooms_unit_access',
    'access arguments' => array(
      'view',
      3,
    ),
    'type' => MENU_CALLBACK,
    'weight' => 30,
  );
  $items['admin/rooms/units/unit/%rooms_unit/event'] = array(
    'title' => 'Event Management',
    'page callback' => 'rooms_availability_event_manager_page',
    'page arguments' => array(
      4,
    ),
    'access callback' => 'rooms_unit_access',
    'access arguments' => array(
      'update availability',
      4,
    ),
    'type' => MENU_CALLBACK,
    'weight' => 30,
  );
  $items['admin/rooms/units/bulk_unit_management'] = array(
    'title' => 'Bulk availability management',
    'page callback' => 'rooms_availability_bulk_unit_management',
    'page arguments' => array(
      4,
      5,
      6,
    ),
    'access arguments' => array(
      'administer rooms_unit availability',
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 10,
  );
  return $items;
}

/**
 * Implements hook_query_TAG_alter().
 */
function rooms_availability_query_rooms_availability_access_alter(QueryAlterableInterface $query) {

  // Look for unit base table to pass to the query altering function or else
  // assume we don't have the tables we need to establish order related altering
  // right now.
  foreach ($query
    ->getTables() as $table) {
    if ($table['table'] === 'rooms_units') {
      rooms_entity_access_query_alter($query, 'rooms_unit', $table['alias'], NULL, 'update availability');
      break;
    }
  }
}

/**
 * Implements hook_entity_delete().
 */
function rooms_availability_entity_delete($entity, $type) {
  if ($type == 'rooms_unit') {

    // Remove data related to entity from rooms_availability table.
    db_delete('rooms_availability')
      ->condition('unit_id', $entity->unit_id)
      ->execute();
  }
}

/**
 * Form for the Bulk Availability Management.
 *
 * Could receive date params for the interested interval to edit.
 *
 * @param string $year
 *   Year to perform the operations.
 * @param string $month
 *   Month to perform the operations.
 * @param string $type
 *   Bookable unit type to perform the operation.
 *
 * @return array
 *   Bulk availability management page render array.
 */
function rooms_availability_bulk_unit_management($year = '', $month = '', $type = 'all') {

  // Load FullCalendar.
  rooms_fullcalendar_loaded();

  // Modal includes and style.
  rooms_availability_modal_style();

  // If year is not set then give it the current date.
  $year = $year != '' && is_numeric($year) ? $year : date('Y', time());
  $month = $month != '' && is_numeric($month) ? $month : date('n', time());
  $type = $type == '' ? 'all' : $type;

  // It's not a valid unit type.
  if (rooms_unit_get_types($type) == FALSE) {
    $type = 'all';
  }

  // It's not a valid month.
  if ($month < 1 || $month > 12) {
    $month = 1;
  }
  $efq = new EntityFieldQuery();
  $efq
    ->entityCondition('entity_type', 'rooms_unit');
  $efq
    ->addTag('rooms_availability_access');
  if ($type != 'all') {
    $efq
      ->entityCondition('bundle', $type, '=');
  }
  $efq
    ->pager(20);
  $rooms_units = $efq
    ->execute();
  $rooms_id = $units = array();
  if ($rooms_units) {
    $units = array_values(entity_load('rooms_unit', array_keys($rooms_units['rooms_unit'])));
    $rooms_id = array();
    foreach ($units as $value) {
      $rooms_id[] = $value->unit_id;
    }
  }
  $js_file = drupal_get_path('module', 'rooms_availability') . '/js/rooms_unit_management.js';
  $css_file = drupal_get_path('module', 'rooms_availability') . '/css/rooms_availability.css';

  // Show full day events on calendar.
  if (variable_get('rooms_calendar_events_view', '0') == '1') {
    $js_file = drupal_get_path('module', 'rooms_availability') . '/js/rooms_unit_management_full_day.js';
  }

  // Return the full render array.
  return array(
    drupal_get_form('rooms_filter_month_form', $month, $year),
    drupal_get_form('rooms_availability_update_status_form', $month, $year, $type, $units),
    array(
      '#theme' => 'pager',
    ),
    '#attached' => array(
      'css' => array(
        $css_file,
      ),
      'js' => array(
        $js_file,
        drupal_get_path('module', 'rooms') . '/js/rooms_fullcalendar_singlerowmonth.js',
        array(
          'data' => array(
            'roomsUnitManagement' => array(
              'roomsNumber' => count($rooms_id),
              'currentMonth' => $month,
              'currentYear' => $year,
              'roomsId' => $rooms_id,
            ),
          ),
          'type' => 'setting',
        ),
      ),
    ),
  );
}

/**
 * Form to manage the availability for specific month.
 *
 * @see rooms_availability_bulk_unit_management()
 */
function rooms_availability_update_status_form($form, &$form_state, $month, $year, $type, $rooms_units) {
  $form['#attributes']['class'][] = 'rooms-management-form rooms-bulk-availability-form';
  $form['rooms_availability_update'] = array(
    '#type' => 'fieldset',
    '#title' => t('Update Availability'),
    '#description' => t('Change the availability status of the units selected below for the specified date range.'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['rooms_update_availability']['curr_month'] = array(
    '#type' => 'hidden',
    '#value' => $month,
  );
  $form['rooms_update_availability']['curr_year'] = array(
    '#type' => 'hidden',
    '#value' => $year,
  );
  $form['rooms_update_availability']['curr_type'] = array(
    '#type' => 'hidden',
    '#value' => $type,
  );
  $form['rooms_availability_update']['rooms_date_range'] = rooms_date_range_fields($year, $month);
  $state_options = rooms_unit_state_options();
  $form['rooms_availability_update']['change_event_status'] = array(
    '#title' => t('Bookable Unit State'),
    '#type' => 'select',
    '#options' => $state_options,
    '#empty_option' => t('- Select -'),
  );
  $form['rooms_availability_update']['actions'] = array(
    '#type' => 'container',
    '#attributes' => array(
      'class' => array(
        'form-actions',
      ),
    ),
    '#weight' => 400,
  );
  $form['rooms_availability_update']['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Update Unit Availability'),
  );
  $form['#validate'][] = 'rooms_form_start_end_dates_validate';
  $form['#validate'][] = 'rooms_availability_update_status_form_validate';
  $form['rooms_data'] = array(
    '#prefix' => '<table class="rooms-month-manager">',
    '#type' => 'container',
    '#suffix' => '</tbody></table>',
  );
  if (count($rooms_units) > 0) {
    $date = new DateTime();
    $date
      ->setDate($year, $month, '01');
    $form['rooms_data']['select-all'] = array(
      '#type' => 'select',
      '#prefix' => '<thead><tr><th class="unit-bulk-select">',
      '#options' => array(
        ROOMS_THIS_PAGE => t('All (this page)'),
        ROOMS_ALL_PAGES => t('All (all pages)'),
        ROOMS_NONE => t('None'),
      ),
      '#empty_option' => t('- Select -'),
      '#suffix' => '</th><th class="month-name"><div class="fc-header-title"><h2>' . format_date($date
        ->getTimestamp(), 'custom', 'F Y') . '</h2></div></th></tr></thead><tbody>',
    );
  }
  foreach ($rooms_units as $key => $value) {
    $form['rooms_data']['rooms-' . $value->unit_id] = array(
      '#type' => 'checkbox',
      '#title' => $value->name,
      '#prefix' => '<tr><th class="unit-name">',
      '#suffix' => '</th><td  class="unit-days"><div id="calendar' . $key . '"></div></td></tr>',
    );
  }
  return $form;
}

/**
 * Validate callback for rooms_availability_update_status_form form.
 */
function rooms_availability_update_status_form_validate(&$form, &$form_state) {
  if ($form_state['values']['change_event_status'] == '') {
    form_set_error('change_event_status', t('Select a valid status.'));
  }

  // Validate that a rooms is selected.
  _rooms_select_rooms_validation($form_state);
}

/**
 * Submit callback for rooms_availability_update_status_form form.
 */
function rooms_availability_update_status_form_submit(&$form, &$form_state) {
  list($start_date, $end_date) = rooms_form_input_get_start_end_dates($form_state);
  $type = $form_state['values']['curr_type'];
  $event_id = $form_state['values']['change_event_status'];

  // Consider right START DATE and END DATE for all events.
  $end_date
    ->sub(new DateInterval('P1D'));
  if ($form_state['values']['select-all'] == ROOMS_ALL_PAGES) {
    $query = db_select('rooms_units', 'n')
      ->fields('n', array(
      'unit_id',
      'name',
    ));
    if ($type != 'all') {
      $query
        ->condition('type', $type, '=');
    }
    $rooms_units = $query
      ->execute()
      ->fetchAll();
    foreach ($rooms_units as $room) {
      $unit_id = $room->unit_id;

      // Create a new Booking Event.
      $be = new BookingEvent($unit_id, $event_id, $start_date, $end_date);
      $events = array(
        $be,
      );
      $rc = new UnitCalendar($unit_id);
      $response = $rc
        ->updateCalendar($events);
      if ($response[$event_id] == ROOMS_BLOCKED) {
        drupal_set_message($room->name . ' - ' . t('Could not update calendar because a locked event is blocking the update - you need to unlock any locked events in that period.'), 'warning');
      }
      elseif ($response[$event_id] == ROOMS_UPDATED) {
        drupal_set_message($room->name . ' - ' . t('Calendar Updated'));
      }
    }
  }
  else {
    foreach ($form_state['values'] as $key => $value) {
      if (strpos($key, 'rooms-') === 0 && $value == '1') {
        $unit_id = str_replace('rooms-', '', $key);

        // Create a new Booking Event.
        $be = new BookingEvent($unit_id, $event_id, $start_date, $end_date);
        $events = array(
          $be,
        );
        $rc = new UnitCalendar($unit_id);
        $response = $rc
          ->updateCalendar($events);
        if ($response[$event_id] == ROOMS_BLOCKED) {
          drupal_set_message($form_state['complete form']['rooms_data'][$key]['#title'] . ' - ' . t('Could not update calendar because a locked event is blocking the update - you need to unlock any locked events in that period.'), 'warning');
        }
        elseif ($response[$event_id] == ROOMS_UPDATED) {
          drupal_set_message($form_state['complete form']['rooms_data'][$key]['#title'] . ' - ' . t('Calendar Updated'));
        }
      }
    }
  }
}

/**
 * Callback for admin/rooms/units/unit/%unit/availability - builds availability
 * page by adding calendar and pulling events from availability table.
 */
function rooms_availability_page(RoomsUnit $rooms_unit, $year = '', $month = '') {

  // Set the page title.
  drupal_set_title(t('Edit @unit_name Availability', array(
    '@unit_name' => $rooms_unit->name,
  )));

  // Add styles.
  rooms_availability_modal_style();

  // Get the current page's URL, stripped of the year and month args.
  // This allows us to place this page anywhere, including at
  // unit/%/availability or admin/rooms/units/unit/%/availability
  list($url) = explode('/' . $year . '/' . $month, current_path());
  $js_file = drupal_get_path('module', 'rooms_availability') . '/js/rooms_availability.js';
  $css_file = drupal_get_path('module', 'rooms_availability') . '/css/rooms_availability.css';

  // Show full day events on calendar.
  if (variable_get('rooms_calendar_events_view', '0') == '1') {
    $js_file = drupal_get_path('module', 'rooms_availability') . '/js/rooms_availability_full_day.js';
  }
  return array(
    '#theme' => 'rooms_three_month_calendar',
    '#url' => $url,
    '#form' => drupal_get_form('update_availability_calendar_form', $rooms_unit->unit_id, $year, $month),
    '#year' => $year,
    '#month' => $month,
    '#attached' => array(
      'css' => array(
        $css_file,
      ),
      'js' => array(
        $js_file,
        array(
          'data' => array(
            'roomsAvailability' => array(
              'roomID' => $rooms_unit->unit_id,
            ),
          ),
          'type' => 'setting',
        ),
      ),
    ),
  );
}

/**
 * A basic form that allows us to update the state of the calendar.
 */
function update_availability_calendar_form($form, &$form_state, $unit_id, $year, $month) {
  $form['#attributes']['class'][] = 'rooms-management-form rooms-availability-calendar-form';
  $form['rooms_update_availability'] = array(
    '#type' => 'fieldset',
    '#title' => t('Update Unit Availability'),
    '#description' => t('Change the availability status for a specified date range.'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['rooms_update_availability']['unit_id'] = array(
    '#type' => 'hidden',
    '#value' => $unit_id,
  );
  $form['rooms_update_availability']['rooms_date_range'] = rooms_date_range_fields();

  // Unset a js setting.
  drupal_add_js(array(
    'rooms' => array(
      'roomsBookingStartDay' => 0,
    ),
  ), 'setting');
  $state_options = rooms_unit_state_options();
  $form['rooms_update_availability']['unit_state'] = array(
    '#type' => 'select',
    '#title' => t('Change status to'),
    '#options' => $state_options,
  );
  $form['rooms_update_availability']['actions'] = array(
    '#type' => 'container',
    '#attributes' => array(
      'class' => array(
        'form-actions',
      ),
    ),
    '#weight' => 400,
  );

  // We add the form's #submit array to this button along with the actual submit
  // handler to preserve any submit handlers added by a form callback_wrapper.
  $submit = array();
  if (!empty($form['rooms_update_availability']['#submit'])) {
    $submit += $form['rooms_update_availability']['#submit'];
  }
  $form['rooms_update_availability']['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Update Availability'),
    '#submit' => $submit + array(
      'update_availability_calendar_form_submit',
    ),
  );

  // We append the validate handler to #validate in case a form callback_wrapper
  // is used to add validate handlers earlier.
  $form['#validate'][] = 'rooms_form_start_end_dates_validate';
  return $form;
}

/**
 * @todo Need to figure out what to do when we cancel an existing booking.
 */
function update_availability_calendar_form_submit(&$form, &$form_state) {
  list($start_date, $end_date) = rooms_form_input_get_start_end_dates($form_state);
  $event_id = $form_state['values']['unit_state'];
  $unit_id = $form_state['values']['unit_id'];

  // Consider right START DATE and END DATE for all events.
  $end_date
    ->sub(new DateInterval('P1D'));

  // Create a new Booking Event.
  $be = new BookingEvent($unit_id, $event_id, $start_date, $end_date);
  $events = array(
    $be,
  );
  $rc = new UnitCalendar($unit_id);
  $response = $rc
    ->updateCalendar($events);
  if ($response[$event_id] == ROOMS_BLOCKED) {
    drupal_set_message(t('Could not update calendar because a locked event is blocking the update - you need to unlock any locked events in that period.'), 'warning');
  }
  elseif ($response[$event_id] == ROOMS_UPDATED) {
    drupal_set_message(t('Calendar Updated'));
  }
}

/**
 * Displays the necessary json for the date range provided - needs at least start
 * year and month at which point it will return the entire month.
 */
function rooms_availability_event($unit, $start_year = '', $start_month = '', $start_day = '', $end_year = '', $end_month = '', $end_day = '', $event_style = ROOMS_AVAILABILITY_ADMIN_STYLE) {

  // If user don't have 'view anonymous availability information' permission.
  if (!(user_access('view anonymous availability information') || rooms_unit_access('update availability', $unit))) {
    echo drupal_json_encode(array());
    return;
  }
  $json_events = array();
  $json_events = rooms_availability_generate_json($unit, $start_year, $start_month, $start_day, $end_year, $end_month, $end_day, $event_style = ROOMS_AVAILABILITY_ADMIN_STYLE);
  echo drupal_json_encode($json_events);
}

/**
 * Generates json based on date range provided.
 */
function rooms_availability_generate_json($unit, $start_year = '', $start_month = '', $start_day = '', $end_year = '', $end_month = '', $end_day = '', $event_style = ROOMS_AVAILABILITY_ADMIN_STYLE) {
  $start_year = (int) $start_year;
  $start_month = (int) $start_month;
  $start_day = (int) $start_day;
  $end_year = (int) $end_year;
  $end_month = (int) $end_month;
  $end_day = (int) $end_day;
  $today = new DateTime();
  $month_start = new DateTime("{$start_year}-{$start_month}-1");
  $previous_month = $today >= $month_start;
  if (!user_access('view past availability information') && $previous_month) {
    $start_day = date('j');
    $start_month = date('n');
    $start_year = date('Y');
  }
  $eom = rooms_end_of_month_dates($start_year);
  if ($start_year == 0 || $start_month == 0) {
    echo drupal_json_encode('missing basic info');
    return;
  }
  elseif ($start_day == 0) {
    $start_date = new DateTime("{$start_year}-{$start_month}-1");
    $end_day = $eom[$start_month];
    $end_date = new DateTime("{$start_year}-{$start_month}-{$end_day}");
  }
  elseif ($start_day != 0 && $end_year == 0) {
    $start_date = new DateTime("{$start_year}-{$start_month}-{$start_day}");
    $end_day = $eom[$start_month];
    $end_date = new DateTime("{$start_year}-{$start_month}-{$end_day}");
  }
  else {
    $start_date = new DateTime("{$start_year}-{$start_month}-{$start_day}");
    $end_date = new DateTime("{$end_year}-{$end_month}-{$end_day}");
  }
  $json_events = array();
  $rc = new UnitCalendar($unit->unit_id, $unit->default_state);
  $events = $rc
    ->getEvents($start_date, $end_date);
  $event_style = rooms_availability_get_style($event_style, $unit);
  foreach ($events as $event) {
    if (variable_get('rooms_calendar_events_view', '0') == '0') {
      $event->end_date
        ->add(new DateInterval('P1D'));
    }
    $json_events[] = $event
      ->formatJson($event_style, $unit->name);
  }
  return $json_events;
}

/**
 * Helper function to determine the $event style depending on permissions.
 */
function rooms_availability_get_style($event_style, $unit) {
  $event_style = is_numeric($event_style) ? (int) $event_style : (int) ROOMS_AVAILABILITY_ADMIN_STYLE;

  // If user don't have 'view named availability information' permission.
  if (!(user_access('view named availability information') || rooms_unit_access('update availability', $unit)) && $event_style == ROOMS_AVAILABILITY_ADMIN_STYLE) {
    $event_style = (int) ROOMS_AVAILABILITY_GENERIC_STYLE;
  }
  return $event_style;
}

/**
 * The EventManager page shows when clicking on an event in the availability
 * calendar - will allow a user to manipulate that event.
 */
function rooms_availability_event_manager_page($unit, $event_id = NULL, $start_date = 0, $end_date = 0) {

  // Include modal library.
  ctools_include('modal');

  // If any info missing we cannot load the event.
  if ($event_id == NULL || $start_date == 0 || $end_date == 0) {
    $output[] = ctools_modal_command_dismiss();
    drupal_set_message(t('Unable to load event.'), 'error');
  }

  // Basic check to avoid damage from dirty input.
  $event_id = check_plain($event_id);
  $start_date = check_plain($start_date);
  $end_date = check_plain($end_date);

  // Process start and end date.
  $sd = new DateTime($start_date);
  $ed = new DateTime($end_date);
  $booked = FALSE;
  if ($event_id > 10 || $event_id < -10) {
    $booked = TRUE;
  }
  if ($booked) {
    $booking_id = rooms_availability_return_id($event_id);
    $booking = rooms_booking_load($booking_id);

    // For existing bookings allow to edit in the modal.
    module_load_include('inc', 'rooms_booking', 'rooms_booking.admin');
    $form_state = array(
      'title' => t('Edit booking'),
      'ajax' => TRUE,
      'build_info' => array(
        'args' => array(
          $booking,
        ),
        'files' => array(
          'rooms_booking_admin' => array(
            'module' => 'rooms_booking',
            'name' => 'rooms_booking.admin',
            'type' => 'inc',
          ),
        ),
      ),
    );

    // Wrap the form via ctools modal.
    $output = ctools_modal_form_wrapper('rooms_booking_edit_form', $form_state);
    if ($form_state['executed']) {
      if (!empty($form_state['booking_deleted'])) {

        // If there are messages for the form, render them.
        $messages = theme('status_messages');
        $output = array();

        // If the form has not yet been rendered, render it.
        $output[] = ctools_modal_command_display(t('Booking deleted'), $messages);
      }
      else {
        $output = array(
          ctools_modal_command_dismiss(),
        );
      }
    }
    print ajax_render($output);
    exit;
  }

  // If the event is blocked, show an error message.
  $uc = new UnitCalendar($unit->unit_id);
  $mock_event = new BookingEvent($unit->unit_id, NULL, $sd, $ed);
  if ($uc
    ->eventBlocked($mock_event)) {
    drupal_set_message(t('You can not update calendar because a locked event is blocking the update. You need to unlock any locked events in that period.'), 'warning');
    $output = theme('status_messages');
    ctools_modal_render(t('Event Management'), $output);
    return;
  }
  ctools_modal_render(t('Event Management'), drupal_get_form('rooms_availability_event_manager_form', $unit, $event_id, $sd, $ed));
}

/**
 * Define modal JS style and dependencies.
 */
function rooms_availability_modal_style() {

  // Include libraries.
  ctools_include('modal');
  ctools_include('ajax');
  ctools_modal_add_js();

  // Styles to use for the modal.
  $modal_style = array(
    'rooms-modal-style' => array(
      'modalSize' => array(
        'type' => 'fixed',
        'width' => 400,
        'height' => 400,
        'addWidth' => 0,
        'addHeight' => 0,
      ),
      'modalOptions' => array(
        'opacity' => 0.0,
        'background-color' => '#000',
      ),
      'animation' => 'fadeIn',
    ),
  );

  // Add the ctool modal configuration to settings.
  drupal_add_js($modal_style, 'setting');

  // Add the ctools modal stylesheet.
  drupal_add_css(drupal_get_path('module', 'rooms') . '/css/rooms_modal.css');
}

/**
 * The Event Manager Form.
 */
function rooms_availability_event_manager_form($form, $form_state, $unit, $event_id, $start_date, $end_date) {
  $form = array();
  $new_event_id = $event_id;
  if (isset($form_state['values']['change_event_status'])) {
    $new_event_id = $form_state['values']['change_event_status'];
  }
  $state_options = rooms_unit_state_options();
  $form['#attributes']['class'][] = 'rooms-management-form rooms-event-form';

  // This entire form element will be replaced whenever 'changethis' is updated.
  $form['#prefix'] = '<div id="replace_textfield_div">';
  $form['#suffix'] = '</div>';
  $form['unit_id'] = array(
    '#type' => 'hidden',
    '#value' => $unit->unit_id,
  );
  $form['event_id'] = array(
    '#type' => 'hidden',
    '#value' => $event_id,
  );
  $form['rooms_start_date'] = array(
    '#type' => 'hidden',
    '#value' => $start_date,
  );
  $form['rooms_end_date'] = array(
    '#type' => 'hidden',
    '#value' => $end_date,
  );
  if ($event_id == -2) {
    $form['event_title'] = array(
      '#prefix' => '<h2>',
      '#markup' => check_plain($unit->name),
      '#suffix' => '</h2>',
    );
  }
  else {
    $form['event_title'] = array(
      '#prefix' => '<h2>',
      '#markup' => t('@unit_name is @status', array(
        '@unit_name' => $unit->name,
        '@status' => $state_options[$new_event_id],
      )),
      '#suffix' => '</h2>',
    );
  }
  $date_format = variable_get('rooms_date_format', 'd-m-Y');
  $form['event_details'] = array(
    '#prefix' => '<div class="event-details">',
    '#markup' => t('Duration: @startdate to @enddate', array(
      '@startdate' => $start_date
        ->format($date_format),
      '@enddate' => $end_date
        ->format($date_format),
    )),
    '#suffix' => '</div>',
  );
  unset($state_options[$new_event_id]);
  $form['change_event_status'] = array(
    '#title' => t('Change the state for this event to:') . ' ',
    '#type' => 'select',
    '#options' => $state_options,
    '#ajax' => array(
      'callback' => 'rooms_availability_ajax_event_status_change',
      'wrapper' => 'replace_textfield_div',
    ),
    '#empty_option' => t('- Select -'),
  );
  if (module_exists('rooms_booking') && $new_event_id != 89) {
    $booking_types = rooms_booking_get_types();
    foreach ($booking_types as $type) {
      $book_end_date = clone $end_date;

      // If we select one day from the calendar, postpone the departure date.
      if ($start_date == $end_date) {
        $book_end_date = $book_end_date
          ->add(new DateInterval('P1D'));
      }
      $form['order']['order_link'][$type->type] = array(
        '#type' => 'markup',
        '#markup' => '<div>' . l(t('Create @booking_type', array(
          '@booking_type' => $type->label,
        )), 'admin/rooms/bookings/add/' . $type->type, array(
          'query' => array(
            'startdate' => $start_date
              ->getTimestamp(),
            'enddate' => $book_end_date
              ->getTimestamp(),
            'unitid' => $unit->unit_id,
          ),
        )) . '</div>',
      );
    }
  }
  return $form;
}

/**
 * The callback for the change_event_status widget of the event manager form.
 */
function rooms_availability_ajax_event_status_change($form, $form_state) {
  $start_date = $form_state['values']['rooms_start_date'];
  $end_date = $form_state['values']['rooms_end_date'];
  $unit_id = $form_state['values']['unit_id'];
  $event_id = $form_state['values']['event_id'];
  $new_event_id = $form_state['values']['change_event_status'];

  // If we have a new event id go ahead and update event.
  if ($event_id != $new_event_id && $new_event_id != -1) {
    $event = new BookingEvent($unit_id, $new_event_id, $start_date, $end_date);
    $uc = new UnitCalendar($unit_id);
    $responses = $uc
      ->updateCalendar(array(
      $event,
    ));
    $state_options = rooms_unit_state_options();
    if ($event_id >= -1) {
      $form['form_wrapper_bottom']['#markup'] = t('Updated event from <strong>@old_status</strong> to <strong>@new_status</strong>.', array(
        '@old_status' => $state_options[$event_id],
        '@new_status' => $state_options[$new_event_id],
      ));
    }
    else {
      $form['form_wrapper_bottom']['#markup'] = t('New Event state is <strong>@state</strong>.', array(
        '@state' => $state_options[$new_event_id],
      ));
    }
  }
  return $form;
}

/**
 * Sets event ids.
 *
 * @todo - Make this depend on a parameter
 */
function rooms_availability_assign_id($id, $status = '1') {

  // Add eleven for now - this allows for 10 states that do not
  // refer to a specific booking.
  $id = $id + 11;
  if ($status == '0') {
    return -$id;
  }
  else {
    return $id;
  }
}

/**
 * Given an event state it returns the valid booking id.
 */
function rooms_availability_return_id($id) {

  // Make sure we are not looking for negative ids;
  $id = abs($id);
  $id = $id - 11;
  return $id;
}

/**
 * Implements hook_form__FORM_ID_alter().
 *
 * FORM_ID = rooms_booking_settings
 */
function rooms_availability_form_rooms_booking_settings_alter(&$form, &$form_state, $form_id) {
  $form['label_settings'] = array(
    '#type' => 'fieldset',
    '#group' => 'rooms_settings',
    '#title' => t('Calendar Color Codes & Labels'),
  );
  $form['label_settings']['rooms_not_available_color'] = array(
    '#type' => 'textfield',
    '#title' => t('"@availability_status" color', array(
      '@availability_status' => t('Unavailable'),
    )),
    '#size' => 10,
    '#maxlength' => 7,
    '#default_value' => variable_get('rooms_not_available_color', '#CC2727'),
    '#element_validate' => array(
      'rooms_availability_validate_hex_color',
    ),
    '#dependency' => array(
      'edit-row-options-colors-legend' => array(
        'type',
      ),
    ),
    '#prefix' => '<div class="rooms-colorpicker-wrapper form-wrapper">',
    '#suffix' => '<div class="rooms-colorpicker"></div></div>',
    '#attributes' => array(
      'class' => array(
        'rooms-edit-colorpicker',
      ),
    ),
    '#attached' => array(
      // Add Farbtastic color picker.
      'library' => array(
        array(
          'system',
          'farbtastic',
        ),
      ),
      // Add javascript to trigger the colorpicker.
      'js' => array(
        drupal_get_path('module', 'rooms_availability') . '/js/rooms_color.js',
      ),
    ),
  );
  $form['label_settings']['rooms_not_available_text'] = array(
    '#type' => 'textfield',
    '#title' => t('"@availability_status" label', array(
      '@availability_status' => t('Unavailable'),
    )),
    '#size' => 10,
    '#maxlength' => 50,
    '#default_value' => variable_get('rooms_not_available_text', 'N/A'),
  );
  $form['label_settings']['rooms_available_color'] = array(
    '#type' => 'textfield',
    '#title' => t('"@availability_status" color', array(
      '@availability_status' => t('Available'),
    )),
    '#size' => 10,
    '#maxlength' => 7,
    '#default_value' => variable_get('rooms_available_color', '#8BA175'),
    '#element_validate' => array(
      'rooms_availability_validate_hex_color',
    ),
    '#dependency' => array(
      'edit-row-options-colors-legend' => array(
        'type',
      ),
    ),
    '#prefix' => '<div class="rooms-colorpicker-wrapper">',
    '#suffix' => '<div class="rooms-colorpicker"></div></div>',
    '#attributes' => array(
      'class' => array(
        'rooms-edit-colorpicker',
      ),
    ),
    '#attached' => array(
      // Add Farbtastic color picker.
      'library' => array(
        array(
          'system',
          'farbtastic',
        ),
      ),
      // Add javascript to trigger the colorpicker.
      'js' => array(
        drupal_get_path('module', 'rooms_availability') . '/js/rooms_color.js',
      ),
    ),
  );
  $form['label_settings']['rooms_available_text'] = array(
    '#type' => 'textfield',
    '#title' => t('"@availability_status" label', array(
      '@availability_status' => t('Available'),
    )),
    '#size' => 10,
    '#maxlength' => 50,
    '#default_value' => variable_get('rooms_available_text', 'AV'),
  );
  $form['label_settings']['rooms_on_request_color'] = array(
    '#type' => 'textfield',
    '#title' => t('"@availability_status" color', array(
      '@availability_status' => t('Available on Request'),
    )),
    '#size' => 10,
    '#maxlength' => 7,
    '#default_value' => variable_get('rooms_on_request_color', '#C5C5C5'),
    '#element_validate' => array(
      'rooms_availability_validate_hex_color',
    ),
    '#dependency' => array(
      'edit-row-options-colors-legend' => array(
        'type',
      ),
    ),
    '#prefix' => '<div class="rooms-colorpicker-wrapper">',
    '#suffix' => '<div class="rooms-colorpicker"></div></div>',
    '#attributes' => array(
      'class' => array(
        'rooms-edit-colorpicker',
      ),
    ),
    '#attached' => array(
      // Add Farbtastic color picker.
      'library' => array(
        array(
          'system',
          'farbtastic',
        ),
      ),
      // Add javascript to trigger the colorpicker.
      'js' => array(
        drupal_get_path('module', 'rooms_availability') . '/js/rooms_color.js',
      ),
    ),
  );
  $form['label_settings']['rooms_on_request_text'] = array(
    '#type' => 'textfield',
    '#title' => t('"@availability_status" label', array(
      '@availability_status' => t('Available on Request'),
    )),
    '#size' => 10,
    '#maxlength' => 50,
    '#default_value' => variable_get('rooms_on_request_text', 'ON-REQ'),
  );
  $form['label_settings']['rooms_anon_booking_color'] = array(
    '#type' => 'textfield',
    '#title' => t('"@availability_status" color', array(
      '@availability_status' => t('Anonymous booking'),
    )),
    '#size' => 10,
    '#maxlength' => 7,
    '#default_value' => variable_get('rooms_anon_booking_color', '#8C6A5A'),
    '#element_validate' => array(
      'rooms_availability_validate_hex_color',
    ),
    '#dependency' => array(
      'edit-row-options-colors-legend' => array(
        'type',
      ),
    ),
    '#prefix' => '<div class="rooms-colorpicker-wrapper">',
    '#suffix' => '<div class="rooms-colorpicker"></div></div>',
    '#attributes' => array(
      'class' => array(
        'rooms-edit-colorpicker',
      ),
    ),
    '#attached' => array(
      // Add Farbtastic color picker.
      'library' => array(
        array(
          'system',
          'farbtastic',
        ),
      ),
      // Add javascript to trigger the colorpicker.
      'js' => array(
        drupal_get_path('module', 'rooms_availability') . '/js/rooms_color.js',
      ),
    ),
  );
  $form['label_settings']['rooms_anon_booking_text'] = array(
    '#type' => 'textfield',
    '#title' => t('"@availability_status" label', array(
      '@availability_status' => t('Anonymous booking'),
    )),
    '#size' => 10,
    '#maxlength' => 50,
    '#default_value' => variable_get('rooms_anon_booking_text', 'A-B'),
  );
  $form['label_settings']['rooms_unconfirmed_booking_color'] = array(
    '#type' => 'textfield',
    '#title' => t('"@availability_status" color', array(
      '@availability_status' => t('Unconfirmed booking'),
    )),
    '#size' => 10,
    '#maxlength' => 7,
    '#default_value' => variable_get('rooms_unconfirmed_booking_color', '#6D8C9C'),
    '#element_validate' => array(
      'rooms_availability_validate_hex_color',
    ),
    '#dependency' => array(
      'edit-row-options-colors-legend' => array(
        'type',
      ),
    ),
    '#prefix' => '<div class="rooms-colorpicker-wrapper">',
    '#suffix' => '<div class="rooms-colorpicker"></div></div>',
    '#attributes' => array(
      'class' => array(
        'rooms-edit-colorpicker',
      ),
    ),
    '#attached' => array(
      // Add Farbtastic color picker.
      'library' => array(
        array(
          'system',
          'farbtastic',
        ),
      ),
      // Add javascript to trigger the colorpicker.
      'js' => array(
        drupal_get_path('module', 'rooms_availability') . '/js/rooms_color.js',
      ),
    ),
  );
  $form['label_settings']['rooms_unconfirmed_booking_text'] = array(
    '#type' => 'textfield',
    '#title' => t('"@availability_status" label', array(
      '@availability_status' => t('Unconfirmed booking'),
    )),
    '#size' => 10,
    '#maxlength' => 50,
    '#default_value' => variable_get('rooms_unconfirmed_booking_text', 'UNCONF'),
  );
  $form['label_settings']['rooms_view_unit_name'] = array(
    '#type' => 'checkboxes',
    '#options' => array(
      '1' => t('Display unit name in place of availability state label.'),
    ),
    '#default_value' => variable_get('rooms_view_unit_name', array(
      '',
    )),
  );
  $form['label_settings']['rooms_calendar_events_view'] = array(
    '#type' => 'radios',
    '#title' => t('Calendar Events Display Mode'),
    '#description' => t('Select how to display events on calendars.'),
    '#default_value' => variable_get('rooms_calendar_events_view', '0'),
    '#options' => array(
      '0' => t('Display events as starting at middle of day (check-in day) and ending at middle of check-out day'),
      '1' => t('Display events occupying full day box at start and ending on day of last night (day before check-out date)'),
    ),
  );
}

/**
 * Utility function to validate hex color numbers.
 */
function rooms_availability_validate_hex_color($element, &$form_state) {
  if (!preg_match('/^#[a-f0-9]{6}$/i', $element['#value'])) {
    form_error($element, t('This is not a valid hexadecimal color!'));
  }
}

Functions

Namesort descending Description
rooms_availability_ajax_event_status_change The callback for the change_event_status widget of the event manager form.
rooms_availability_assign_id Sets event ids.
rooms_availability_bulk_unit_management Form for the Bulk Availability Management.
rooms_availability_entity_delete Implements hook_entity_delete().
rooms_availability_event Displays the necessary json for the date range provided - needs at least start year and month at which point it will return the entire month.
rooms_availability_event_manager_form The Event Manager Form.
rooms_availability_event_manager_page The EventManager page shows when clicking on an event in the availability calendar - will allow a user to manipulate that event.
rooms_availability_form_rooms_booking_settings_alter Implements hook_form__FORM_ID_alter().
rooms_availability_generate_json Generates json based on date range provided.
rooms_availability_get_style Helper function to determine the $event style depending on permissions.
rooms_availability_menu Implements hook_menu().
rooms_availability_modal_style Define modal JS style and dependencies.
rooms_availability_page Callback for admin/rooms/units/unit/%unit/availability - builds availability page by adding calendar and pulling events from availability table.
rooms_availability_permission Implements hook_permission().
rooms_availability_query_rooms_availability_access_alter Implements hook_query_TAG_alter().
rooms_availability_return_id Given an event state it returns the valid booking id.
rooms_availability_update_status_form Form to manage the availability for specific month.
rooms_availability_update_status_form_submit Submit callback for rooms_availability_update_status_form form.
rooms_availability_update_status_form_validate Validate callback for rooms_availability_update_status_form form.
rooms_availability_validate_hex_color Utility function to validate hex color numbers.
update_availability_calendar_form A basic form that allows us to update the state of the calendar.
update_availability_calendar_form_submit @todo Need to figure out what to do when we cancel an existing booking.

Constants

Namesort descending Description
ROOMS_AVAILABILITY_ADMIN_STYLE @file Manages availability for Bookable Units and displaying dates on the jquery FullCalendar plugin.
ROOMS_AVAILABILITY_GENERIC_STYLE