You are here

function merci_node_validate in MERCI (Manage Equipment Reservations, Checkout and Inventory) 6

Same name and namespace in other branches
  1. 6.2 merci.module \merci_node_validate()

Implementation of hook_validate().

1 string reference to 'merci_node_validate'
merci_form_alter in ./merci.module
Implementation of hook_form_alter().

File

./merci.module, line 2188
MERCI - Managed Equipment Reservation Checkout and Inventory

Code

function merci_node_validate($form, &$form_state) {
  if (user_access('suspend MERCI access') && !user_access('administer MERCI')) {
    form_set_error('merci_status', t('Your access to make new Reservations or edit existing Reservations has been suspended.'));
  }
  else {
    $node = (object) $form_state['values'];

    // No validation necessary on deletion.
    if ($form_state['clicked_button']['#id'] != 'edit-delete') {

      // Reservations with a checked out status.
      if ($node->merci_status == MERCI_STATUS_CHECKED_OUT) {

        // Make sure all existing bucket reservations have an item assigned.
        if (isset($node->existing_items['items'])) {
          foreach ($node->existing_items['items'] as $did => $item_nid) {
            if (!$item_nid) {
              form_set_error("existing_items][items][{$did}", t("The bucket reservation must have an item associated with it for finalized reservations."));
            }
          }
        }
        else {
          form_set_error('merci_status', t('You can not finalize a reservation that has no reserved items.'));
        }

        // Can't add a bucket item and finalize at the same time.
        foreach ($node->choice as $num => $choice) {
          $item = $choice['item'];
          if ($item && !is_numeric($item)) {
            form_set_error("choice][{$num}][item", t("You cannot finalize a reservation while adding a bucket item."));
          }
        }
      }

      // Build date objects we'll need for our different validations.
      $start = $node->field_merci_date[0]['value'];
      $end = $node->field_merci_date[0]['value2'];
      $start_object = merci_create_local_date_object($start);
      $end_object = merci_create_local_date_object($end);
      $hours_of_operation = merci_load_hours_of_operation();
      $start_day_of_week = (int) date_format($start_object, 'w');
      $end_day_of_week = (int) date_format($end_object, 'w');
      $start_month_day = date_format($start_object, 'm-d');
      $end_month_day = date_format($end_object, 'm-d');
      $start_hours = $hours_of_operation[$start_day_of_week];
      $end_hours = $hours_of_operation[$end_day_of_week];
      $start_date = date_format($start_object, 'm-d-Y');
      $max_days = variable_get("merci_max_days_advance_reservation", '0');

      //Users in role with Administer MERCI permssion are exempt from content type and hours of operation restrictions
      if (user_access('administer MERCI') || user_access('create reservations outside hours of operation')) {
        drupal_set_message(t('You may be making a Reservation outside the normal hours of operation.  This may impact access to the items you are reserving.'));
      }
      else {

        // Reservation start date cannot exceed the max advance
        if ($max_days) {
          $max_date = new DateTime("+{$max_days} day");
          if ($start_object > $max_date) {
            form_set_error('merci_status', t('You cannot make a Reservation more than %days days in advance. Start the Reservation before %date.', array(
              '%days' => $max_days,
              '%date' => date_format($max_date, 'm-d-Y'),
            )));
          }
        }

        // Can't start or end a reservation on days that are
        // closed dates.
        if (in_array($start_month_day, $hours_of_operation['closed_days'])) {
          $name = date_format($start_object, 'F jS');
          form_set_error('field_merci_date][0][value][date', t('Sorry, but we are closed on %day for a holiday or special event.', array(
            '%day' => $name,
          )));
        }
        if (in_array($end_month_day, $hours_of_operation['closed_days'])) {
          $name = date_format($end_object, 'F jS');
          form_set_error('field_merci_date][0][value2][date', t('Sorry, but we are closed on %day for a holiday or special event.', array(
            '%day' => $name,
          )));
        }

        // Can't start or end a reservation on a day the facility
        // has no hours of operation, or outside hours of operation.
        $start_name = date_format($start_object, 'l');
        if (!$hours_of_operation[$start_day_of_week]) {
          form_set_error('field_merci_date][0][value][date', t('Reservations cannot start on a %day.', array(
            '%day' => $start_name,
          )));
        }
        else {
          $start_time = date_format($start_object, 'H:i');
          if ($start_time < $start_hours['open']) {
            form_set_error('field_merci_date][0][value][time', t('Reservations cannot start on a %day before %start.', array(
              '%day' => $start_name,
              '%start' => merci_format_time($start_hours['open']),
            )));
          }
          elseif ($start_time > $start_hours['close']) {
            form_set_error('field_merci_date][0][value][time', t('Reservations cannot start on a %day after %end.', array(
              '%day' => $start_name,
              '%end' => merci_format_time($start_hours['close']),
            )));
          }
        }
        $end_name = date_format($end_object, 'l');
        if (!$hours_of_operation[$end_day_of_week]) {
          form_set_error('field_merci_date][0][value2][date', t('Reservations cannot end on a %day.', array(
            '%day' => $end_name,
          )));
        }
        else {
          $end_time = date_format($end_object, 'H:i');
          if ($end_time < $end_hours['open']) {
            form_set_error('field_merci_date][0][value2][time', t('Reservations cannot end on a %day before %start.', array(
              '%day' => $end_name,
              '%start' => merci_format_time($end_hours['open']),
            )));
          }
          elseif ($end_time > $end_hours['close']) {
            form_set_error('field_merci_date][0][value2][time', t('Reservations cannot end on a %day after %end.', array(
              '%day' => $end_name,
              '%end' => merci_format_time($end_hours['close']),
            )));
          }
        }
      }

      // Tests for existing items.
      if (isset($node->nid)) {

        // For saved reservations, include the items already reserved
        // in the available list.
        $options = merci_build_reservable_items($node, $form_state, $node->nid);
      }
      else {
        $options = merci_build_reservable_items($node, $form_state);
      }
      $flat_options = $options['flat_options'];
      if (isset($node->existing_items)) {

        // Check each reserved item.
        foreach ($node->existing_items['bucket_resource'] as $did => $value) {

          // The item is no longer reservable, so figure out why.
          if (!in_array($value, $flat_options)) {

            // Resource.
            if (is_numeric($value)) {
              $new_item = db_fetch_object(db_query("SELECT title, type FROM {node} WHERE nid = %d", $value));
              $title = $new_item->title;
              $type = $new_item->type;
            }
            elseif ($value) {
              $title = db_result(db_query("SELECT name FROM {node_type} WHERE type = '%s'", $value));
              $type = $value;
            }

            // Make sure the item still passes content type restrictions.
            $restrictions = merci_check_content_type_restrictions($type, $start, $end);
            if (!empty($restrictions)) {
              $message = '';
              foreach ($restrictions as $restriction) {
                $message .= '<div>' . strtr($restriction, array(
                  '%name' => theme('placeholder', $title),
                )) . '</div>';
              }
            }
            else {
              $message = t("The existing reservation for %name is no longer reservable with your current date settings.", array(
                '%name' => $title,
              ));
            }
            form_set_error("existing_items][placeholders][{$did}", $message);
          }
          elseif (!is_numeric($value)) {
            $bucket_items = array_keys(merci_get_available_bucket_items($node, $value));
            $assigned_item = (int) $node->existing_items['items'][$did];
            if ($assigned_item && !in_array($assigned_item, $bucket_items)) {
              $title_name = db_fetch_object(db_query("SELECT n.title, nt.name FROM {node} n INNER JOIN {node_type} nt ON n.type = nt.type WHERE n.nid = %d", $assigned_item));
              form_set_error("existing_items][placeholders][{$did}", t("The assignment of %item for the %bucket reservation is no longer reservable with your current date settings.", array(
                '%item' => $title_name->title,
                '%bucket' => $title_name->name,
              )));
            }
          }
        }
      }

      // Tests for new items.
      if (isset($node->nid)) {

        // Only need to rebuild this again for existing nodes.
        $options = merci_build_reservable_items($node, $form_state);
        $flat_options = $options['flat_options'];
      }

      // Check each new item.
      foreach ($node->choice as $num => $choice) {

        // The item is no longer reservable, so figure out why.
        if ($choice['item'] && !in_array($choice['item'], $flat_options)) {

          // Resource.
          if (is_numeric($choice['item'])) {
            $new_item = db_fetch_object(db_query("SELECT title, type FROM {node} WHERE nid = %d", $choice['item']));
            $title = $new_item->title;
            $type = $new_item->type;
          }
          elseif ($choice['item']) {
            $title = db_result(db_query("SELECT name FROM {node_type} WHERE type = '%s'", $choice['item']));
            $type = $choice['item'];
          }

          // Make sure the item still passes content type restrictions.
          $restrictions = merci_check_content_type_restrictions($type, $start, $end);
          if (!empty($restrictions)) {
            $message = '';
            foreach ($restrictions as $restriction) {
              $message .= '<div>' . strtr($restriction, array(
                '%name' => theme('placeholder', $title),
              )) . '</div>';
            }
          }
          else {
            $count_sql = "SELECT COUNT(n.nid) \n             FROM {node} n \n             JOIN {merci_node_type} t\n             ON t.type = n.type\n             WHERE n.status = 1 AND\n             (\n               (\n                 t.type_setting = 'bucket'\n                 AND n.type = '%s'\n               ) OR\n               (\n                 t.type_setting = 'resource'\n                 AND n.title = '%s'\n               )\n             )";
            $count = db_result(db_query($count_sql, $type, $title));
            $start_mysql = date('Y-m-d', strtotime($start));
            $end_mysql = date('Y-m-d', strtotime($end . ' +1 day'));
            $reservations = merci_load_reservations_for_type_in_timespan($type, $start_mysql, $end_mysql);
            $reservations_by_date = array();
            $hours = merci_load_hours_of_operation();
            $message = '<div> ' . t("The dates and times for %name conflict with one or more existing reservations", array(
              '%name' => $title,
            )) . '</div>';
            $message .= '<div class="merci-availability-key"><span class="available"></span> = available <span class="unavailable"></span> = unavailable</div>';
            foreach ($reservations as $date => $times) {
              $date_timestamp = strtotime($date);
              $hours_date = $hours[date('w', $date_timestamp)];
              if (user_access('administer MERCI') || user_access('create reservations outside hours of operation')) {
                $adminhours = explode('-', variable_get('merci_hours_admin', '07:00-23:00'));
                $hours_date['open'] = $adminhours[0];
                $hours_date['close'] = $adminhours[1];
              }
              if (isset($hours_date['open'])) {
                $message .= '<table class="merci-availability-schedule"><thead><tr>';
                $message .= '<th>' . date('m/d/Y', $date_timestamp) . '</th>';
                $time = $hours_date['open'];
                while ($time < $hours_date['close']) {
                  $message .= '<th colspan="4">' . date('g:i a', strtotime($time)) . '</th>';
                  $time = date('H:i', strtotime($time . ' +1 hour'));
                }
                $message .= '</tr></thead><tbody>';
                for ($i = 1; $i <= $count; $i++) {
                  $message .= '<tr><th>' . htmlspecialchars($title);
                  if ($count > 1) {
                    $message .= ' ' . $i . '/' . $count;
                  }
                  $message .= '</th>';
                  $time = $hours_date['open'];
                  while ($time < $hours_date['close']) {
                    if ($times[$time . ':00'] >= $i) {
                      $message .= '<td class="unavailable"></td>';
                    }
                    else {
                      $message .= '<td class="available"></td>';
                    }
                    $time = date('H:i', strtotime($time . ' +15 minutes'));
                  }

                  // while
                  $message .= '</tr>';
                }

                // for
                $message .= '</tbody></table>';
              }

              // if
            }

            // foreach
          }
          form_set_error("choice][{$num}][item", $message);
        }
      }

      //if message wasn't set by a validation function
      if (!$message) {
        drupal_set_message(t('There are no conflicts with this Reservation.'));
      }

      // Prevent status changes on reservations that have past.
      $current_status = db_result(db_query("SELECT m.status FROM {node} n INNER JOIN {merci_reservation} m ON n.vid = m.vid WHERE n.nid = %d", $node->nid));
      if ($current_status && $current_status != $node->merci_status && time() > strtotime($node->field_merci_date[0]['value2']) && !in_array((int) $node->merci_status, array(
        MERCI_STATUS_CANCELLED,
        MERCI_STATUS_CHECKED_IN,
        MERCI_STATUS_DENIED,
      ))) {
        $statuses = merci_record_status();
        form_set_error('merci_status', t('You cannot change the status to %status for a reservation that has past.', array(
          '%status' => $statuses[$node->merci_status],
        )));
      }
    }
  }
}