type_setting != 'disabled') {
// Cast to object here, as it can come in both ways.
$node = (object) $form['#node'];
// Make the data representation consistent.
if (isset($node->merci_sub_type)) {
$sub_type = $node->merci_sub_type;
$default_availability = $node->merci_default_availability;
$late_fee_per_hour = $node->merci_late_fee_per_hour;
$rate_per_hour = $node->merci_rate_per_hour;
$fee_free_hours = $node->merci_fee_free_hours;
}
elseif (isset($node->merci['sub_type'])) {
$sub_type = $node->merci['sub_type'];
$default_availability = $node->merci['default_availability'];
$late_fee_per_hour = $node->merci['late_fee_per_hour'];
$rate_per_hour = $node->merci['rate_per_hour'];
$fee_free_hours = $node->merci['fee_free_hours'];
}
else {
$sub_type = MERCI_SUB_TYPE_ITEM;
$default_availability = MERCI_AVA_F;
// Only resource types have individual pricing data.
if ($merci_settings->type_setting == 'bucket') {
$rate_per_hour = 0;
$late_fee_per_hour = 0;
$fee_free_hours = 0;
}
else {
$rate_per_hour = $merci_settings->rate_per_hour;
$late_fee_per_hour = $merci_settings->late_fee_per_hour;
$fee_free_hours = $merci_settings->fee_free_hours;
}
}
// New nodes are always sub type item.
$form['merci_sub_type'] = array(
'#type' => 'value',
'#value' => $sub_type,
);
if (user_access('administer MERCI')) {
$form['merci'] = array(
'#type' => 'fieldset',
'#title' => t('MERCI settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['merci']['merci_default_availability'] = array(
'#title' => t('Default booking availability'),
'#type' => 'radios',
'#options' => merci_item_status(),
'#description' => t('If no availability information is defined for a given time, the resource falls back onto this setting.'),
'#default_value' => $default_availability,
);
// Bucket item nodes have no individual pricing, so just zero these values out.
if ($merci_settings->type_setting == 'bucket' && $sub_type == MERCI_SUB_TYPE_ITEM) {
$form['merci_rate_per_hour'] = array(
'#type' => 'value',
'#value' => $rate_per_hour,
);
$form['merci_late_fee_per_hour'] = array(
'#type' => 'value',
'#value' => $late_fee_per_hour,
);
$form['merci_fee_free_hours'] = array(
'#type' => 'value',
'#value' => $fee_free_hours,
);
}
else {
$form['merci']['merci_rate_per_hour'] = array(
'#type' => 'textfield',
'#title' => t('Rate per hour'),
'#size' => 10,
'#default_value' => $rate_per_hour,
'#element_validate' => array('merci_is_numeric_validate'),
'#description' => t('The per hour rental fee for the item.'),
);
$form['merci']['merci_late_fee_per_hour'] = array(
'#type' => 'textfield',
'#title' => t('Late fee per hour'),
'#size' => 10,
'#default_value' => $late_fee_per_hour,
'#element_validate' => array('merci_is_numeric_validate'),
'#description' => t('The per hour fee for returning the item late.'),
);
$form['merci']['merci_fee_free_hours'] = array(
'#type' => 'textfield',
'#title' => t('Fee free hours'),
'#size' => 10,
'#default_value' => $fee_free_hours,
'#element_validate' => array('merci_is_numeric_validate'),
'#description' => t('The number of hours the item can be used before fees are charged.'),
);
}
}
else {
$form['merci_default_availability'] = array(
'#type' => 'value',
'#value' => $default_availability,
);
$form['merci_rate_per_hour'] = array(
'#type' => 'value',
'#value' => $rate_per_hour,
);
$form['merci_late_fee_per_hour'] = array(
'#type' => 'value',
'#value' => $late_fee_per_hour,
);
$form['merci_fee_free_hours'] = array(
'#type' => 'value',
'#value' => $fee_free_hours,
);
}
}
}
}
switch ($form_id) {
// Add check availability button inside date selector.
case 'merci_reservation_node_form':
$form['field_merci_date'][0]['merci_date_filter'] = array(
'#type' => 'submit',
'#value' => t('Check availability'),
'#weight' => 10,
'#submit' => array('merci_date_filter'),
);
// Since hook_validate is broken in 6.x, we add our own
// custom validation here.
$form['#validate'][] = 'merci_node_validate';
break;
// Node settings form.
case 'node_type_form':
// Reservation content type can't used for other MERCI functionality.
if (isset($form['#node_type']->type) && $form['#node_type']->type == 'merci_reservation') {
return;
}
$warning = '
'. t(' WARNING: changing this setting has no effect on existing reserved items.') .'
';
$type = $form['old_type']['#value'];
$settings = db_fetch_object(db_query("SELECT * FROM {merci_node_type} WHERE type = '%s'", $type));
$options = array(
'disabled' => t('Disabled'),
'bucket' => t('Bucket'),
'resource' => t('Resource'),
);
$form['#validate'][] = 'merci_node_type_save_validate';
$form['#submit'][] = 'merci_node_type_save_submit';
$form['merci'] = array(
'#type' => 'fieldset',
'#title' => t('MERCI settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
// If any nodes have already been created, lock the type setting.
if (merci_check_existing_bucket_items($type)) {
$form['merci']['merci_type_setting'] = array(
'#type' => 'value',
'#value' => $settings->type_setting,
);
$form['merci']['merci_type_setting_display'] = array(
'#type' => 'item',
'#title' => t('Reservable item type'),
'#value' => $options[$settings->type_setting],
'#description' => t('The setting cannot be change because content already exists for this type.'),
);
}
else {
$description_items = array(
t('Resource: Use this content type to create unique items that can be reserved.'),
t('Bucket: Use this content type to create interchangable items that can be reserved (ex. Camera). Buckets reference interchangable items. The actual item does not have to be chosen until the reservation is checked out.'),
);
$form['merci']['merci_type_setting'] = array(
'#type' => 'radios',
'#title' => t('Reservable item type'),
'#options' => $options,
'#default_value' => $settings ? $settings->type_setting : 'disabled',
'#description' => theme('item_list', $description_items),
);
}
$status = array(
MERCI_STATUS_ACTIVE => t('Active'),
MERCI_STATUS_INACTIVE => t('Inactive'),
);
$form['merci']['merci_status'] = array(
'#type' => 'radios',
'#title' => t('Status'),
'#options' => $status,
'#default_value' => isset($settings->status) && $settings->status ? $settings->status : MERCI_STATUS_ACTIVE,
'#description' => t('Set to active to allow this type to be reserved.'),
);
// This setting is only valid for buckets.
if (!$settings || $settings->type_setting == 'bucket') {
$form['merci']['merci_spare_items'] = array(
'#type' => 'textfield',
'#title' => t('Spare items'),
'#size' => 10,
'#default_value' => $settings ? $settings->spare_items : 0,
'#element_validate' => array('merci_is_numeric_validate'),
'#description' => t("Set this to the number of items of this type that should always be available even when it's fully reserved.") . $warning,
);
}
else {
$form['merci']['merci_spare_items'] = array(
'#type' => 'value',
'#value' => 0,
);
}
$form['merci']['merci_max_hours_per_reservation'] = array(
'#type' => 'textfield',
'#title' => t('Maximum hours per reservation'),
'#size' => 10,
'#default_value' => $settings ? $settings->max_hours_per_reservation : 0,
'#element_validate' => array('merci_is_numeric_validate'),
'#description' => t('The maximum hours the item can be reserved for in one reservation. Set to zero for no limit.') . $warning,
);
$form['merci']['merci_allow_overnight'] = array(
'#type' => 'checkbox',
'#title' => t('Allow overnight reservation'),
'#default_value' => $settings ? $settings->allow_overnight : 0,
'#description' => t('Allow a reservation to continue over multiple days.') . $warning,
);
$form['merci']['merci_allow_weekends'] = array(
'#type' => 'checkbox',
'#title' => t('Allow weekend reservation'),
'#default_value' => $settings ? $settings->allow_weekends : 0,
'#description' => t('Allow a reservation to be made on a weekend day.') . $warning,
);
$form['merci']['merci_rate_per_hour'] = array(
'#type' => 'textfield',
'#title' => t('Rate per hour'),
'#size' => 10,
'#default_value' => $settings ? $settings->rate_per_hour : 0,
'#element_validate' => array('merci_is_numeric_validate'),
'#description' => t('The per hour rental fee for the item.'),
);
$form['merci']['merci_late_fee_per_hour'] = array(
'#type' => 'textfield',
'#title' => t('Late fee per hour'),
'#size' => 10,
'#default_value' => $settings ? $settings->late_fee_per_hour : 0,
'#element_validate' => array('merci_is_numeric_validate'),
'#description' => t('The per hour fee for returning the item late.'),
);
$form['merci']['merci_fee_free_hours'] = array(
'#type' => 'textfield',
'#title' => t('Fee free hours'),
'#size' => 10,
'#default_value' => $settings ? $settings->fee_free_hours : 0,
'#element_validate' => array('merci_is_numeric_validate'),
'#description' => t('The number of hours the item can be used before fees are charged.'),
);
$form['merci']['merci_min_cancel_hours'] = array(
'#type' => 'textfield',
'#title' => t('Minimum hours for cancelation without No Show'),
'#size' => 10,
'#default_value' => $settings ? $settings->min_cancel_hours : 0,
'#element_validate' => array('merci_is_numeric_validate'),
'#description' => t('Minimum number of hours a user can cancel a reservation for the item.'),
);
break;
case 'node_delete_confirm':
$node = node_load((int) arg(1));
merci_delete_item_validate($node);
break;
case 'node_type_delete_confirm':
$type = str_replace('-', '_', arg(3));
merci_delete_node_type_validate($type);
break;
case 'node_admin_content':
if (!isset($form['#validate'])) {
$form['#validate'] = array();
}
$form['#validate'][] = 'merci_node_admin_delete_validate';
break;
}
}
/**
* Implementation of hook_menu().
*/
function merci_menu() {
$admin = array('administer MERCI');
// Callback for AJAX adding of item selectors.
$items['merci/js'] = array(
'title' => 'Javascript Choice Form',
'page callback' => 'merci_choice_js',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
// Administration settings.
$items['admin/settings/merci'] = array(
'title' => 'MERCI',
'page callback' => 'drupal_get_form',
'page arguments' => array('merci_admin_settings'),
'access callback' => 'user_access',
'access arguments' => $admin,
'description' => t('Configure system settings for MERCI.'),
);
$items['merci/taxonomy'] = array(
'title' => 'JSON interface for node taxonomy',
'description' => 'Takes a node ID and returns taxonomy data as JSON',
'page arguments' => array(2),
'page callback' => 'merci_taxonomy_json',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
$items['merci/contract'] = array(
'title' => 'Printable contract',
'description' => 'Takes a node ID and returns a printable contract',
'page arguments' => array(2),
'page callback' => 'merci_printable_contract',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Builds the MERCI admininstration settings form.
*/
function merci_admin_settings() {
$form = array();
$form['merci_hours_mon'] = array(
'#type' => 'textfield',
'#title' => t('Monday hours'),
'#size' => 11,
'#maxlength' => 11,
'#default_value' => variable_get('merci_hours_mon', ''),
'#description' => t('
Enter military time for both opening and closing time, separated by a dash, in the format hh:mm-hh:mm
ex. 09:00-17:00 would be open at 9AM, close at 5PM. Leave blank to indicate not being open.'),
);
$form['merci_hours_tue'] = array(
'#type' => 'textfield',
'#title' => t('Tuesday hours'),
'#size' => 11,
'#maxlength' => 11,
'#default_value' => variable_get('merci_hours_tue', ''),
'#description' => t('
Enter military time for both opening and closing time, separated by a dash, in the format hh:mm-hh:mm
ex. 09:00-17:00 would be open at 9AM, close at 5PM. Leave blank to indicate not being open.'),
);
$form['merci_hours_wed'] = array(
'#type' => 'textfield',
'#title' => t('Wednesday hours'),
'#size' => 11,
'#maxlength' => 11,
'#default_value' => variable_get('merci_hours_wed', ''),
'#description' => t('
Enter military time for both opening and closing time, separated by a dash, in the format hh:mm-hh:mm
-- ex. 09:00-17:00 would be open at 9AM, close at 5PM. Leave blank to indicate not being open.'),
);
$form['merci_hours_thu'] = array(
'#type' => 'textfield',
'#title' => t('Thursday hours'),
'#size' => 11,
'#maxlength' => 11,
'#default_value' => variable_get('merci_hours_thu', ''),
'#description' => t('
Enter military time for both opening and closing time, separated by a dash, in the format hh:mm-hh:mm
ex. 09:00-17:00 would be open at 9AM, close at 5PM. Leave blank to indicate not being open.'),
);
$form['merci_hours_fri'] = array(
'#type' => 'textfield',
'#title' => t('Friday hours'),
'#size' => 11,
'#maxlength' => 11,
'#default_value' => variable_get('merci_hours_fri', ''),
'#description' => t('
Enter military time for both opening and closing time, separated by a dash, in the format hh:mm-hh:mm
ex. 09:00-17:00 would be open at 9AM, close at 5PM. Leave blank to indicate not being open.'),
);
$form['merci_hours_sat'] = array(
'#type' => 'textfield',
'#title' => t('Saturday hours'),
'#size' => 11,
'#maxlength' => 11,
'#default_value' => variable_get('merci_hours_sat', ''),
'#description' => t('
Enter military time for both opening and closing time, separated by a dash, in the format hh:mm-hh:mm
ex. 09:00-17:00 would be open at 9AM, close at 5PM. Leave blank to indicate not being open.'),
);
$form['merci_hours_sun'] = array(
'#type' => 'textfield',
'#title' => t('Sunday hours'),
'#size' => 11,
'#maxlength' => 11,
'#default_value' => variable_get('merci_hours_sun', ''),
'#description' => t('
Enter military time for both opening and closing time, separated by a dash, in the format hh:mm-hh:mm
ex. 09:00-17:00 would be open at 9AM, close at 5PM. Leave blank to indicate not being open.'),
);
$form['merci_closed_dates'] = array(
'#type' => 'textarea',
'#title' => t('Closed dates'),
'#rows' => 10,
'#cols' => 5, // TODO: this doesn't seem to work...
'#default_value' => variable_get('merci_closed_dates', ''),
'#description' => t('
Enter dates which are closed regardless of the day of the week, one date per line, in the format mm-dd
ex. 07-04 would mean July 4th is always closed, regardless of what day of the week it falls on.'),
);
$form['merci_contract_header'] = array(
'#type' => 'textarea',
'#title' => t('Contract header'),
'#rows' => 10,
'#cols' => 5, // TODO: this doesn't seem to work...
'#default_value' => variable_get('merci_contract_header', ''),
'#description' => t('Header portion of printable contract. Allows HTML.'),
);
$form['merci_contract_boilerplate'] = array(
'#type' => 'textarea',
'#title' => t('Contract boilerplate'),
'#rows' => 10,
'#cols' => 5, // TODO: this doesn't seem to work...
'#default_value' => variable_get('merci_contract_boilerplate', ''),
'#description' => t('Legalese that makes the contract legally binding.'),
);
$form['merci_contract_footer'] = array(
'#type' => 'textarea',
'#title' => t('Contract footer'),
'#rows' => 10,
'#cols' => 5, // TODO: this doesn't seem to work...
'#default_value' => variable_get('merci_contract_footer', ''),
'#description' => t('Footer portion of printable contract. Normally includes signature lines. Allows HTML.'),
);
return system_settings_form($form);
}
/**
* Implementation of hook_node_info().
*/
function merci_node_info() {
return array(
// Reservation nodes.
'merci_reservation' => array(
'name' => t('Reservation'),
'module' => 'merci',
'has_body' => FALSE,
'description' => t("A reservation reserves a resource or group of resources for some period of time."),
),
);
}
/**
* Implementation of hook_node_info().
*/
function merci_node_type($op, $info) {
switch ($op) {
case 'update':
// If type was edited, update it.
if (isset($info->old_type) && $info->type != $info->old_type) {
db_query("UPDATE {merci_node_type} SET type = '%s' WHERE type = '%s'", $info->type, $info->old_type);
}
break;
case 'delete':
db_query("DELETE FROM {merci_node_type} WHERE type = '%s'", $info->type);
break;
}
}
/**
* Implementation of hook_form().
*/
function merci_form(&$node, $form_state) {
$form = node_content_form($node, $form_state);
// Build existing reserved items table on existing reservations.
if (isset($node->nid)) {
$form['existing_items'] = merci_build_reservation_table_form($form_state, $node, TRUE);
$merci = $node->merci;
}
else {
$merci['status'] = MERCI_STATUS_UNCONFIRMED;
}
// Choice adding code mostly stolen from poll module.
if (isset($form_state['choice_count'])) {
$choice_count = $form_state['choice_count'];
}
else {
$choice_count = max(3, empty($node->choice) ? 3 : count($node->choice));
}
// Add a wrapper for the choices and more button.
$form['choice_wrapper'] = array(
'#tree' => FALSE,
'#prefix' => '
',
'#suffix' => '
',
);
// Container for just the item selector.
$form['choice_wrapper']['choice'] = array(
'#prefix' => '
',
'#suffix' => '
',
'#theme' => 'merci_choices',
);
// Add the current choices to the form.
for ($delta = 0; $delta < $choice_count; $delta++) {
$default = isset($node->choice[$delta]['item']) ? $node->choice[$delta]['item'] : '';
$form['choice_wrapper']['choice'][$delta] = _merci_choice_form($node, $form_state, $delta, $default);
}
// We name our button 'merci_more' to avoid conflicts with other modules using
// AHAH-enabled buttons with the id 'more'.
$form['choice_wrapper']['merci_more'] = array(
'#type' => 'submit',
'#value' => t('Add more items'),
'#description' => t("If the amount of items above isn't enough, click here to add more items."),
'#weight' => 1,
'#submit' => array('merci_more_choices_submit'), // If no javascript action.
/* '#ahah' => array(
'path' => 'merci/js',
'wrapper' => 'merci-choices',
'method' => 'replace',
'effect' => 'fade',
),*/
);
if (user_access('administer MERCI')) {
$form['merci'] = array(
'#type' => 'fieldset',
'#title' => t('MERCI settings'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['merci']['merci_status'] = array(
'#title' => t('Status'),
'#type' => 'radios',
'#options' => merci_record_status(),
'#default_value' => $merci['status'],
'#description' => t('Finalized bookings cannot have time conflicts with each other.'),
);
}
else {
$form['merci_status'] = array(
'#type' => 'value',
'#value' => $merci['status'],
);
}
return $form;
}
/**
* Submit handler to add more choices to a reservation form. This handler is used when
* javascript is not available. It makes changes to the form state and the
* entire form is rebuilt during the page reload.
*/
function merci_more_choices_submit($form, &$form_state) {
// Set the form to rebuild and run submit handlers.
node_form_submit_build_node($form, $form_state);
// Make the changes we want to the form state.
if ($form_state['values']['merci_more']) {
$form_state['choice_count'] = count($form_state['values']['choice']) + 5;
}
}
/**
* Submit handler to date filter items on a reservation form.
* It makes changes to the form state and the entire form is
* rebuilt during the page reload.
*/
function merci_date_filter($form, &$form_state) {
// Set the form to rebuild and run submit handlers.
node_form_submit_build_node($form, $form_state);
}
/**
* Builds an individual item selector.
*
* @param $node
* The reservation node object.
* @param $form_state
* Current form state array.
* @param $delta
* Which selector number to build.
* @param $default
* Default value for the select.
* @return
* The form array for the selector.
*/
function _merci_choice_form($node, $form_state, $delta, $default = '') {
$form = array(
'#tree' => TRUE,
);
// We'll manually set the #parents property of these fields so that
// their values appear in the $form_state['values']['choice'] array.
$options = merci_build_reservable_items($node, $form_state);
$form['item'] = array(
'#type' => 'select',
'#title' => t('Reserve item @n', array('@n' => ($delta + 1))),
'#options' => $options['options'],
'#default_value' => $default,
'#parents' => array('choice', $delta, 'item'),
);
return $form;
}
/**
* Builds the list of all currently reservable items, filtered by date.
*
* @param $node
* The reservation node object.
* @param $form_state
* Current form state array.
* @param $reservation_nid
* (Optional) The nid of a reservation to ignore in the options exclusions.
* @return
* An associative array with the following key/value pairs:
* 'options' => An array of available items, in the format used
* for the item selector.
* 'flat_options' => An array of available items, whose values are the
* nids of the items.
*/
function merci_build_reservable_items($node, $form_state, $reservation_nid = NULL) {
// Newly set dates take precedence.
if (isset($form_state['values']['field_merci_date'])) {
$start = $form_state['values']['field_merci_date'][0]['value'];
$end = $form_state['values']['field_merci_date'][0]['value2'];
}
// Dates loaded from the reservation are next.
elseif (isset($node->nid)) {
$date_info = $node->field_merci_date[0];
$start = $date_info['value'];
$end = $date_info['value2'];
}
// New reservation, so no date filtering.
else {
$is_new = TRUE;
}
$options = array();
$options['options'] = array('' => t('