array( 'title' => t('Book units'), 'description' => t('Allows users to book units'), ), ); return $permissions; } /** * Implements hook_menu(). */ function rooms_booking_manager_menu() { $items = array(); $items['booking'] = array( 'title' => t('Booking'), 'page callback' => 'rooms_booking_manager_search_availability', 'file' => 'rooms_booking_manager.availability_search.inc', 'access arguments' => array('book units'), 'type' => MENU_NORMAL_ITEM, ); $items['booking/%start_date/%end_date'] = array( 'title' => t('Booking'), 'page callback' => 'rooms_booking_manager_results_page', 'page arguments' => array(1, 2), 'access arguments' => array('book units'), 'type' => MENU_CALLBACK, ); $items['bookings'] = array( 'title' => 'Booking cart', 'page callback' => 'rooms_booking_manager_cart_view', 'access arguments' => array('access content'), ); $items['enquiry-confirmation'] = array( 'title' => 'Enquiry page', 'page callback' => 'rooms_booking_manager_enquiry_confirmation', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); return $items; } /** * */ function rooms_booking_manager_enquiry_confirmation() { return theme('rooms_booking_enquiry_confirmation', array('message' => 'Booking confirmed')); } /** * Displays the shopping cart form and associated information. */ function rooms_booking_manager_cart_view() { global $user; // Default to displaying an empty message. $content = theme('commerce_cart_empty_page'); // First check to make sure we have a valid order. if ($order = commerce_cart_order_load($user->uid)) { $wrapper = entity_metadata_wrapper('commerce_order', $order); // Only show the cart form if we found product line items. if (commerce_line_items_quantity($wrapper->commerce_line_items, commerce_product_line_item_types()) > 0) { drupal_add_css(drupal_get_path('module', 'commerce_cart') . '/theme/commerce_cart.theme.css'); // Add the form for editing the cart contents. $content = commerce_embed_view('booking_cart_form', 'default', array($order->order_id), 'cart'); } } return $content; } /** * Constructs the booking results page following an availability search * * @param $start_date * The start date for the search * * @param $end_date * The end date for the search * * @param $group_size_adults * How many are to be accommodated * * @param $b_units * In how many rooms are we to accommodate them */ function rooms_booking_manager_results_page($start_date = 0, $end_date = 0, $group_size_adults = 2, $group_size_children = 0, $b_units = 1) { // The array of content to render $content = array(); // Make sure variables are clear $group_size_adults = check_plain($group_size_adults); $group_size_children = check_plain($group_size_children); $b_units = check_plain($b_units); // Check validity of date range - this is repeating what we do in rooms_booking_manager_availability_search_form_validate // but if we want to cater for both direct links and query coming through form need to accommodate both. $datesok = rooms_booking_manager_check_dates($start_date, $end_date); if ($datesok) { $content['booking_results'] = 1; // Get all the units - note: we instantiate the Availability Agent using the date form set by the user $date_format = str_replace('-', '/', variable_get('rooms_date_format', 'd-m-Y')); $agent = new AvailabilityAgent($start_date->format($date_format), $end_date->format($date_format), $group_size_adults, $group_size_children, $b_units); $agent->setValidStates(variable_get('rooms_valid_availability_states', array(ROOMS_AVAILABLE, ROOMS_ON_REQUEST, ROOMS_UNCONFIRMED_BOOKINGS))); $units_per_type = $agent->checkAvailability(); if (($units_per_type == ROOMS_NO_ROOMS) || ($units_per_type == ROOMS_SIZE_FAILURE)) { $content['booking_results'] = 0; module_load_include('inc', 'rooms_booking_manager', 'rooms_booking_manager.availability_search'); $booking_search_form = drupal_get_form('rooms_booking_availability_search_form'); $no_results = array( '#prefix' => '
', '#markup' => '

' . t('Unfortunately no rooms are available - try different dates if possible.') . '

', '#suffix' => '
', ); $content['no_results'] = $no_results; $content['booking_search_form'] = $booking_search_form; } elseif (variable_get('rooms_presentation_style', ROOMS_PER_TYPE) == ROOMS_PER_TYPE) { $content = rooms_booking_manager_present_types($units_per_type, $content, $start_date, $end_date, $group_size_adults, $group_size_children, $b_units); } elseif (variable_get('rooms_presentation_style', ROOMS_PER_TYPE) == ROOMS_INDIVIDUAL) { $content = rooms_booking_manager_present_individual_rooms($units_per_type, $content, $start_date, $end_date); } } else { drupal_set_message(t('Perform a search to get availability information')); drupal_goto('booking'); exit; } $output = theme('rooms_booking_results', $content); return $output; } /** * Checks the logical validity of date values coming through URL * @param $start_date * The start date for the search * * @param $end_date * The end date for the search */ function rooms_booking_manager_check_dates($start_date, $end_date) { $datesok = TRUE; if ((gettype($start_date) == 'integer') || (gettype($end_date) == 'integer')) { return FALSE; } else { $now = new DateTime(); // Ensure start date is after today $diff1 = $now->diff($start_date); if ($diff1->invert) { $datesok = FALSE; } // Ensure end date is after start date $diff2 = $start_date->diff($end_date); // If date1 > date2 if ($diff2->invert) { $datesok = FALSE; } } return $datesok; } /** * Prepares rooms on a per room basis for presentation */ function rooms_booking_manager_present_individual_rooms($units_per_type, $content, $start_date, $end_date) { $content['style'] = ROOMS_INDIVIDUAL; foreach ($units_per_type as $type => $price_level) { $type_obj = rooms_unit_type_load($type); $content[$type] = array( '#prefix' => '

', '#markup' => t($type_obj->label), '#suffix' => '

' ); $currency_setting = commerce_currency_load(commerce_default_currency()); $currency_symbol = $currency_setting['symbol']; foreach ($price_level as $price => $units) { foreach ($units as $unit_id => $unit) { // Load the unit and render $unit_obj = rooms_unit_load($unit_id); $controller = entity_get_controller('rooms_unit'); $unit_content = $controller->view(array($unit_id => $unit_obj)); $content['units_per_type'][$type][$price][$unit_id]['unit'] = $unit_content; $content['units_per_type'][$type][$price][$unit_id]['price'] = array( '#prefix' => '
', '#markup' => t('Cost:') . ' ' . $unit['price'] . ' ' . $currency_symbol, '#suffix' => '
' ); // Add purchase forms - passing through hook_forms to handle multiple forms on the page $form = 'book_unit_form_' . $unit_id; $content['units_per_type'][$type][$price][$unit_id]['book_unit_form'] = drupal_get_form($form, $unit_obj, $start_date, $end_date, $unit['state']); } } } return $content; } /** * Prepares rooms on a per type basis */ function rooms_booking_manager_present_types($units_per_type, $content, $start_date, $end_date, $group_size, $group_size_children, $b_units) { // Flag used in tpl $content['style'] = ROOMS_PER_TYPE; // We build all the content as a form for now $content['units_per_type_form'] = drupal_get_form('book_units_per_type_form', $units_per_type, $start_date, $end_date, $group_size, $group_size_children, $b_units); return $content; } /** * Implementation of hook_forms() * * We use this to be able to present a different purhase button for each choice */ function rooms_booking_manager_forms($form_id, $args) { $forms = array(); if (0 !== strpos($form_id, 'book_unit_form_')) { return $forms; } $forms[$form_id] = array( 'callback' => 'book_unit_form_builder', ); return $forms; } /** * The form builder builds the form (where visible is simply the purchase button) * for individual bookable units. * * The builder gets called for each unit from the rooms_booking_manager_present_individual_rooms function above. * * The available units have already been identified by rooms_booking_manager_results_page. */ function book_unit_form_builder($form_id, $form_state, $unit, $start_date, $end_date, $status) { $form['unit_id'] = array( '#type' => 'hidden', '#value' => $unit->unit_id, ); $form['status'] = array( '#type' => 'hidden', '#value' => $status, ); $form['start_date'] = array( '#type' => 'hidden', '#value' => $start_date->format('Y-m-d'), ); $form['end_date'] = array( '#type' => 'hidden', '#value' => $end_date->format('Y-m-d'), ); // 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['#submit'])) { $submit += $form['#submit']; } $form['actions']['submit'] = array( '#type' => 'submit', '#value' => t('Book This Room'), '#submit' => $submit + array('book_unit_form_submit'), ); // We append the validate handler to #validate in case a form callback_wrapper // is used to add validate handlers earlier. $form['#validate'][] = 'book_unit_form_validate'; return $form; } /** * Validation for cart booking form * * @todo Evaluate what to do here */ function book_unit_form_validate(&$form, &$form_state) { } function book_unit_form_submit(&$form, &$form_state) { module_load_include('inc', 'rooms_booking_manager', 'rooms_booking_manager.commerce'); global $user; $unit_id = $form_state['values']['unit_id']; $start_date = $form_state['values']['start_date']; $end_date = $form_state['values']['end_date']; $status = $form_state['values']['status']; // This is very inefficient right now but we need to create date objects // reconvert them back to strings to only recreate them in the Availability Agent $sd = start_date_load($start_date); $ed = end_date_load($end_date); // Let us get the available rooms again and match the order against actual rooms $date_format = str_replace('-', '/', variable_get('rooms_date_format', 'd-m-Y')); $agent = new AvailabilityAgent($sd->format($date_format), $ed->format($date_format)); $agent->setValidStates(variable_get('rooms_valid_availability_states', array(ROOMS_AVAILABLE, ROOMS_ON_REQUEST))); // Let us make sure our bookable unit is still available $available_units = $agent->checkAvailabilityForUnit($unit_id); if (count($available_units) > 0) { $unit = array_pop($available_units); // Create line item $line_item = rooms_create_line_item($unit, $agent); // Add line item to cart $line_item = commerce_cart_product_add($user->uid, $line_item, FALSE); // Send user to cart drupal_goto('bookings'); } else { drupal_set_message(t('We apologize it seems the room is no longer available')); drupal_goto(''); } } function book_units_per_type_form($form, $form_state, $units_per_type, $start_date, $end_date, $group_size, $group_size_children, $b_units) { $date_format = variable_get('rooms_date_format', 'd-m-Y'); $nights = $end_date->diff($start_date); // Check to see if we are rebuilding the form to create an enquiry if (($form_state['rebuild']) && (variable_get('rooms_checkout_style', ROOMS_COMMERCE_CHECKOUT) == ROOMS_ENQ_CHECKOUT)) { $form = rooms_booking_manager_per_type_enquiry_form($form, $form_state, $units_per_type, $start_date, $end_date, $group_size, $group_size_children, $b_units); // If not display the per type choices } else { // 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['#submit'])) { $submit += $form['#submit']; } $form['start_date'] = array( '#type' => 'hidden', '#value' => $start_date->format('Y-m-d'), ); $form['end_date'] = array( '#type' => 'hidden', '#value' => $end_date->format('Y-m-d'), ); $form['group_size'] = array( '#type' => 'hidden', '#value' => $group_size, ); $form['group_size_children'] = array( '#type' => 'hidden', '#value' => $group_size_children, ); $form['b_units'] = array( '#type' => 'hidden', '#value' => $b_units, ); $form['legend1'] = array( '#prefix' => '', ); $form['legend2'] = array( '#prefix' => '', ); $form['legend3'] = array( '#prefix' => '
', '#markup' => 'Arrival Date: ' . $start_date->format($date_format) . '  Departure Date: ' . $end_date->format($date_format) . '  Nights: ' . $nights->d, '#suffix' => '
', '#markup' => 'N° Rooms', '#suffix' => '', '#markup' => 'Booking', '#suffix' => '
', ); drupal_add_js(drupal_get_path('module', 'rooms_booking_manager') . '/js/rooms_booking_manager_button_scroll.js'); drupal_add_css(drupal_get_path('module', 'rooms_booking_manager') . '/css/button_float.css'); $currency_setting = commerce_currency_load(commerce_default_currency()); $currency_symbol = $currency_setting['symbol']; $index = 0; foreach ($units_per_type as $type => $units_per_price) { // Load the type obj and set a title $type_obj = rooms_unit_type_load($type); $form[$type]['title'][$type . ':title'] = array( '#prefix' => '

', '#markup' => t($type_obj->label), '#suffix' => '

', ); foreach ($units_per_price as $price => $units) { $form[$type . ':' . $price][$type . ':' . $price . ':open-markup'] = array( '#markup' => '', ); // Check if a description source is loaded and if so render if ($type_obj->data['rooms_description_source'] != '') { $source_ref = explode(':', $type_obj->data['rooms_description_source']); $node_id = $source_ref[1]; if (module_exists('translation')) { $node_translations = translation_node_get_translations($node_id); if (!empty($node_translations)) { $node_id = $node_translations[$GLOBALS['language']->language]->nid; } } $node = node_load($node_id); $node_html = render(node_view($node,'rooms_list')); $form[$type . ':' . $price][$type . ':' . $price . ':description'] = array( '#prefix' => '', ); } // Element to display price $form[$type . ':' . $price][$type . ':' . $price . ':price'] = array( '#prefix' => '', ); // Dropdown to select quantity $options = array(); for ($i = 0; $i <= count($units); $i++) { $options[$i] = $i; } $form[$type . ':' . $price][$type . ':' . $price . ':quantity'] = array( '#prefix' => '', ); if ($index == 0) { $form[$type . ':' . $price]['submit'] = array( '#prefix' => '', ); $index++; } else { $form[$type . ':' . $price]['submit'] = array( '#prefix' => '', ); } $form[$type . ':' . $price][$type . ':' . $price . ':close-markup'] = array( '#markup' => '
', '#markup' => $node_html, '#suffix' => '
', '#markup' => t('Cost:') . ' ' . $units[key($units)]['price'] . ' ' . $currency_symbol, '#suffix' => '
' ); // Element to hold price $form[$type . ':' . $price][$type . ':' . $price . ':price_value'] = array( '#type' => 'hidden', '#value' => $units[key($units)]['price'], '#suffix' => '
', '#title' => t('Units'), '#type' => 'select', '#options' => $options, '#suffix' => '
', '#type' => 'submit', '#value' => t('Place Booking'), '#submit' => $submit + array('book_units_per_type_form_submit'), '#suffix' => '
', '#suffix' => '
', ); } } $form['submit'] = array( '#type' => 'submit', '#value' => t('Change search'), '#submit' => $submit + array('rooms_booking_manager_change_search'), ); $form['actions'] = array( '#type' => 'container', '#attributes' => array('class' => array('form-actions')), '#weight' => 400, ); // We append the validate handler to #validate in case a form callback_wrapper // is used to add validate handlers earlier. $form['#validate'][] = 'book_units_per_type_form_validate'; } return $form; } function rooms_booking_manager_per_type_enquiry_form($form, $form_state, $units_per_type, $start_date, $end_date, $group_size, $group_size_children, $b_units) { $form = $form_state['values']['form_data']; $date_format = variable_get('rooms_date_format', 'd-m-Y'); $nights = $end_date->diff($start_date); $form['legend1'] = array( '#markup' => 'Arrival Date: ' . $start_date->format($date_format).'  Departure Date: ' . $end_date->format($date_format) . '  Nights: ' . $nights->d, ); $currency_setting = commerce_currency_load(commerce_default_currency()); $currency_symbol = $currency_setting['symbol']; $form['enquiry_form'] = array( '#type' => 'hidden', '#value' => 'enquiry', ); $form['customer_name'] = array( '#title' => t('Name:'), '#type' => 'textfield', '#size' => 50, '#required' => TRUE, ); $form['customer_email'] = array( '#title' => t('Email:'), '#type' => 'textfield', '#size' => 50, ); $form['customer_add1'] = array( '#title' => t('Address Line 1:'), '#type' => 'textfield', '#size' => 80, ); $form['customer_add2'] = array( '#title' => t('Address Line 2:'), '#type' => 'textfield', '#size' => 80, ); $form['customer_city'] = array( '#title' => t('City:'), '#type' => 'textfield', '#size' => 60, ); $form['customer_state'] = array( '#title' => t('State/County:'), '#type' => 'textfield', '#size' => 60, ); $form['customer_country'] = array( '#title' => t('Country:'), '#type' => 'textfield', '#size' => 60, ); $form['comments'] = array( '#title' => t('Comments:'), '#type' => 'textarea', '#cols' => 50, '#resizable' => TRUE, '#rows' => 5, ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'), ); return $form; } function book_units_per_type_form_validate(&$form, &$form_state) { if (isset($form_state['complete form']['comments'])) return; if ($form_state['triggering_element']['#value'] == t('Change search')) return; foreach ($form_state['complete form'] as $key => $value) { if (isset($value['submit'])) { if (isset($value[$key . ':quantity']) && is_array($value)) { if ($value[$key . ':quantity']['#value'] != 0) { return; } } } } form_set_error('', t('Please select a unit in order to continue with booking')); } function room_booking_manager_send_email($form_state) { $email = variable_get('site_mail', ini_get('sendmail_from')); $module = 'rooms_booking_manager'; $key = 'booking'; $language = language_default(); $params = array(); $from = NULL; $send = FALSE; $message = drupal_mail($module, $key, $email, $language, $params, $from, $send); $message['subject'] = 'Booking'; $variables = array(); $booking_request = array(); foreach ($form_state['values'] as $value_key => $value) { $values = explode(':', $value_key); if (count($values) == 3) { $label = db_select('rooms_unit_type', 'n')->fields('n', array('label'))->condition('type', $values[0], '=')->execute()->fetchField(); $booking_request[] = '

' . $label . ' (' . $values[1] . ' - ' . $value[2] . ')

'; } } $variables['customer_name'] = t('Name:') . ' ' . $form_state['values']['customer_name']; $variables['customer_email'] = t('Email:') . ' ' . $form_state['values']['customer_email']; $variables['customer_add1'] = t('Address Line 1:') . ' ' . $form_state['values']['customer_add1']; $variables['customer_add2'] = t('Address Line 2:') . ' ' . $form_state['values']['customer_add2']; $variables['customer_city'] = t('City:') . ' ' . $form_state['values']['customer_city']; $variables['customer_state'] = t('State/County:') . ' ' . $form_state['values']['customer_state']; $variables['customer_country'] = t('Country:') . ' ' . $form_state['values']['customer_country']; $variables['comment'] = t('Comments:') . ' ' . $form_state['values']['comment']; $variables['booking_request'] = $booking_request; $message['body'] = array(theme('rooms_booking_email', $variables)); // Retrieve the responsible implementation for this message. $system = drupal_mail_system($module, $key); // Format the message body. $message = $system->format($message); // Send e-mail. $message['result'] = $system->mail($message); drupal_goto('enquiry-confirmation'); } /** *@todo - check that original availability still holds *@todo - fix the user ownership of products */ function book_units_per_type_form_submit(&$form, &$form_state) { if (isset($form_state['values']['enquiry_form'])) { room_booking_manager_send_email($form_state); } module_load_include('inc', 'rooms_booking_manager', 'rooms_booking_manager.commerce'); global $user; $start_date = $form_state['values']['start_date']; $end_date = $form_state['values']['end_date']; $group_size = $form_state['values']['group_size']; $group_size_children = $form_state['values']['group_size_children']; $b_units = $form_state['values']['b_units']; // Create an "order" based on the form submitted $order = array(); foreach($form_state['values'] as $value_key => $value) { $values = explode(':', $value_key); if (count($values) == 3) { list($type, $price_level, $value_type) = $values; $order[$type][$price_level][$value_type] = $value; } } $currency_setting = commerce_currency_load(commerce_default_currency()); $currency_symbol = $currency_setting['symbol']; // This is very inefficient right now but we need to create date objects // reconvert them back to strings to only recreate them in the Availability Agent $sd = start_date_load($start_date); $ed = end_date_load($end_date); // Let us get the available rooms again and match the order against actual rooms $date_format = str_replace('-', '/', variable_get('rooms_date_format', 'd-m-Y')); // We are going to check that this is still true - but let us try and service the order foreach ($order as $type => $price_serving) { foreach ($price_serving as $price_level => $unit_order) { if ($unit_order['quantity'] > 0) { for ($i = 1; $i <= $unit_order['quantity']; $i++) { $agent = new AvailabilityAgent($sd->format($date_format), $ed->format($date_format), $group_size, $group_size_children, $b_units, array(), array($type)); $agent->setValidStates(variable_get('rooms_valid_availability_states', array(ROOMS_AVAILABLE, ROOMS_ON_REQUEST))); $units_per_type = $agent->checkAvailability(); $available_units = $units_per_type[$type][$price_level]; $unit = array_pop($available_units); // If we are using Commerce create the line items and pop in cart if (variable_get('rooms_checkout_style', ROOMS_COMMERCE_CHECKOUT) == ROOMS_COMMERCE_CHECKOUT) { // Create line item $line_item = rooms_create_line_item($unit, $agent); // Add line item to cart if (!empty($line_item)) { $line_item = commerce_cart_product_add($user->uid, $line_item, FALSE); } // If we are doing a straight forward enquiry form add some form elements and rebuild form // this allows us to preserve state across page loads and avoid repeating code } elseif (variable_get('rooms_checkout_style', ROOMS_COMMERCE_CHECKOUT) == ROOMS_ENQ_CHECKOUT) { $type_obj = rooms_unit_type_load($type); $form_data[$type]['title'][$type . ':title'] = array( '#prefix' => '

', '#markup' => t($type_obj->label), '#suffix' => '

', ); $unit_info = $agent->checkAvailabilityForUnit($unit['unit']->unit_id); $unit_first = array_pop($unit_info); $price = $unit_first['price']; $form_data[$unit['unit']->type . ':' . $price][$i] = array( '#prefix' => '
', '#markup' => t('1 - Cost:') . ' ' . $price . ' ' . $currency_symbol, '#suffix' => '
' ); $form_data[$unit['unit']->type . ':adults:' . $i] = array( '#title' => 'Adults:', '#type' => 'textfield', '#size' => 3, ); $form_data[$unit['unit']->type . ':children:' . $i] = array( '#title' => 'Children:', '#type' => 'textfield', '#size' => 3, '#suffix' => '
' ); // We are storing the partially built form in form_data to use it // when rebuilding the results page with the enquiry form $form_state['values']['form_data'] = $form_data; } } } } } if (variable_get('rooms_checkout_style', ROOMS_COMMERCE_CHECKOUT) == ROOMS_COMMERCE_CHECKOUT) { // Send user to cart drupal_goto('bookings'); } elseif (variable_get('rooms_checkout_style', ROOMS_COMMERCE_CHECKOUT) == ROOMS_ENQ_CHECKOUT) { $form_state['rebuild'] = TRUE; } } /** * This function redirects the user back to the search box and sets up the values * of the search as a convenient way to modify the search. */ function rooms_booking_manager_change_search(&$form, &$form_state) { drupal_goto('booking', array('query' => array( 'start_date' => $form_state['values']['start_date'], 'end_date' => $form_state['values']['end_date'], 'group_size' => $form_state['values']['group_size'], 'group_size_children' => $form_state['values']['group_size_children'], 'b_units' => $form_state['values']['b_units'], ))); } /** * Implements hook_load() * * Expects to see a date in the form Y-m-d * * @returns a DateTime Object or null if invalid */ function start_date_load($start_date) { $start_date = check_plain($start_date); // Try to create a date time object try { $sd = new DateTime($start_date); } catch (Exception $e) { $sd = 0; } return $sd; } /** * Implements hook_load() * * Expects to see a date in the form Y-m-d * * @returns a DateTime Object or null if invalid */ function end_date_load($end_date) { $end_date = check_plain($end_date); // Try to create a date time object try { $ed = new DateTime($end_date); } catch (Exception $e) { $ed = 0; } return $ed; } /** * Implements hook_theme() */ function rooms_booking_manager_theme() { return array( 'rooms_booking_results' => array( 'template' => 'rooms_booking_results' ), 'rooms_booking_email' => array( 'template' => 'rooms_booking_email' ), 'rooms_booking_enquiry_confirmation' => array( 'template' => 'rooms_booking_enquiry_confirmation' ), ); } /** * Implements hook_commerce_checkout_complete */ function rooms_booking_manager_commerce_checkout_complete($order) { $profile = commerce_customer_profile_load($order->commerce_customer_billing['und'][0]['profile_id']); // Cycle through orders looking for booking products foreach ($order->commerce_line_items as $lang => $item) { foreach ($item as $item_id) { $line_item = commerce_line_item_load($item_id['line_item_id']); if ($line_item->type == 'rooms_booking') { // Create a booking $booking = rooms_booking_create(array('type' => 'standard_booking')); $booking->created = time(); $booking->start_date = $line_item->rooms_booking_dates['und'][0]['value']; // Associate it with this order $booking->order_id = $order->order_number; // End date is actually the checkout date so we need to add a day $booking_end_day = new DateTime($line_item->rooms_booking_dates['und'][0]['value2']); $booking_end_day->add(new DateInterval('P1D')); $booking->end_date = $booking_end_day->format('Y-m-d'); $booking->unit_id = $line_item->rooms_booked_unit_id['und'][0]['value']; // Load the unit to get its type $unit = rooms_unit_load($booking->unit_id); $booking->unit_type = $unit->type; $booking->customer_id = $order->commerce_customer_billing['und'][0]['profile_id']; $booking->name = $profile->commerce_customer_address['und'][0]['name_line']; $booking->booking_status = 1; $booking->save(); // Now let us lock availability // First - we get an event id $id = rooms_availability_assign_id($booking->booking_id, '1'); // Set the start and end dates for the booking event // They are the same as the booking above but the end date is not the departure date // rather it is the last night spend in the room $sd = new DateTime($booking->start_date); // End date is actually a day less $booking_end_day->sub(new DateInterval('P1D')); $ed = $booking_end_day; // Create a booking event $be = new BookingEvent($booking->unit_id, $id, $sd, $ed); // Call up the UnitCalednar for this booking unit and add the booking event to it $rc = new UnitCalendar($booking->unit_id); $responses = $rc->updateCalendar(array($be)); // If the event addition was succesful lock the event if ($responses[$id] == ROOMS_UPDATED) { $be->lock(); drupal_set_message(t('Room Availability Updated')); } else { drupal_set_message(t('Room Availability could not be updated')); } } } } } function rooms_booking_manager_commerce_order_state_info() { $order_states = array(); $order_states['rooms_unit_booking'] = array( 'name' => 'rooms_unit_booking', 'title' => t('Rooms Booking'), 'description' => t('Orders related to Rooms bookings'), 'weight' => 0, 'default_status' => 'confirmed', ); return $order_states; } function rooms_booking_manager_commerce_order_status_info() { $order_statuses = array(); $order_statuses['rooms_unit_confirmed'] = array( 'name' => 'rooms_unit_confirmed', 'title' => t('Booking Confirmed'), 'state' => 'rooms_unit_booking', ); $order_statuses['rooms_unit_canceled'] = array( 'name' => 'rooms_unit_canceled', 'title' => t('Booking Canceled'), 'state' => 'rooms_unit_booking', ); $order_statuses['rooms_unit_pending'] = array( 'name' => 'rooms_unit_pending', 'title' => t('Booking Pending'), 'state' => 'rooms_unit_booking', ); return $order_statuses; } /** * */ function _rooms_booking_manager_line_item_type_fields() { $field_data = array( 'fields' => array( 'rooms_booking_dates' => array( 'field_name' => 'rooms_booking_dates', 'label' => t('Booking Dates'), 'cardinality' => 1, 'type' => 'date', 'module' => 'date', 'active' => '1', 'locked' => '1', 'settings' => array( 'repeat' => 0, 'todate' => 'required', 'granularity' => array( 'year' => 'year', 'month' => 'month', 'day' => 'day', ), 'tz_handling' => 'none', 'timezone_db' => '', ), ), 'rooms_booked_unit_id' => array( 'field_name' => 'rooms_booked_unit_id', 'label' => t('Booked Unit ID'), 'cardinality' => 1, 'type' => 'number_integer', 'module' => 'number', 'active' => 1, 'locked' => 1, 'settings' => array( 'size' => 8, 'max_length' => 10, 'text_processing' => 0, ), ), 'rooms_booked_status' => array( 'field_name' => 'rooms_booked_status', 'label' => t('Booked Unit Status'), 'cardinality' => 1, 'type' => 'number_integer', 'module' => 'number', 'active' => 1, 'locked' => 1, 'settings' => array( 'size' => 8, 'max_length' => 10, 'text_processing' => 0, ), ), 'rooms_booked_price' => array( 'field_name' => 'rooms_booked_price', 'label' => t('Booked Unit Price'), 'cardinality' => 1, 'type' => 'number_integer', 'module' => 'number', 'active' => 1, 'locked' => 1, 'settings' => array( 'size' => 8, 'max_length' => 10, 'text_processing' => 0, ), ), 'rooms_booked_bookingprice' => array( 'field_name' => 'rooms_booked_bookingprice', 'label' => t('Booking Price'), 'cardinality' => 1, 'type' => 'number_integer', 'module' => 'number', 'active' => 1, 'locked' => 1, 'settings' => array( 'size' => 8, 'max_length' => 10, 'text_processing' => 0, ), ), 'rooms_booking_number_people' => array( 'field_name' => 'rooms_booking_number_people', 'label' => t('Booking Number People'), 'cardinality' => 2, 'type' => 'number_integer', 'module' => 'number', 'active' => 1, 'locked' => 1, 'settings' => array( 'size' => 8, 'max_length' => 10, 'text_processing' => 0, ), ), 'commerce_display_path' => array( 'field_name' => 'commerce_display_path', 'type' => 'text', 'cardinality' => 1, 'entity_types' => array('commerce_line_item'), 'translatable' => FALSE, 'locked' => TRUE, ), ), 'instances' => array( 'rooms_booking_dates' => array( 'field_name' => 'rooms_booking_dates', 'label' => t('Booking Dates'), 'entity_type' => 'commerce_line_item', 'bundle' => 'rooms_booking', 'required' => FALSE, 'widget' => array( 'type' => 'date_popup', 'module' => 'date', 'settings' => array( 'default_value' => 'now', 'default_format' => 'medium', ), ), ), 'rooms_booked_unit_id' => array( 'field_name' => 'rooms_booked_unit_id', 'label' => t('Booked Unit ID'), 'entity_type' => 'commerce_line_item', 'bundle' => 'rooms_booking', 'required' => TRUE, 'settings' => array( 'size' => 8, 'max_length' => 10, 'text_processing' => 0, ), 'widget' => array( 'type' => 'text_textfield', ), 'display' => array( 'default' => array( 'label' => 'above', 'module' => 'number', 'settings' => array( 'decimal_separator' => '.', 'prefix_suffix' => TRUE, 'scale' => 0, 'thousand_separator' => ' ', ), 'type' => 'number_integer', 'weight' => 11, ), 'teaser' => array( 'label' => 'above', 'settings' => array(), 'type' => 'hidden', 'weight' => 0, ), ), ), 'rooms_booked_status' => array( 'field_name' => 'rooms_booked_status', 'label' => t('Booked Unit Status'), 'entity_type' => 'commerce_line_item', 'bundle' => 'rooms_booking', 'required' => TRUE, 'settings' => array( 'size' => 8, 'max_length' => 10, 'text_processing' => 0, ), 'widget' => array( 'type' => 'text_textfield', ), 'display' => array( 'default' => array( 'label' => 'above', 'module' => 'number', 'settings' => array( 'decimal_separator' => '.', 'prefix_suffix' => TRUE, 'scale' => 0, 'thousand_separator' => ' ', ), 'type' => 'number_integer', 'weight' => 11, ), 'teaser' => array( 'label' => 'above', 'settings' => array(), 'type' => 'hidden', 'weight' => 0, ), ), ), 'rooms_booked_price' => array( 'field_name' => 'rooms_booked_price', 'label' => t('Booked Unit Price'), 'entity_type' => 'commerce_line_item', 'bundle' => 'rooms_booking', 'required' => TRUE, 'settings' => array( 'size' => 8, 'max_length' => 10, 'text_processing' => 0, ), 'widget' => array( 'type' => 'text_textfield', ), 'display' => array( 'default' => array( 'label' => 'above', 'module' => 'number', 'settings' => array( 'decimal_separator' => '.', 'prefix_suffix' => TRUE, 'scale' => 0, 'thousand_separator' => ' ', ), 'type' => 'number_integer', 'weight' => 11, ), 'teaser' => array( 'label' => 'above', 'settings' => array(), 'type' => 'hidden', 'weight' => 0, ), ), ), 'rooms_booked_bookingprice' => array( 'field_name' => 'rooms_booked_bookingprice', 'label' => t('Booking Price'), 'entity_type' => 'commerce_line_item', 'bundle' => 'rooms_booking', 'required' => TRUE, 'settings' => array( 'size' => 8, 'max_length' => 10, 'text_processing' => 0, ), 'widget' => array( 'type' => 'text_textfield', ), 'display' => array( 'default' => array( 'label' => 'above', 'module' => 'number', 'settings' => array( 'decimal_separator' => '.', 'prefix_suffix' => TRUE, 'scale' => 0, 'thousand_separator' => ' ', ), 'type' => 'number_integer', 'weight' => 11, ), 'teaser' => array( 'label' => 'above', 'settings' => array(), 'type' => 'hidden', 'weight' => 0, ), ), ), 'rooms_booking_number_people' => array( 'field_name' => 'rooms_booking_number_people', 'label' => t('Booking Number People'), 'entity_type' => 'commerce_line_item', 'bundle' => 'rooms_booking', 'required' => TRUE, 'settings' => array( 'size' => 8, 'max_length' => 10, 'text_processing' => 0, ), 'widget' => array( 'type' => 'text_textfield', ), 'display' => array( 'default' => array( 'label' => 'above', 'module' => 'number', 'settings' => array( 'decimal_separator' => '.', 'prefix_suffix' => TRUE, 'scale' => 0, 'thousand_separator' => ' ', ), 'type' => 'number_integer', 'weight' => 11, ), 'teaser' => array( 'label' => 'above', 'settings' => array(), 'type' => 'hidden', 'weight' => 0, ), ), ), 'commerce_display_path' => array( 'field_name' => 'commerce_display_path', 'entity_type' => 'commerce_line_item', 'bundle' => 'rooms_booking', 'label' => t('Display path'), 'required' => TRUE, 'settings' => array(), 'widget' => array( 'type' => 'text_textfield', 'weight' => 0, ), 'display' => array( 'display' => array( 'label' => 'hidden', 'weight' => 0, ), ), ), ), ); return $field_data; } /** * Implementation of hook_form_alter() */ function rooms_booking_manager_form_alter(&$form, &$form_state, $form_id) { // Commerce checkout form alters if ($form_id == 'commerce_checkout_form_checkout') { // Extract the View and display keys from the cart contents pane setting. list($view_id, $display_id) = explode('|', variable_get('commerce_cart_contents_pane_view', 'commerce_cart_summary|default')); global $user; $order = commerce_cart_order_load($user->uid); $form['cart_contents']['cart_contents_view'] = array( '#markup' => commerce_embed_view('booking_checkout_form', 'booking_checkout_form', array($order->order_id)), ); } // Commerce cart view for booking form alters if (strpos($form_id, 'views_form_booking_cart_form_') === 0) { unset($form['actions']['submit']); $form['#action'] = str_replace('cart', 'bookings', $form['#action']); // Change any Delete buttons to say Remove. if (!empty($form['edit_delete'])) { foreach(element_children($form['edit_delete']) as $key) { // Load and wrap the line item to have the title in the submit phase. if (!empty($form['edit_delete'][$key]['#line_item_id'])) { $line_item_id = $form['edit_delete'][$key]['#line_item_id']; $form_state['line_items'][$line_item_id] = commerce_line_item_load($line_item_id); $form['edit_delete'][$key]['#value'] = t('Remove'); $form['edit_delete'][$key]['#submit'] = array_merge($form['#submit'], array('commerce_cart_line_item_delete_form_submit')); } } } $form['actions']['checkout'] = array( '#type' => 'submit', '#value' => t('Checkout'), '#weight' => 5, '#access' => user_access('access checkout'), '#submit' => array_merge($form['#submit'], array('commerce_checkout_line_item_views_form_submit')), ); } elseif (strpos($form_id, 'commerce_checkout_form_') === 0 && !empty($form['buttons']['cancel'])) { // Override the submit handler for changing the order status on checkout cancel. foreach ($form['buttons']['cancel']['#submit'] as $key => &$value) { if ($value == 'commerce_checkout_form_cancel_submit') { $value = 'commerce_cart_checkout_form_cancel_submit'; } } } elseif (strpos($form_id, 'views_form_commerce_cart_block') === 0) { // No point in having a "Save" button on the shopping cart block. unset($form['actions']); } // Adding extra settings to rooms booking settings if ($form_id == 'rooms_booking_settings') { $form['rooms_presentation_style'] = array( '#type' => 'radios', '#title' => t('Results presentation style'), '#options' => array( ROOMS_PER_TYPE => t('Show availability on a per-type basis.'), ROOMS_INDIVIDUAL => t('Show availability of individual units.'), ), '#default_value' => variable_get('rooms_presentation_style', ROOMS_PER_TYPE), ); $form['rooms_checkout_style'] = array( '#type' => 'radios', '#title' => t('Checkout presentation style'), '#options' => array( ROOMS_ENQ_CHECKOUT => t('Enquiry checkout'), ROOMS_COMMERCE_CHECKOUT => t('Commerce checkout'), ), '#default_value' => variable_get('rooms_checkout_style', ROOMS_COMMERCE_CHECKOUT), ); $form['rooms_valid_availability_states'] = array( '#type' => 'checkboxes', '#title' => t('Valid availability states'), '#description' => t('Select the states for which rooms should show as available in a search.'), '#options' => array( ROOMS_AVAILABLE => t('Rooms marked as available.'), ROOMS_ON_REQUEST => t('Rooms marked as available on request.'), ), '#default_value' => variable_get('rooms_valid_availability_states', array(ROOMS_AVAILABLE, ROOMS_ON_REQUEST)), ); $form['rooms_payment_options'] = array( '#type' => 'item', '#title' => t('Payment options'), '#description' => t('Select payment option for booking confirmation.'), ); $form['rooms_payment_options'][FULL_PAYMENT] = array( '#type' => 'radio', '#title' => t('Full price'), '#return_value' => FULL_PAYMENT, '#parents' => array('rooms_payment_options'), '#default_value' => variable_get('rooms_payment_options', FULL_PAYMENT), ); $form['rooms_payment_options'][PERCENT_PAYMENT] = array( '#prefix' => '
', ); $form['rooms_payment_options'][PERCENT_PAYMENT]['perc_option'] = array( '#type' => 'radio', '#title' => t('Percentage of full price: '), '#return_value' => PERCENT_PAYMENT, '#parents' => array('rooms_payment_options'), '#default_value' => variable_get('rooms_payment_options', FULL_PAYMENT), ); $form['rooms_payment_options'][PERCENT_PAYMENT]['perc_textfield'] = array( '#type' => 'textfield', '#size' => 10, '#suffix' => '
', '#default_value' => variable_get('rooms_payment_options_percentual'), ); $form['rooms_payment_options'][FIRST_NIGHT_PAYMENT] = array( '#type' => 'radio', '#title' => t('First night'), '#return_value' => FIRST_NIGHT_PAYMENT, '#parents' => array('rooms_payment_options'), '#default_value' => variable_get('rooms_payment_options', FULL_PAYMENT), ); drupal_add_js(drupal_get_path('module', 'rooms_booking_manager') . '/js/rooms_booking_manager_checked.js'); $form['rooms_date_format'] = array( '#type' => 'item', '#title' => t('Rooms PHP Date Format'), ); $form['rooms_date_format']['date_format'] = array( '#type' => 'textfield', '#size' => 12, '#prefix' => '
Date format:  ', '#suffix' => '
', '#default_value' => variable_get('rooms_date_format', 'd-m-Y'), ); $form['#submit'][] = 'rooms_booking_manager_settings_form_submit'; } } function rooms_booking_manager_settings_form_submit($form, &$form_state) { if($form_state['values']['rooms_payment_options'] == PERCENT_PAYMENT) { variable_set('rooms_payment_options_percentual', $form_state['values']['perc_textfield']); } else { variable_set('rooms_payment_options_percentual', ''); } variable_set('rooms_date_format', $form_state['values']['date_format']); } /** * Implements Rules to set Order Status */ function rooms_booking_manager_rules_action_info() { $actions = array(); $actions['rooms_booking_cancel_order'] = array( 'label' => t('Cancel the booking related to an order'), 'parameter' => array( 'commerce_order' => array( 'type' => 'commerce_order', 'label' => t('Order to extract info from for booking cancellation'), ), ), 'group' => t('Rooms'), 'callbacks' => array( 'execute' => 'rooms_booking_cancel_order_booking', ), ); $actions['rooms_booking_manager_price_apply'] = array( 'label' => t('Apply price to a Rooms line item'), 'parameter' => array( 'commerce_line_item' => array( 'type' => 'commerce_line_item', 'label' => t('Line item'), ), ), 'group' => t('Rooms'), 'callbacks' => array( 'execute' => 'rooms_booking_manager_price_apply', ), ); return $actions; } function rooms_booking_cancel_order_booking() { } function rooms_booking_manager_price_apply($line_item, $name) { if ($line_item->type == 'rooms_booking') { $amount = $line_item->commerce_unit_price[LANGUAGE_NONE][0]['amount']; $start_date = new DateTime($line_item->rooms_booking_dates[LANGUAGE_NONE][0]['value']); $end_date = new DateTime($line_item->rooms_booking_dates[LANGUAGE_NONE][0]['value2']); $unit_id = $line_item->rooms_booked_unit_id[LANGUAGE_NONE][0]['value']; $unit = rooms_unit_load($unit_id); // First set up price modifiers $price_modifiers = array(); if ($line_item->rooms_booking_number_people[LANGUAGE_NONE][0]['value'] == 1) { $price_modifiers['single'] = array('#type' => ROOMS_PRICE_SINGLE_OCCUPANCY); } if ($line_item->rooms_booking_number_people[LANGUAGE_NONE][0]['value'] > 0) { $price_modifiers['children'] = array( '#type' => ROOMS_DYNAMIC_MODIFIER, '#op_type' => ROOMS_ADD, '#amount' => $unit->cot_surcharge * ($start_date->diff($end_date)->days + 1), ); } // Give other modules a chance to change the price modifiers drupal_alter('rooms_price_modifier', $price_modifiers); $price_calendar = new UnitPricingCalendar($unit->unit_id, $price_modifiers); $price = $price_calendar->calculatePrice($start_date, $end_date); $full_price = $price['full_price'] * 100; $line_item->commerce_unit_price[LANGUAGE_NONE][0]['amount'] = $full_price; $line_item->commerce_unit_price[LANGUAGE_NONE][0]['currency_code'] = commerce_default_currency(); foreach ($line_item->commerce_unit_price[LANGUAGE_NONE][0]['data']['components'] as $key => $component) { $line_item->commerce_unit_price[LANGUAGE_NONE][0]['data']['components'][$key]['price']['amount'] = $full_price / $amount * $component['price']['amount']; } } } /** * Implements hook_default_rules_configuration(). */ function rooms_booking_manager_default_rules_configuration() { $rules = array(); $rule = rules_reaction_rule(); $rule->label = 'Rooms'; $rule->active = TRUE; $rule->weight = -100; $rule ->event('commerce_product_calculate_sell_price') ->action('rooms_booking_manager_price_apply', array( 'commerce_line_item:select' => 'commerce-line-item', )); $rules['rooms'] = $rule; return $rules; } /** * Implements hook_block_info() */ function rooms_booking_manager_block_info() { $blocks = array(); $blocks['rooms_availability_search'] = array( 'info' => t('Rooms Availability Search'), 'cache' => DRUPAL_NO_CACHE, ); return $blocks; } /** * Implements hook_block_view() */ function rooms_booking_manager_block_view($block_name = '') { if ($block_name == 'rooms_availability_search') { $block = array( 'subject' => t('Availability Search'), 'content' => drupal_get_form('rooms_booking_availability_search_form'), ); return $block; } } /** * Implements hook_commerce_line_item_type_info(). */ function rooms_booking_manager_commerce_line_item_type_info() { return array( 'rooms_booking' => array( 'name' => t('Rooms Booking'), 'description' => t('Represents a booking of a Rooms product.'), 'product' => TRUE, 'add_form_submit_value' => t('Add product'), 'base' => 'rooms_booking_manager_line_item', ), ); } /** * Ensures the booking line item type contains a product reference field and * all other rooms fields required for a booking. */ function rooms_booking_manager_line_item_configuration($line_item_type) { $type = $line_item_type['type']; // Get the info about the fields and instances we need to create $field_data = _rooms_booking_manager_line_item_type_fields(); // Create the product reference field for the line item type. commerce_product_reference_create_instance('commerce_product', 'commerce_line_item', $type, t('Product')); // For each field, check whether it already exists create it if it doesn't foreach ($field_data['fields'] as $field_name => $field_info) { $field = field_info_field($field_name); $instance = field_info_instance('commerce_line_item', $field_name, $type); if (empty($field)) { field_create_field($field_data['fields'][$field_name]); } if (empty($instance)) { field_create_instance($field_data['instances'][$field_name]); } } } /** * Implements hook_line_item_title() * Returns the title of a line item based on its type. * * @param $line_item * The line item object whose title should be returned. * * @return * The type-dependent title of the line item. */ function rooms_booking_manager_line_item_title($line_item) { // Use the line item's label for the title. return ($line_item->line_item_label); } /** * Implements hook_commerce_product_type_info(). */ function rooms_booking_manager_commerce_product_type_info() { return array( 'rooms_product' => array( 'type' => 'rooms_product', 'name' => t('Rooms product'), 'description' => t('Products bookable with Rooms.'), 'revision' => '1', ), ); } /** * Implements hook_enable(). * * Creates a product that can be referenced from line items. */ function rooms_booking_manager_enable() { // Reset product types cache to have our rooms_product available commerce_product_types_reset(); $types = commerce_product_types(); if (isset($types['rooms_product']) && !empty($types['rooms_product'])) { $previous_product_id = variable_get('rooms_booking_manager_booking_product_id', 0); if (!($previous_product_id && commerce_product_load($previous_product_id))) { $product = commerce_product_new('rooms_product'); $product->sku = 'ROOMS-BASIC-BOOKING'; $product->title = t('Rooms Basic Booking'); // We will change the price later, but for now set the price to 100 (=$1) // to give tax module something to work with $product->commerce_price[LANGUAGE_NONE][0]['amount'] = 100; $product->commerce_price[LANGUAGE_NONE][0]['currency_code'] = commerce_default_currency(); commerce_product_save($product); variable_set('rooms_booking_manager_booking_product_id', $product->product_id); } } else { drupal_set_message(t('There was an error creating the rooms product to handle bookings.')); } } /** * Implements hook_views_api(). */ function rooms_booking_manager_views_api() { return array( 'api' => 3, 'path' => drupal_get_path('module', 'rooms_booking_manager') . '/views', ); }