You are here

merci_hours.module in MERCI (Manage Equipment Reservations, Checkout and Inventory) 7.3

File

merci_hours/merci_hours.module
View source
<?php

define('MERCI_HOURS_FIELD', 'field_office_hours');
module_load_include('inc', 'merci_hours', 'open_hours.element');

/**
 * Implements hook_permission().
 */
function merci_hours_permission() {
  $perms = array();
  $perms['administer all merci hours'] = array(
    'title' => t('Administer all merci hours'),
    'description' => t('Perform all administration tasks for merci hours.'),
  );
  $perms['edit own merci hours'] = array(
    'title' => t('Edit own merci hours'),
    'description' => t('Perform tasks for own merci hours.'),
  );
  $perms['delete own merci hours'] = array(
    'title' => t('Delete own mecri hours'),
    'description' => t('Perform tasks for own merci hours.'),
  );
  $perms['create own merci hours'] = array(
    'title' => t('Create own merci hours'),
    'description' => t('Perform tasks for own merci hours.'),
  );
  return $perms;
}

/**
 * Implements hook_menu().
 */
function merci_hours_menu() {
  $items = array();
  $items['admin/merci/config/merci-hours/settings'] = array(
    'title' => 'Sitewide merci hours',
    'description' => "Site's default merci hours.",
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'merci_hours_sitewide_settings',
    ),
    'access arguments' => array(
      'administer all merci hours',
    ),
    'access callback' => 'user_access',
    'file' => 'merci_hours.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 5,
  );

  /**
   * Ajax callback to get days open.
   */
  $items['merci_hours_dates/%/%/%'] = array(
    'page callback' => 'merci_hours_date_open_days_ajax',
    'page arguments' => array(
      1,
      2,
      3,
    ),
    'access callback' => TRUE,
  );

  /**
   * Ajax callback to get hours open.
   */
  $items['merci_hours_open/%/%'] = array(
    'page callback' => 'merci_hours_open_hours_ajax',
    'page arguments' => array(
      1,
      2,
      3,
    ),
    'access callback' => TRUE,
  );
  return $items;
}

/**
 * Page callback. Returns json array for ajax calls.
 */
function merci_hours_open_hours_ajax($wc, $day) {
  $hours = merci_hours_get_open_hours($wc, $day);
  drupal_json_output($hours);
}

/**
 * Page callback. Returns json array for ajax calls.
 */
function merci_hours_date_open_days_ajax($wc, $year, $month) {
  $dates = merci_hours_get_open_days_in_month($wc, $year, $month);
  drupal_json_output($dates);
}

/**
 * Implements hook_entity_info().
 */
function merci_hours_entity_info() {
  $info = array();
  $info['merci_hours'] = array(
    'module' => 'merci_hours',
    'base table' => 'merci_hours',
    'entity keys' => array(
      'id' => 'id',
      'name' => 'name',
      'label' => 'label',
    ),
    'fieldable' => TRUE,
    'bundles' => array(
      'merci_hours' => array(
        'label' => t('Merci hours'),
        // Provide a default administration path for Field UI, but not if 'admin'
        // has been explicitly set to NULL.
        'admin' => array(
          'path' => 'admin/merci/config/merci-hours',
        ),
      ),
    ),
    'label' => t('Merci hours'),
    'plural label' => t('Merci hours'),
    'entity class' => 'MerciHours',
    'controller class' => 'EntityAPIControllerExportable',
    'exportable' => TRUE,
    'admin ui' => array(
      'path' => 'admin/merci/config/merci-hours',
      'file' => 'includes/entity.ui.inc',
    ),
    'access callback' => 'merci_hours_access',
  );
  return $info;
}

/**
 * Implements access callback.
 */
function merci_hours_access($op, $entity = NULL, $account = NULL) {
  switch ($op) {

    //case 'view':

    //case 'update':

    //case 'create':

    //case 'edit':
    case 'delete':
      $default = variable_get('merci_hours_default', NULL);
      if (isset($entity) and $entity->name == $default) {
        drupal_set_message(t("This is the default merci hours and can't be deleted. Please change the default merci hours at <a href='!url'>admin/config/merci/merci-hours/settings</a> if you want to delete this one.", array(
          '!url' => url('admin/config/merci/merci-hours/settings'),
        )), 'error');
        return false;
      }
      break;
  }
  return user_access('administer all merci hours');
}

/**
 * Returns all merci hours indexed by name, or just the one requested.
 *
 * Used by machine name existence check
 * also useful for menu path wildcard loader.
 */
function merci_hours_load($name = NULL) {
  $wc = entity_load_multiple_by_name('merci_hours', isset($name) ? array(
    $name,
  ) : FALSE);
  return isset($name) ? reset($wc) : $wc;
}

/**
 * Returns a merci hours selection form element.
 *
 * @param boolean include_default wether to add "use site default" as an option.
 * @param integer default_value Id of the default merci hours.
 *
 * @return form element.
 */
function merci_hours_form_element($include_default = FALSE, $default_value = NULL) {
  $options = array();
  if ($include_default && variable_get('merci_hours_default', FALSE)) {
    $options[0] = t('-- use site default --');
  }
  $options += db_select('merci_hours', 'wc')
    ->fields('wc', array(
    'name',
    'label',
  ))
    ->execute()
    ->fetchAllKeyed(0, 1);
  $element = array(
    '#type' => 'select',
    '#title' => t('Choose merci hours'),
    '#default_value' => $default_value,
    '#options' => $options,
  );
  return $element;
}

/**
 * Implements hook_field_info_alter().
 *
 * Extends instance settings of date fields with work calendar defaults.
 */
function merci_hours_field_info_alter(&$info) {
  $settings = array(
    'merci_hours' => array(
      'set_merci_date_enabled' => FALSE,
      'enabled' => FALSE,
      'id' => NULL,
      'min_date' => NULL,
      'max_date' => NULL,
    ),
  );
  $fields = array(
    'datetime',
  );
  foreach ($fields as $field) {
    $info[$field]['instance_settings'] += $settings;
  }
}

/**
 * Implements hook_date_field_instance_settings_form_alter().
 *
 * Adds elements to instance settings form of date fields to configure
 * work calendar settings.
 */
function merci_hours_date_field_instance_settings_form_alter(&$form, $context) {
  $settings = $context['instance']['settings'];
  $form['merci_hours'] = array(
    '#type' => 'fieldset',
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#title' => 'Merci hours',
    '#fieldset' => 'defaults',
  );
  $form['merci_hours']['enabled'] = array(
    '#type' => 'checkbox',
    '#title' => t('Restrict dates based on Merci hours.'),
    '#default_value' => $settings['merci_hours']['enabled'],
  );
  $form['merci_hours']['id'] = merci_hours_form_element(TRUE, $settings['merci_hours']['id']);
  $form['merci_hours']['id']['#states'] = array(
    'enabled' => array(
      ':input[name="instance[settings][merci_hours][enabled]"]' => array(
        'checked' => TRUE,
      ),
    ),
  );
  $form['merci_hours']['min_date'] = array(
    '#type' => 'textfield',
    '#title' => t('Minimum date'),
    '#description' => t('Relative date a reservation can be made; valid periods are "y" for years, "m" for months, "w" for weeks, and "d" for days. For example, "+1m +7d" represents one month and seven days from today. "-1d" represents one day before today.'),
    '#default_value' => $settings['merci_hours']['min_date'],
  );
  $form['merci_hours']['max_date'] = array(
    '#type' => 'textfield',
    '#title' => t('Maximum date'),
    '#description' => t('Relative date a reservation can be made; valid periods are "y" for years, "m" for months, "w" for weeks, and "d" for days. For example, "+1m +7d" represents one month and seven days from today. "-1d" represents one day before today.'),
    '#default_value' => $settings['merci_hours']['max_date'],
  );
}

/**
 * Implements hook_date_popup_process_alter().
 *
 * This function perform two tasks:
 *   - adds an extra validation callback if a work calendar is set
 *   - adds javascript settings to control the available days in the popup.
 */
function merci_hours_date_popup_process_alter(&$element, $form_state, $context) {
  if (!array_key_exists('#instance', $element)) {
    return;
  }
  $settings = $element['#instance']['settings']['merci_hours'];
  if ($settings['enabled']) {
    $element['#element_validate'][] = 'merci_hours_date_element_validate';
    $merci_hours = variable_get('merci_hours_default', '');

    // Current year. TODO: extend to a dinamic ajax callback.
    // Limit selectable days based on days open.
    $element['date']['#attributes']['class'][] = 'merci-hours-date-popup';
    $id = $element['date']['#id'];
    $settings = array(
      $id => array(
        'settings' => array(
          'workCalendar' => $merci_hours,
          'openDays' => merci_hours_get_open_days_in_year($merci_hours),
          'minDate' => $settings['min_date'],
          'maxDate' => $settings['max_date'],
          'timeid' => $element['time']['#id'],
        ),
      ),
    );
    drupal_add_js(array(
      'datePopup' => $settings,
    ), 'setting');
    drupal_add_js(drupal_get_path('module', 'merci_hours') . '/merci_hours_date_popup.js');

    // Limit selectable times based on hours open.
    $return_id = $element['time']['#id'];
    $open_hours = merci_hours_get_open_hours($merci_hours, 4);
    $element['time']['#attributes']['class'][] = 'merci-hours-timefield';
    $settings = array(
      'minTime' => $open_hours['open'],
      'maxTime' => $open_hours['close'],
      'dateid' => $element['date']['#id'],
      'workCalendar' => $merci_hours,
    );
    if (empty($element['time']['#value'])) {
      $element['time']['#value'] = $open_hours['open'];
    }
    $js_settings['datePopup'][$return_id] = array(
      'settings' => $settings,
    );
    drupal_add_js($js_settings, 'setting');
  }
  if (end($element['#parents']) == 'value2') {
    $element['#states'] = array(
      'visible' => array(
        ':input[name="set_merci_date"]' => array(
          'value' => 'custom',
        ),
      ),
    );
  }
}

/**
 * Validate callback for date form elements with #work_calendar.
 *
 * Check the date is a open day in the in the work calendar.
 */
function merci_hours_date_element_validate($element, &$form_state, $form) {
}

/**
 * Implements hook_merci_fields_info().
 */
function merci_hours_merci_fields_info() {
  $fields = array();

  // Exported field_base: 'field_office_hours'
  $fields[MERCI_HOURS_FIELD] = array(
    'field' => array(
      'cardinality' => -1,
      'field_name' => MERCI_HOURS_FIELD,
      'type' => 'datetime',
      'settings' => array(
        'todate' => 'required',
        'tz_handling' => 'none',
      ),
    ),
    'instance' => array(
      'label' => 'Office hours',
      'required' => 0,
      'widget' => array(
        'module' => 'merci_hours',
        'type' => 'merci_hours',
      ),
    ),
  );
  return $fields;
}

/**
 * Load the requested calendar or site's default if none given.
 */
function merci_hours_instantiate($name = NULL) {
  if (empty($name)) {
    $name = variable_get('merci_hours_default');
    if (empty($name)) {
      throw new Exception('Default merci hours not configured.');
    }
  }
  $wc = entity_load_single('merci_hours', $name);
  if (!$wc) {
    throw new Exception($name . ' merci hours doesn\'t exist.');
  }
  $week_days = array();
  $weekdays = date_week_days_untranslated();
  foreach ($wc->{MERCI_HOURS_FIELD}[LANGUAGE_NONE] as $timefield) {
    $open = new DateObject($timefield['value']);
    $day = $open
      ->format('w');
    $week_days[] = $weekdays[$day];
  }
  $wc
    ->updateWeek($week_days);
  return $wc;
}

/**
 * Complete empty date parts with today values.
 */
function merci_hours_complete_date($year, $month = NULL, $day = NULL) {
  $year = is_null($year) ? date('Y') : $year;
  $month = is_null($month) ? date('m') : $month;
  $day = is_null($day) ? date('d') : $day;
  return array(
    $year,
    $month,
    $day,
  );
}

/**
 * Wrapper for WorkCalendar::openDays().
 */
function merci_hours_get_open_days_in_year($cal = NULL, $year = NULL) {
  $wc = merci_hours_instantiate($cal);
  list($year, , ) = merci_hours_complete_date($year);
  $dates = $wc
    ->getOpenDays($year);
  $context = array(
    'year' => $year,
  );
  drupal_alter('merci_dates_open', $dates, $wc, $context);
  return $dates;
}

/**
 * Wrapper for WorkCalendar::openDays().
 */
function merci_hours_get_open_days_in_month($cal = NULL, $year = NULL, $month = NULL) {
  $wc = merci_hours_instantiate($cal);
  list($year, $month, ) = merci_hours_complete_date($year, $month);
  $dates = $wc
    ->getOpenDays($year, $month);
  $context = array(
    'year' => $year,
    'month' => $month,
  );
  drupal_alter('merci_dates_open', $dates, $wc, $context);
  return $dates;
}

/**
 * Return array of office hours keyed by day of the week.
 */
function merci_hours_get_open_hours_by_day($cal) {
  $hours =& drupal_static(__FUNCTION__, array());
  if (!array_key_exists($cal, $hours)) {
    $wc = merci_hours_instantiate($cal);
    $cal_hours = array();
    foreach ($wc->{MERCI_HOURS_FIELD}[LANGUAGE_NONE] as $timefield) {
      $open = new DateObject($timefield['value']);
      $close = new DateObject($timefield['value2']);
      $day_of_week = $open
        ->format('w');
      if (!array_key_exists($day_of_week, $cal_hours)) {
        $cal_hours[$day_of_week] = array();
      }
      $cal_hours[$day_of_week][] = array(
        'open' => $open,
        'close' => $close,
      );
    }
    $hours[$cal] = $cal_hours;
  }
  return $hours[$cal];
}

/**
 * returns the open and close hours for the given calendar and day of week.
 *
 * Used to filter the hours widget.
 */
function merci_hours_get_open_hours($cal = NULL, $day = NULL) {
  $hours = merci_hours_get_open_hours_by_day($cal);
  if (array_key_exists($day, $hours)) {
    $open = $hours[$day][0]['open'];
    $close = $hours[$day][0]['close'];
    return array(
      'open' => $open
        ->format('g:ia'),
      'close' => $close
        ->format('g:ia'),
    );
  }
  else {
    return array(
      'open' => '',
      'close' => '',
    );
  }
}

/**
 * Determine if we are open during the given time.
 */
function merci_hours_time_is_open($cal, $day, $time) {
  $open_hours = merci_hours_get_open_hours_by_day($cal, $day);
  foreach ($open_hours[$day] as $hours) {
    $open = $hours['open'];
    $close = $hours['close'];
    $open_hour = $open
      ->format('H:i:s');
    $close_hour = $close
      ->format('H:i:s');
    if ($time >= $open_hour and $time <= $close_hour) {
      return TRUE;
    }
  }
  return FALSE;
}

/**
 *  * Wrapper for WorkCalendar::isOpenDay().
 */
function merci_hours_day_is_open($cal = NULL, $year = NULL, $month = NULL, $day = NULL) {
  $wc = merci_hours_instantiate($cal);
  list($year, $month, $day) = merci_hours_complete_date($year, $month, $day);
  return $wc
    ->isOpenDay($year, $month, $day);
}

Functions

Namesort descending Description
merci_hours_access Implements access callback.
merci_hours_complete_date Complete empty date parts with today values.
merci_hours_date_element_validate Validate callback for date form elements with #work_calendar.
merci_hours_date_field_instance_settings_form_alter Implements hook_date_field_instance_settings_form_alter().
merci_hours_date_open_days_ajax Page callback. Returns json array for ajax calls.
merci_hours_date_popup_process_alter Implements hook_date_popup_process_alter().
merci_hours_day_is_open Wrapper for WorkCalendar::isOpenDay().
merci_hours_entity_info Implements hook_entity_info().
merci_hours_field_info_alter Implements hook_field_info_alter().
merci_hours_form_element Returns a merci hours selection form element.
merci_hours_get_open_days_in_month Wrapper for WorkCalendar::openDays().
merci_hours_get_open_days_in_year Wrapper for WorkCalendar::openDays().
merci_hours_get_open_hours returns the open and close hours for the given calendar and day of week.
merci_hours_get_open_hours_by_day Return array of office hours keyed by day of the week.
merci_hours_instantiate Load the requested calendar or site's default if none given.
merci_hours_load Returns all merci hours indexed by name, or just the one requested.
merci_hours_menu Implements hook_menu().
merci_hours_merci_fields_info Implements hook_merci_fields_info().
merci_hours_open_hours_ajax Page callback. Returns json array for ajax calls.
merci_hours_permission Implements hook_permission().
merci_hours_time_is_open Determine if we are open during the given time.

Constants

Namesort descending Description
MERCI_HOURS_FIELD