$email)); return false; } //now check the domain exists if (preg_match('/^(.*?)\@(.*)/', $email, $matches)) { //watchdog('booking', 'Email address checking: @info', array('@info' => var_export($matches, TRUE))); if (! checkdnsrr($matches[2], "MX")) { watchdog('booking', "No valid MX record found for email address '!email' with domain name !domain", array('!email' => $email, '!domain' => $matches[2])); return false; } return true; } watchdog('booking', "Regular expression failed to detect domain portion of email address '!email'", array('!email' => $email)); //watchdog('booking', 'Email address checking doesnt match'); return false; } /** * Helper function to perform some validity checking of Medicare Numbers * Based on http://dyball.wordpress.com/2007/12/05/validation-of-medicare-numbers/ */ function _valid_medicare_number($input) { //strip any whitespace $medicare = preg_replace( '/\s+/', '', $input ); if (is_numeric($medicare) && strlen($medicare) >= 9 && $medicare > 0) { $check_digit = $medicare[0] + (3 * $medicare[1]) + (7 * $medicare[2]) + (9 * $medicare[3]) + $medicare[4] + (3 * $medicare[5]) + (7 * $medicare[6]) + (9 * $medicare[7]); if (($check_digit % 10) == $medicare[8]) { watchdog('booking', 'Medicare number (!mca) validates since check digit !check matches remainder from !remainder', array('!mca' => $input, '!check' => $medicare[8], '!remainder' => $check_digit)); return TRUE; } else { watchdog('booking', 'Medicare number (!mca) does not validate since check digit !check does not match remainder from !remainder', array('!mca' => $input, '!check' => $medicare[8], '!remainder' => $check_digit)); return FALSE; } } else { watchdog('booking', 'Medicare number (!mca) does not validate since it is either non-numeric or too short', array('!mca' => $input)); return FALSE; } } /** * Helper function to perform some validity checking of a passport number * Based on http://dyball.wordpress.com/2007/04/12/validation-of-passport-numbers/ * @param $input string containing passport number to be verified * @return boolean indicating if passport number is valid */ function _valid_passport_number($input) { //strip whitespace $passport = preg_replace( '/\s+/', '', $input ); //check for a match if (preg_match('/^[a-zA-Z]{1,2}\d{7}$/', $input, $matches)) { watchdog('booking', 'Passport number "!passnum" validates since it passed our regexp', array('!passnum' => $input)); return TRUE; } watchdog('booking', 'Passport number "!passnum" fails to validate', array('!passnum' => $input)); return FALSE; } function _valid_phone_number($input) { //strip any whitespace $number = preg_replace( '/\s+/', '', $input ); //strip any non-numeric characters $number = preg_replace('/\D+/','', $number); if (is_numeric($number)) return TRUE; else return FALSE; } function _valid_australian_mobile_number($input) { if (preg_match('/^\s*(?:\+61|61|0061|0)(\d{3})\s*(\d{3})\s*(\d{3})\s*$/', $input, $matches)) { //watchdog('booking', 'Australian Mobile Number "!passnum" validates since it passed our regexp', array('!passnum' => $input)); return TRUE; } else return FALSE; } /** * Helper function to check whether the number of registrations for the current event have reached their defined maximum size */ function _booking_check_bookings_full() { global $event; $waitinglist_query = db_query("SELECT count(*) as num_ppl FROM {booking_person} where booking_eventid = :eventid and booking_status = 1", array(':eventid' => $event->eid)) ->fetchObject(); //check the number of people registered against the defined max if ($waitinglist_query->num_ppl >= variable_get('booking_regn_limit', 350)) { //watchdog('booking', 'There are !num people booked in, which is greater than or equal to the limit of !limit.', // array('!num' => $waitinglist_query->num_ppl, '!limit' => variable_get('booking_regn_limit', 350) )); return true; } else { //watchdog('booking', 'There are !num people booked in, which is less than the limit of !limit.', // array('!num' => $waitinglist_query->num_ppl, '!limit' => variable_get('booking_regn_limit', 350) )); return false; } } /** * Helper function to check who is the first person on the waiting list */ function _booking_get_waitinglist_top() { global $event; $result = db_query('SELECT p.nid, p.booking_firstname, p.booking_lastname, pay.booking_payment_date FROM {booking_person} p, {booking_payment} pay WHERE booking_status = 2 and p.booking_eventid = :eid and p.nid = pay.booking_person_nid ORDER BY pay.booking_payment_date LIMIT 1', array(':eid' => $event->eid)); foreach ($result as $person) { watchdog('booking', "First person on the waiting list: @info", array('@info' => var_export($person, TRUE))); return $person->nid; } //in case there's no people with status waiting list, but there is some with missed payment deadline $result = db_query('SELECT p.nid, p.booking_firstname, p.booking_lastname, pay.booking_payment_date FROM {booking_person} p, {booking_payment} pay WHERE booking_status = 4 and p.booking_eventid = :eid and p.nid = pay.booking_person_nid ORDER BY pay.booking_payment_date LIMIT 1', array(':eid' => $event->eid)); foreach ($result as $person) { watchdog('booking', "First person on the missed-payment-deadline list: @info", array('@info' => var_export($person, TRUE))); return $person->nid; } //in case there was no one on the waiting list return -1; } /** * Helper function to update the status of a registration */ function _booking_change_status($nid, $status_id) { db_update('booking_person') ->fields(array( 'booking_status' => $status_id, )) ->condition('nid', $nid) ->execute(); } function _datearray_to_ts($date) { //watchdog('booking', 'Date Conversion: @info', array('@info' => var_export($date, TRUE))); date_default_timezone_set(date_default_timezone(FALSE)); $tz = new DateTimeZone(date_default_timezone(FALSE)); if (empty($date) || ($date['month'] == '' && $date['day'] == '' && $date['year'] == '')) { return 0; } //else // watchdog('booking', "Date array to timestamp: @info", array('@info' => var_export($date, TRUE))); $gmt_ts = mktime(0, 0, 0, $date['month'], $date['day'], $date['year']); $ts = new DateTime("@$gmt_ts"); $ts->setTimezone($tz); return $ts->format("U"); } function _datetime_array_to_ts($date) { //watchdog('booking', 'Date-time Conversion: @info', array('@info' => var_export($date, TRUE))); //watchdog('booking', "Date time conversion timezone configured as: @info", array('@info' => date_default_timezone(FALSE))); date_default_timezone_set(date_default_timezone(FALSE)); $tz = new DateTimeZone(date_default_timezone(FALSE)); if (empty($date) || ($date['month'] == '' && $date['day'] == '' && $date['year'] == '')) { return 0; } //else // watchdog('booking', "Date array to timestamp: @info", array('@info' => var_export($date, TRUE))); $gmt_ts = mktime($date['hour'], $date['minute'], 0, $date['month'], $date['day'], $date['year']); $ts = new DateTime("@$gmt_ts"); $ts->setTimezone($tz); //watchdog('booking', '
Date-time Conversion: @info 
', array('@info' => print_r( $ts, true))); return $ts->format("U"); } function _date_to_ts($date) { $date_split = _booking_split_date($date); date_default_timezone_set(date_default_timezone(FALSE)); $tz = new DateTimeZone(date_default_timezone(FALSE)); if ($date_split[0] == '-1' ) { return 0; } $gmt_ts = mktime(0, 0, 0, $date_split[2], $date_split[3], $date_split[1]); $ts = new DateTime("@$gmt_ts"); $ts->setTimezone($tz); return $ts->format("U"); //return mktime($date_split[5], $date_split[6], 0, $date_split[2], $date_split[3], $date_split[1]); } function _datetime_to_ts($date) { $date_split = _booking_split_date($date); date_default_timezone_set(date_default_timezone(FALSE)); $tz = new DateTimeZone(date_default_timezone(FALSE)); if ($date_split[0] == '-1' ) return 0; $gmt_ts = mktime($date_split[5], $date_split[6], 0, $date_split[2], $date_split[3], $date_split[1]); $ts = new DateTime("@$gmt_ts"); $ts->setTimezone($tz); return $ts->format("U"); //return mktime($date_split[5], $date_split[6], 0, $date_split[2], $date_split[3], $date_split[1]); } /** * Function to turn a loosely formatted date into a timestamp, with optional time * * @param $date in format DD/MM/YYYY HH:mm or just DD/MM/YYYY * @return unix timestamp formatted for current time zone */ function _datetime_to_ts_nonstrict($date) { $pattern = '/^(\d{1,2})\/(\d{1,2})\/(\d{4})(\s+(\d{1,2})\:(\d{1,2}))?/'; //check for a match if (preg_match($pattern, $date, $matches)) { //$date_split = $matches; $hour = isset($matches[5]) ? $matches[5] : 0; $minute = isset($matches[6]) ? $matches[6] : 0; $second = 0; $month = $matches[2]; $day = $matches[1]; $year = $matches[3]; } //return zero now if no matches else { return 0; } date_default_timezone_set(date_default_timezone(FALSE)); $tz = new DateTimeZone(date_default_timezone(FALSE)); //$gmt_ts = mktime($date_split[5], $date_split[6], 0, $date_split[2], $date_split[1], $date_split[3]); $gmt_ts = mktime($hour, $minute, $second, $month, $day, $year); $ts = new DateTime("@$gmt_ts"); $ts->setTimezone($tz); return $ts->format("U"); } /** * Function to split date into array * * @param $date in format YYYY-MM-DD * @return array containing Year, Month, Day */ function _booking_split_date($date) { $pattern = '/^(\d{4})-(\d{2})-(\d{2})(\s(\d{2})\:(\d{2}))?/'; if (preg_match($pattern, $date, $matches)) { return $matches; } else { return array('-1'); } } /** * Function to re-arrange date * * @param $date in format YYYY-MM-DD * @return array containing Year, Month, Day */ function _arrange_date($date) { $pattern = '/^(\d{4})-(\d{2})-(\d{2})/'; if (preg_match($pattern, $date, $matches)) { return $matches; } else { return array('-1'); } } /** * Helper function to ensure timestamp is converted to correct local time */ function _booking_convert_ts($timestamp) { //load the timestamp date_default_timezone_set(date_default_timezone(FALSE)); $tz = new DateTimeZone(date_default_timezone(FALSE)); $date = new DateTime("@$timestamp"); $date->setTimezone($tz); return $date; } /** * Helper function to calculate the timestamp corresponding with the DOB requirements */ function _booking_max_dob_ts() { //calculate DOB limit as defined by configuration $max_dob_matches = _booking_split_date(variable_get('booking_max_dob','0')); return mktime(12, 0, 0, $max_dob_matches[2], $max_dob_matches[3], $max_dob_matches[1]); } /** * Helper function to calculate the year offset between the start of event and a * * @param $datetime Date to compare from date_select field * @return integer containing difference in years */ function _booking_year_offset($datetime) { global $event; //set the time zone date_default_timezone_set(date_default_timezone(FALSE)); $tz = new DateTimeZone(date_default_timezone(FALSE)); //try to load the date try { //$date = new DateTime(variable_get('booking_min_dob','1970-01-01 00:00:00')); $date = new DateTime($datetime); } catch (Exception $e) { $date = new DateTime('1970-01-01 00:00:00'); } //set the timezone for the date $date->setTimezone($tz); //watchdog('booking', '
DateTime of minimum DOB:\n @info 
', array('@info' => print_r( $date, true))); $reference_date = _booking_convert_ts($event->booking_event_start); $difference = $date->diff($reference_date); //watchdog('booking', '
DateTime of difference in minimum DOB to start of event:\n @info 
', array('@info' => print_r( $difference, true))); return $difference->y; } /** * Helper function to calculate the average age in days, months and years at the start of the event */ function _booking_avg_age($sum, $count, $reference_ts) { //handle condition where count is zero if ($count == 0) { return "Zero"; } global $event; //calculate the average age timestamp $average = $sum / $count; //get the difference between now and the average timestamp $average_date = _booking_convert_ts(floor($average)); $now_date = _booking_convert_ts(floor($reference_ts)); $difference = $average_date->diff($now_date); //convert the difference into english return $difference->y . " years, " . $difference->m . " months, " . $difference->d . " days"; } /** * Helper function to calculate persons age in years at start of event */ function _booking_get_age_years($dob_ts) { global $event; $reference_ts = _booking_convert_ts($event->booking_event_start); $dob = _booking_convert_ts($dob_ts); return $dob->diff($reference_ts)->y; } /** * Helper function to create a string describing a date range */ function _date_range_to_string($date_start, $date_end) { $start = _booking_split_date($date_start); $end = _booking_split_date($date_end); $final_string = ''; //check for correctly formatted dates if ($start[0] == '-1' || $end[0] == '-1') { //incorrect response form_set_error('yc_date_endbeforestart', t('Invalid date format received from !date or !date_end.', array('!date' => $date_start, '!date_end' => $date_end))); } else { //start with the day field //mktime uses format month, day, year $end_string = strftime("%e", mktime(12, 0, 0, $end[2], $end[3], $end[1])); $start_string = strftime("%e", mktime(12, 0, 0, $start[2], $start[3], $start[1])); //now include the month in the comparison. Compare including the year. if (mktime(12, 0, 0, $end[2], 1, $end[1]) > mktime(12, 0, 0, $start[2], 1, $start[1])) { //use the textual version to make things more readable //strftime ( string $format [, int $timestamp = time() ] ) //%B Full month name, based on the locale $end_string .= ' ' . strftime("%B", mktime(12, 0, 0, $end[2], 1, $end[1])); $start_string .= ' ' . strftime("%B", mktime(12, 0, 0, $start[2], 1, $start[1])); } else { $end_string .= ' ' . strftime("%B", mktime(12, 0, 0, $end[2], 1, $end[1])); //no need to append anything to $start_string } //create a timestamp based on 1 Jan that year to compare if (mktime(12, 0, 0, 1, 1, $end[1]) > mktime(12, 0, 0, 1, 1, $start[1])) { //create two seperate strings, one to hold the last part of the date range //the other to hold the first part $end_string .= ' ' . $end[1]; $start_string .= ' ' . $start[1]; } else { $end_string .= ' ' . $end[1]; //no need to append anything to $start_string } //put both parts together $final_string = $start_string . ' to ' . $end_string; } return $final_string; } /** * Function to correctly clone an associative array storing objects * Taken from http://stackoverflow.com/questions/1532618/is-there-a-function-to-make-a-copy-of-a-php-array-to-another */ function _booking_clone_array($copied_array) { return array_map(function($element) { return ( ((is_array($element)) ? call_user_func(__FUNCTION__, $element) : ((is_object($element)) ? clone $element : $element ) ) ); }, $copied_array); } /** * Function to randomise the ordering of an array * taken from http://stackoverflow.com/questions/4102777/php-random-shuffle-array-maintaining-key-value */ function _booking_shuffle_assoc($list) { if (!is_array($list)) return $list; $keys = array_keys($list); shuffle($keys); $random = array(); foreach ($keys as $key) { $random[$key] = $list[$key]; } return $random; } /** * Helper function to cycle through a list without getting in an endless loop * Used for calculating study groups and maybe readings groups * * Each iteration through the list the maximum permitted size for a given entry will be increased by one * until we find an available entry or we run out of cycle counts */ function _booking_loop_carefully(&$list, $field, &$i, $maximum, $list_size, $max_cycle_count, &$log_array) { $cycle = 0; while ($list[$i][$field] >= $maximum) { $log_array[] = t("Field !field is !value for entry !index, which larger than maximum allowed size, !max. Moving to next entry in list.", array('!field' => $field, '!value' => $list[$i][$field], '!max' => $maximum, '!index' => $i)); $i++; //reset the counter if we go past the end if ($i > $list_size) { $i = 1; //make sure we don't get stuck in an infinite loop - only go past the end once if ($cycle >= $max_cycle_count) { $log_array[] = t("Reached the end of !field list. Unable to find satisfactory entry after !num cycles.", array('!field' => $field, '!num' => $cycle)); return; } elseif ($cycle > 0) { //temporarily increase the maximum size of our groups by one $maximum++; } //always increment the cycle counter if we've reached the end $cycle++;; } } } /** * Function to mark an attendee as processed for group calculations * @param $input string containing passport number to be verified */ function _booking_assign_attendee_group($nid, $session_id, $gender, $age, &$attendee_list, &$session_count, &$log_array) { $previous_session = 0; //check for valid attendee if (empty($nid)) { drupal_set_message(t('Attempting to process a non-existent node id.')); return; } //check if this person had already been processsed if ($attendee_list[$nid]->processed == 1 && $attendee_list[$nid]->session > 0) { $log_array[] = t('Detected re-assignment of id !id previously assigned to session !session.', array('!id' => $nid, '!session' => $attendee_list[$nid]->session) ); $previous_session = $attendee_list[$nid]->session; //update previous session totals $session_count[$previous_session][$gender]--; $session_count[$previous_session]['total']--; if ($age < 20) $session_count[$previous_session]['under20']--; elseif($age >= 20 && $age < 25) $session_count[$previous_session]['20to25']--; else $session_count[$previous_session]['over25']--; } //mark this person as processed in the working list $attendee_list[$nid]->processed = 1; $attendee_list[$nid]->session = $session_id; //record the category of person $session_count[$session_id][$gender]++; $session_count[$session_id]['total']++; //process ages if ($age < 20) $session_count[$session_id]['under20']++; elseif($age >= 20 && $age < 25) $session_count[$session_id]['20to25']++; else $session_count[$session_id]['over25']++; } /** * Validate there is available capacity for the specified room and bed type * @return TRUE if there is sufficient capacity, otherwise FALSE */ function _booking_room_capacity_check($room_id, $room_bedtype, $room_definition_object = NULL) { global $event; $bed_inputs = array( 1 => 'booking_room_singlebeds', 2 => 'booking_room_doublebeds', 3 => 'booking_room_queenbeds', ); //make sure the value exists before validating it if (!empty($room_bedtype)) { //if we already have the object available, don't query for it again if ($room_definition_object == NULL) { $details = db_query("SELECT * FROM {booking_room_definition} WHERE rid = :rid", array(':rid' => $room_id))->fetchObject(); } else $details = $room_definition_object; //get all person-to-room mappings relating to this room and bed type $mappings = db_query("SELECT count(*) as num FROM {booking_room_mapping} " . "WHERE booking_eventid = :eid AND booking_roomid = :rid AND booking_room_bedtype = :type", array(':eid' => $event->eid, ':rid' => $room_id, ':type' => $room_bedtype))->fetchObject(); $db_field = $bed_inputs[$room_bedtype]; $max_beds = $details->$db_field; //if the beds are dual occupency, pretend there's twice as many of them if ($room_bedtype == 2 || $room_bedtype == 3) { $max_beds = $max_beds * 2; } //check that there is sufficient capacity to allocate another person to this room and bed type if ($mappings->num < $max_beds) { watchdog('booking','Sufficient capacity is available in location !id, room !room, with bed type !type. !count beds remaining of this type', array('!id' => $details->booking_room_location_id, '!room' => $details->booking_room_number, '!type' => _booking_room_bedtype_lookup($room_bedtype), '!count' => $max_beds - $mappings->num)); return true; } else { watchdog('booking',"Couldn't locate sufficient capacity in location !id, room !room, with bed type !type. !count beds remaining of this type", array('!id' => $details->booking_room_location_id, '!room' => $details->booking_room_number, '!type' => _booking_room_bedtype_lookup($room_bedtype), '!count' => $max_beds - $mappings->num)); } } return false; } /** * Function for cleaning up room allocations for people that have withdrawn their registration * @param $nid - the node id for the person * @return nothing */ function _booking_person_rooms_cleanup($nid) { global $event; //first of all make sure we need to do anything if (variable_get('booking_enable_roomallocations', 0) == 1) { //should only be one room allocation per person, so no need to loop over the results $room_mapping = db_query("SELECT * FROM {booking_room_mapping} WHERE booking_eventid = :eid AND booking_nodeid = :nid", array(':eid' => $event->eid, ':nid' => $nid)) ->fetchObject(); if ($room_mapping) { $message = t("Removing id !nid from room id !room.", array('!nid' => $nid, '!room' => $room_mapping->booking_roomid) ); watchdog('booking', $message); drupal_set_message($message, 'status', FALSE); db_delete('booking_room_mapping') ->condition('booking_eventid', $event->eid) ->condition('booking_nodeid', $nid) ->execute(); } //for each room } //end check for room allocations enabled } //end function /** * Function for cleaning up study groups by removing people that have withdrawn their registration * @param nothing - processes all defined study groups for the current event * @return nothing */ function _booking_studygroup_cleanup() { global $event; //search for entries already in the mapping table that have a booking_status of 3 (not coming) $to_remove_query = db_query("SELECT m.* FROM {booking_studygroup_mapping} m inner join {booking_person} p on p.nid = m.booking_node_id WHERE m.booking_eventid = :eid AND p.booking_status = 3", array(':eid' => $event->eid)); $to_remove = $to_remove_query->fetchAll(); //remove the mappings for these people no longer coming foreach ($to_remove as $person) { $num_deleted = db_delete('booking_studygroup_mapping') ->condition('booking_eventid', $event->eid) ->condition('booking_node_id', $person->booking_node_id) ->condition('booking_studygroup_id', $person->booking_studygroup_id) ->execute(); watchdog('booking', 'Removed person !nid from study group !sid, affected !num rows.', array ('!nid' => $person->booking_node_id, '!sid' => $person->booking_studygroup_id, '!num' => $num_deleted)); } } /** * Function for cleaning up study groups for a person that is no longer coming * @param $nid - the node id for the person who has withdrawn their registration * @return nothing */ function _booking_person_studygroups_cleanup($nid) { global $event; //first of all make sure we need to do anything if (variable_get('booking_enable_studygroups', 0) == 1) { //query for any groups this person is assigned to $to_remove_query = db_query("SELECT m.* FROM {booking_studygroup_mapping} m WHERE booking_node_id = :nid", array(':nid' => $nid)); $to_remove = $to_remove_query->fetchAll(); foreach ($to_remove as $group) { $message = t("Removing id !nid from group id !group, session !session with role !role", array('!nid' => $nid, '!group' => $group->booking_studygroup_id, '!session' => $group->booking_session_id, '!role' => _booking_studygroup_role_lookup($group->booking_studygroup_role) ) ); watchdog('booking', $message); drupal_set_message($message, 'status', FALSE); db_delete('booking_studygroup_mapping') ->condition('booking_eventid', $event->eid) ->condition('booking_node_id', $nid) ->condition('booking_studygroup_id', $group->booking_studygroup_id) ->execute(); } //for each group } //end check for study groups enabled } //end function /** * Function for calculating statistics of attendees */ function _booking_generate_statistics($booking_list) { global $event; $statistics = array( 'males' => 0, 'females' => 0, 'under20' => 0, '20to25' => 0, 'over25' => 0, ); foreach ($booking_list as $person) { //ignore people that havent paid or are no longer coming or missed the payment deadline if ($person->booking_status == 0 || $person->booking_status == 3 || $person->booking_status == 4) continue; if ($person->booking_gender == 'M') $statistics['males']++; else $statistics['females']++; $age = _booking_get_age_years($person->booking_dob); if ($age < 20) $statistics['under20']++; elseif($age >= 20 && $age < 25) $statistics['20to25']++; else $statistics['over25']++; } return $statistics; } //figure out if we're in the right time period for discounted registration rates function _booking_is_earlybird() { global $event; if ($event->booking_earlybird_close > time()) return TRUE; else { return FALSE; } } function _booking_datepaid_ts($nid) { $query = db_query("SELECT * FROM {booking_payment} where booking_person_nid = :nid", array(':nid' => $nid)) ->fetchObject(); if ($query) return $query->booking_payment_date; else return 0; } /** * Helper function to calculate paypal fees */ function _booking_add_paypal_fees($amount, $country) { //add the 30 cent fixed cost $result = '0.00'; $result = (float) ($amount + (float) variable_get('booking_paypal_transaction_fee_fixedcost', '0.3')); //and the 2.6 percent transaction fee for australian transaction with no currency conversion if ($country == variable_get('booking_default_country', 'Australia')) { $percentage = (float) variable_get('booking_paypal_transaction_fee_percentage', '2.6'); } else { $percentage = (float) variable_get('booking_paypal_transaction_fee_percentage_intl', '3.6'); //watchdog('booking', "Calculating paypal fees for a currency conversion transaction which adds $percentage percent."); } //apply the percentage $percentage = (float) $percentage / 100; //watchdog('booking', "Paypal percentage transaction fee works out to $percentage."); $result = $result / (1 - $percentage); //return result return $result; } /** * Helper function to return the amount for a booking deposit, if there is one */ function _booking_deposit_amount($person, $include_fees = TRUE) { global $event; $deposit = db_query("SELECT price.booking_price, price.booking_price_descrip " . "FROM {booking_price} price WHERE booking_eventid = :eventid and booking_depositonly = 1 and booking_price_active = 1", array(':eventid' => $event->eid)) ->fetchObject(); if ($deposit) { //if we're using paypal, add the transaction fee if (variable_get('booking_use_paypal', 0) == 1 && $include_fees == TRUE) { $amount_owing = _booking_add_paypal_fees($deposit->booking_price, $person->booking_country); } else { $amount_owing = $deposit->booking_price; } //return the calculated amount rounded to two decimal places return number_format($amount_owing, 2, '.', ''); } else { //there is no deposit amount return 0; } } /** * Calculate exactly how much a person has already paid */ function _booking_amount_paid($nid, $person = NULL) { $amount_paid = 0; //fetch details about the person if we don't already have them if ($person == NULL) { $person = db_query("SELECT price.booking_price, price.booking_late_price, person.booking_payment_id, " . "person.booking_total_pay_reqd, person.booking_amount_paid, person.booking_partner_id " . "FROM {booking_person} person, {booking_price} price " . "WHERE person.nid = :nid " . "AND person.booking_payment_id = price.pid", array(':nid' => $nid)) ->fetchObject(); } //check for a spouse if ($person->booking_partner_id > 0) { //watchdog('booking', "Checking total paid for married person"); //look for payments in the payment transaction table //if we're combining the payment for married couples if (variable_get('booking_enable_combined_pricing', 0) == 1) { //check for payments in the paypal transaction table from either spouse $query = db_query("SELECT booking_mc_gross, booking_mc_fee FROM booking_payment " . "WHERE booking_person_nid = :nid OR booking_person_nid = :spousenid", array(':nid' => $nid, 'spousenid' => $person->booking_partner_id)); } else { //check for payments in the paypal transaction table from just this person $query = db_query("SELECT booking_mc_gross, booking_mc_fee FROM booking_payment " . "WHERE booking_person_nid = :nid", array(':nid' => $nid)); } //add up all the payments foreach ($query as $payment) { $amount_paid += ($payment->booking_mc_gross - $payment->booking_mc_fee); } //watchdog('booking', "Total amount paid according to paypal payments table is " . $amount_paid); //there were no payment transactions, so rely on what the amount is set to in the individual registration records if ($amount_paid == 0) { //if we're combining the payment for married couples if (variable_get('booking_enable_combined_pricing', 0) == 1) { $spouse = db_query("SELECT person.booking_amount_paid " . "FROM {booking_person} person " . "WHERE person.nid = :nid ", array(':nid' => $person->booking_partner_id)) ->fetchObject(); $amount_paid = $person->booking_amount_paid + $spouse->booking_amount_paid; //watchdog('booking', "Total combined payments for couple based on totals in booking_person table is " . $amount_paid); } else { $amount_paid = $person->booking_amount_paid; //watchdog('booking', "Total amount paid for individual based on totals in booking_person table is " . $amount_paid); } //end combined payments check } } //no spouse found else { //Check if there are payment records in the paypal transaction table for this unmarried person //if so, base their payments on the gross amount in there rather than what the person booking_person database says $query = db_query("SELECT booking_mc_gross, booking_mc_fee FROM booking_payment " . "WHERE booking_person_nid = :nid", array(':nid' => $nid)); foreach ($query as $payment) $amount_paid += ($payment->booking_mc_gross - $payment->booking_mc_fee); //watchdog('booking', "Total amount paid according to paypal payments table is " . $amount_paid); //if there were no results, $amount_paid will still be 0 if ($amount_paid == 0) { $amount_paid = $person->booking_amount_paid; } //in case there has been some manual adjustment //elseif ($amount_paid < $person->booking_amount_paid) // $amount_paid = $person->booking_amount_paid; } //watchdog('booking', "Total amount already paid for this registration " . $nid . " is " . $amount_paid); return $amount_paid; } /** * Function to calculate the total amount a person is required to pay * * @param $person - the populated node object representing this person including related price information * @return amount owing as a decimal value */ function _booking_total_due($person) { //watchdog('booking', "
_booking_total_due person:\n @info
", array('@info' => print_r( $person, true))); $total_due = 0.00; //check for a spouse if ($person->booking_partner_id > 0 && variable_get('booking_enable_combined_pricing', 0) == 1) { //watchdog('booking', "Calculating total amount due for a married couple."); //TODO: figure out if anything special is needed here } //determine what rate this person needs to pay if ($person->booking_welfare_required == 'Y' || $person->booking_committee_member == 'Y') { //cater for any manual adjustment //watchdog('booking', "This registration is eligible for welfare rates"); $total_due = $person->booking_total_pay_reqd; } //the early bird rate will be defined by default for the registration elseif (_booking_is_earlybird() == TRUE) { $total_due = $person->booking_total_pay_reqd; } //finally we must be in the late-fee period else { //when first creating this node the price information won't all exist //since we combine that with the booking_person table in the hook for node_load if (!isset($person->booking_late_price)) { //query the database based on the payment_id that is set when we first create the node $query = db_select('booking_price', 'p'); $query->condition('p.pid', $person->booking_payment_id, '=') ->fields('p'); $result = $query->execute()->fetchObject(); //set the result $total_due = $result->booking_late_price; } else { $total_due = $person->booking_late_price; } } //end payment type conditional return $total_due; } /** * Function to calculate the amount outstanding for a person/married couple * * @param $person - the object relating to the registration node * @param $amount_paid - if we have previously calculated the amount paid, this can be passed as a value * @param $include_fees - boolean to indicate whether we want the net amount or the amount owing including paypal fees * @return amount owing as a decimal value */ function _booking_amount_owing($person, $amount_paid = 0, $include_fees = TRUE) { global $event; //quick sanity check if (! $person->nid) { watchdog('booking', "Unable to find matching person relating to registration id. Details were '" . var_export($person, TRUE) . "' ."); return 0.00; } $total_due = _booking_total_due($person); //if we didn't get the amount paid as a command line parameter, check it now if ($amount_paid == 0) { $amount_paid = _booking_amount_paid($person->nid, $person); } //check if there is anything outstanding //use the original total amount required rather than the late-rate, to cater for people that paid before the late rate if ($amount_paid >= $person->booking_total_pay_reqd) { //watchdog('booking', "This person doesn't owe any money: @info", array('@info' => var_export($person, TRUE))); return 0; } //@todo - use booking_payment_processor instead. 0 is paypal, 1 is stripe, 2 is manual //if we're using paypal, add the transaction fee if (variable_get('booking_use_paypal', 0) == 1 && $include_fees == TRUE) { $amount_owing = _booking_add_paypal_fees($total_due - $amount_paid, $person->booking_country); } else { $amount_owing = $total_due - $amount_paid; } return number_format($amount_owing, 2, '.', ''); } /** * Function to update the person object when a payment has been made * payment details should be inserted into booking_payment prior to calling this function * * @param $person - the populated node object representing this person including related price information * @param $payment_amount - the gross payment amount that is being processed * @param $balance_payment - boolean to indicate if this transaction was to complete a payment * @return nothing */ function _booking_process_person_payment($person, $payment_amount, $balance_payment) { global $event; //calculate their total payment amount $total = $person->booking_amount_paid + $payment_amount; //only recalculate their booking status if this is the initial payment, not a payment of the outstanding balance if ($balance_payment == FALSE) { watchdog('booking', 'Processing an initial payment. Booking status is currently ' . $person->booking_status); if ($person->booking_status == 1) { watchdog('booking', 'This registration has been manually assigned to the booked-in list.'); $status = 1; } elseif (_booking_check_bookings_full() == True || $person->booking_status == 2) { watchdog('booking', 'This registration belongs on the waiting list.'); $status = 2; } else { watchdog('booking', 'This registration made it to the booked-in list.'); $status = 1; } } else { //this is a balance payment watchdog('booking', 'Processing a balance payment.'); //if this is a payment of outstanding balance, keep the booking_status the same $status = $person->booking_status; } //update the database for this person db_update('booking_person') ->fields(array( 'booking_amount_paid' => $total, 'booking_status' => $status, )) ->condition('nid', $nid) ->execute(); //handle workflow emails and spouse payment updates _booking_postpayment_trigger($nid, $person, $balance_payment); } /** * Function to handle any post-payment notification emails for either paypal or manual payment * still a WIP * * @param $nid - the node ID relating to this person * @param $person - the populated node object representing this person including related price information * @param $balance_payment - boolean to indicate if this transaction was to complete a payment * @return nothing */ function _booking_postpayment_trigger($nid, $person, $balance_payment) { global $event; //If there is no outstanding balance, send a payment complete email $amount_owing = _booking_amount_owing($person); //if ($total >= $person->booking_total_pay_reqd) if ($amount_owing == 0) { //set the payment complete flag db_update('booking_person') ->fields(array( 'booking_payment_complete' => 'Y', )) ->condition('nid', $nid) ->execute(); //this should always be a balance payment type email, since that tells the user that their payment is completed _booking_registration_email($nid, TRUE); //if we are combining payments, and this person has a linked spouse if ((variable_get('booking_enable_combined_pricing', 0) == 1) && ($person->booking_partner_id > 0)) { //check spouse booking_status and payment info $spouse = db_select('booking_person', 'p') ->condition('p.nid', $person->booking_partner_id,'=') ->fields('p', array('booking_amount_paid', 'booking_status', 'booking_total_pay_reqd')) ->execute() ->fetchObject(); //update the spouse's status from "not paid" if required $spouse_status = $spouse->booking_status == 0 ? 1 : $spouse->booking_status; watchdog('booking', 'Setting status for spouse id !id to !new from !status', array('!id' => $person->booking_partner_id, '!new' => $spouse_status, '!status' => $spouse->booking_status)); //set the spouse's payment required to be zero or equal to their previous payment total $spouse_new_amount_reqd = $spouse->booking_amount_paid > 0 ? $spouse->booking_amount_paid : 0; watchdog('booking', 'Setting amount owing for spouse id !id to !new from !old.', array('!id' => $person->booking_partner_id, '!new' => $spouse_new_amount_reqd, '!old' => $spouse->booking_total_pay_reqd)); //update the database for this person db_update('booking_person') ->fields(array( 'booking_total_pay_reqd' => $spouse_new_amount_reqd, 'booking_status' => $spouse_status, 'booking_payment_complete' => 'Y', )) ->condition('nid', $person->booking_partner_id) ->execute(); //send an email to the spouse _booking_registration_email($person->booking_partner_id, TRUE); } /* elseif (variable_get('booking_enable_combined_pricing', 0) == 1) { watchdog('booking', 'Combined pricing is enabled, but this person has a partner id of !id.', array('!id' => $person->booking_partner_id)); } //end spouse check */ } //if this was an initial payment we might need to send a notification elseif ($balance_payment == FALSE) { //send a notification email if we didn't automatically send one earlier if (variable_get('booking_auto_confirm_email', 0) == 0) { _booking_registration_email($nid, FALSE); } } else //this person still has an outstanding balance so just send a confirmation email { watchdog('booking', 'This balance payment was insufficient for !id to completely pay the total outstanding of !outstanding.', array('!id' => $nid, '!outstanding' => $amount_owing)); //send the person an email thanking them for their partial payment _booking_partialbalance_payment_email($nid); //TODO: create an email specifically for partial-balance payments //_booking_registration_email($nid, $balance_payment); } } /** * Function to process the amount to refund a person when they withdraw their registration * * @param $person - the populated node object representing this person including related price information * @return amount to be refunded for this registration */ function _booking_process_refund($person) { global $event; $refund = 0; //calculate amount to be refunded $paid = _booking_amount_paid($person->nid, $person); if ($paid > 0) { //calculate the refund due //don't include paypal fees in the deposit amount $refund = $paid - _booking_deposit_amount($person, FALSE); //if there is a spouse, subtract their deposit too if (variable_get('booking_enable_combined_pricing', 0) == 1 && $person->booking_partner_id > 0) { $refund = $refund - _booking_deposit_amount($person, FALSE); } } watchdog('booking', "Processing refund due to !first !last. Calculated as $!refund", array('!first' => $person->booking_firstname, '!last' => $person->booking_lastname, '!refund' => $refund)); //$refund_due = $person->booking_amount_paid - $refund; if ($refund == 0) { //mark the refund as processed since no action is required and don't add an entry into the manual payments table db_update('booking_person') ->fields(array( 'booking_refund_due' => 0, 'booking_refund_processed' => 'Y', )) ->condition('nid', $person->nid) ->execute(); } else { //update booking_amount_paid db_update('booking_person') ->fields(array( 'booking_refund_due' => $refund, )) ->condition('nid', $person->nid) ->execute(); //add manual payment entry for refund $result = db_insert('booking_payment') ->fields(array( 'booking_person_nid' => $person->nid, 'booking_eventid' => $event->eid, 'booking_mc_gross' => $refund * -1, 'booking_mc_currency' => 'AUD', 'booking_mc_fee' => '0.00', 'booking_quantity' => 1, 'booking_invoice' => 'Refund', 'booking_payer_id' => '', 'booking_payment_date' => REQUEST_TIME, 'booking_payment_status' => '', 'booking_first_name' => $person->booking_firstname, 'booking_last_name' => $person->booking_lastname, 'booking_buyer_email' => '', 'booking_payer_status' => '', 'booking_item_name' => 'Refund', 'booking_ipn_track_id' => '', )) ->execute(); } //return the amount to refund this person return $refund; } /** * Helper function to generate paypal form for payments */ function _booking_paypal_form($person, $invoiceid, $amount_owing, $button_text) { $form = drupal_get_form('_booking_paypal_form_builder', $person, $invoiceid, $amount_owing, $button_text); return drupal_render($form); } /** * Helper function to generate form elements for paypal form */ function _booking_paypal_form_builder($node, &$form_state, $person, $invoiceid, $amount_owing, $button_text) { global $event; //get our current path so we can send the user back here if they cancel $path = isset($_GET['q']) ? $_GET['q'] : ''; //paypal specific settings $vars = array( 'module' => 'Booking System', 'type' => $event->booking_eventname, //'custom' => $data, 'item_name' => $event->booking_eventname . ' ' . $person->booking_price_descrip, 'invoice' => $invoiceid, 'no_shipping' => TRUE, 'no_note' => TRUE, 'currency_code' => 'AUD', 'return' => url('bookingfinal', array('absolute' => TRUE)), 'cancel_return' => url($path, array('absolute' => TRUE)), 'rm' => '2', 'amount' => $amount_owing, 'last_name' => $person->booking_lastname, 'first_name' => $person->booking_firstname, 'cmd' => '_xclick', 'notify_url' => url(BOOKING_PAYPAL_IPN_PATH, array('absolute' => TRUE)), 'business' => variable_get('booking_paypal_account', '') ); $form['#action'] = url(variable_get('booking_paypal_sandbox', 0) ? BOOKING_PAYPAL_SUBMIT_URL_SANDBOX : BOOKING_PAYPAL_SUBMIT_URL, array('absolute' => TRUE)); //turn the array into a form foreach($vars as $name => $value) { $form[$name] = array( '#type' => 'hidden', '#value' => $value, ); } $form['submit'] = array( '#type' => 'button', '#value' => t($button_text), ); //watchdog('booking', 'Booking Balance payment: @info', array ('@info' => var_export($form, TRUE))); return $form; } /** * Helper function to provide a list of columns in the booking_person table * This will be used to select which fields to import/export to/from a CSV */ function _booking_get_person_fields() { $list_of_columns = array(); $query = db_query('SHOW COLUMNS FROM {booking_person_view}'); $result = $query->fetchAll(); foreach ($result as $column) { $field = $column->Field; $list_of_columns[$field] = $field; } //watchdog('booking_debug', "
Database columns for booking_person\n@info
", array('@info' => print_r( $list_of_columns, true))); return $list_of_columns; } /** * Helper function to format registrations details for summary in the confirmation email */ function _booking_details_email_summary($node) { //query for payment type description $payment_description_query = db_select('booking_price', 'p') ->condition('p.pid', $node->booking_payment_id,'=') ->fields('p', array('booking_price_descrip')) ->execute() ->fetchObject(); //watchdog('booking', "Payment description: @info", array('@info' => var_export($payment_description_query, TRUE))); $rows = array(); $rows[] = t('Registration Reference Number: !id', array('!id' => $node->nid)); $rows[] = t('Date/Time registered: !timestamp', array('!timestamp' => _booking_convert_ts($node->booking_timestamp)->format('j F, Y H:i'))); $rows[] = t('Name: !first !last', array('!first' => $node->booking_firstname, '!last' => $node->booking_lastname)); $rows[] = t('Gender: !gender', array('!gender' => $node->booking_gender == 'M' ? 'Male' : 'Female')); $rows[] = t('Date of birth: !dob', array('!dob' => _booking_convert_ts($node->booking_dob)->format('d/m/Y'))); /* if (variable_get('booking_enable_passport', 1) == 1) { $rows[] = t('Passport Number: !value', array('!value' => $node->booking_passport_num)); $rows[] = t('Passport Expiry: !timestamp', array('!timestamp' => _booking_convert_ts($node->booking_passport_expiry_date)->format('d/m/Y'))); $rows[] = t('Passport Exact Issued Name: !value', array('!value' => $node->booking_passport_issue_name)); $rows[] = t('Passport Issue Location: !value', array('!value' => $node->booking_passport_issue_location)); } */ $rows[] = t('Email address: !email', array('!email' => $node->booking_email)); $rows[] = t('Home Phone Number: !home', array('!home' => $node->booking_phone)); $rows[] = t('Mobile Phone Number: !mob', array('!mob' => $node->booking_mobile)); $rows[] = t("Postal Address:\n!street\n!suburb !state !code\n!country", array('!street' => $node->booking_street, '!suburb' => $node->booking_suburb, '!state' => $node->booking_state, '!code' => $node->booking_postcode, '!country' => $node->booking_country)); $rows[] = t('Ecclesia: !ecclesia', array('!ecclesia' => $node->booking_ecclesia)); $rows[] = t('Baptised: !ans', array('!ans' => ($node->booking_baptised == 'Y' ? 'Yes' : 'No'))); if (variable_get('booking_allow_couples', 1) == 1) { $rows[] = t('Married: !ans', array('!ans' => ($node->booking_married == 'Y' ? 'Yes' : 'No'))); $rows[] = t("If married, attending partner's name: !name", array('!name' => $node->booking_partner_name)); } if (variable_get('booking_enable_tshirts', 1) == 1) { $rows[] = t('!text: !size', array('!text' => variable_get('booking_tshirts_text_definition', 'T-Shirt size'), '!size' => $node->booking_shirt_size)); } $rows[] = t('Emergency Contact Name: !contact', array('!contact' => $node->booking_guardian_name)); $rows[] = t('Emergency Contact Relationship: !relationship', array('!relationship' => $node->booking_guardian_type)); $rows[] = t('Emergency Contact Phone: !phone', array('!phone' => $node->booking_guardian_phone)); $rows[] = t('Emergency Contact Alternate Phone: !phone', array('!phone' => $node->booking_guardian_phone_alt)); if (variable_get('booking_enable_medicare', 1) == 1) { $rows[] = t('Medicare Number: !medicare', array('!medicare' => $node->booking_medicare)); } if (variable_get('booking_enable_roommate', 0) == 1) { $rows[] = t('Preferred room-mates: !room', array('!room' => $node->booking_room_mate1 . ' ' . $node->booking_room_mate2)); } if (variable_get('booking_enable_helpareas', 1) == 1) { $help_areas = ''; if ($node->booking_help_music) $help_areas .= 'music: ' . $node->booking_help_music . ', '; if ($node->booking_help_reading == 'Y') $help_areas .= 'reading, '; if ($node->booking_help_chairing == 'Y') $help_areas .= 'chairing, '; if ($node->booking_help_readgroup_lead == 'Y') $help_areas .= 'reading group leading, '; if ($node->booking_help_discussgroup_lead == 'Y') $help_areas .= 'discussion group leading, '; if ($node->booking_help_praying == 'Y') $help_areas .= 'praying, '; if ($node->booking_help_meditations == 'Y') $help_areas .= 'meditations, '; $rows[] = t('Help areas: !help', array('!help' => $help_areas)); } if (variable_get('booking_enable_skills', 1) == 1) { $skill_areas = ''; if ($node->booking_skills_builder == 'Y') $skill_areas .= 'builder, '; if ($node->booking_skills_cooking == 'Y') $skill_areas .= 'cook, '; if ($node->booking_skills_childminding == 'Y') $skill_areas .= 'child minding, '; if ($node->booking_skills_language == 'Y') $skill_areas .= 'speaks languages: ' . $node->booking_skills_language_details . ', '; if ($node->booking_skills_other == 'Y') $skill_areas .= 'other skills: ' . $node->booking_skills_other_details . ', '; $rows[] = t('Mission related skills: !value', array('!value' => $skill_areas)); $rows[] = t('Previous Mission Experience: !value', array('!value' => $node->booking_mission_experience_details)); } $rows[] = t('Special Dietary Requirements: !dietary', array('!dietary' => $node->booking_dietary)); $rows[] = t('Special Medical Conditions: !medical', array('!medical' => $node->booking_medical_conditions)); $rows[] = t('Gross Amount Paid: !payment', array('!payment' => $node->booking_amount_paid)); $rows[] = t('Net Amount Due: !payment', array('!payment' => $node->booking_total_pay_reqd)); $rows[] = t('Payment Type: !payment', array('!payment' => $payment_description_query->booking_price_descrip)); foreach ($rows as $key => $value) $rows[$key] = wordwrap($value); return implode("\n", $rows); } /** * Helper function to format travel form summary */ function _booking_travelform_email_summary($node) { global $event; $rows = array(); if (! empty($node->tid)) { //look up the actual name if a boyfriend/girlfriend is defined if ($node->booking_bf_gf_nid != 0) { $query = db_query("Select booking_firstname, booking_lastname from {booking_person} where nid = :nid", array(':nid' => $node->booking_bf_gf_nid)) ->fetchObject(); $bf_gf = $query->booking_firstname . " " . $query->booking_lastname; } else $bf_gf = "N/A"; $rows = array(); $rows[] = t('Name: !first !last', array('!first' => $node->booking_firstname, '!last' => $node->booking_lastname)); $rows[] = t('Transport Type: !transport', array('!transport' => $node->booking_transport_type)); if ($node->booking_transport_type == 'Flying') { $rows[] = t('Catching the train to Study Week: !value', array('!value' => $node->booking_transport_from_morriset_reqd == 1 ? 'Yes' : 'No')); $rows[] = t('Inbound Flight Number: ' . $node->booking_flightnum_inbound); $rows[] = t('Flight Arrival: !date', array('!date' => format_date($node->booking_flight_datetime_inbound, 'custom', 'd/m/Y H:i'))); $rows[] = t('Outbound Flight Number: ' . $node->booking_flightnum_outbound); $rows[] = t('Flight Departure: !date', array('!date' => format_date($node->booking_flight_datetime_outbound, 'custom', 'd/m/Y H:i'))); } $rows[] = t('Accommodation before Study Week Required: !value', array('!value' => $node->booking_accom_before_reqd == 1 ? 'Yes' : 'No')); $rows[] = t('Accommodation after Study Week Required: !value', array('!value' => $node->booking_accom_after_reqd == 1 ? 'Yes' : 'No')); //fields from booking_person if (variable_get('booking_enable_dietary', 0) == 1) $rows[] = t('Special Dietary Requirements: ' . $node->booking_dietary); if (variable_get('booking_enable_roommate', 0) == 1) $rows[] = t('Special Medical Conditions: ' . $node->booking_medical_conditions); $rows[] = t('Boyfriend/Girlfriend: ' . $bf_gf); $rows[] = t('Requested room mate(s): ' . $node->booking_room_mate1); foreach ($rows as $key => $value) $rows[$key] = wordwrap($value); } //watchdog('booking_debug', "
Travel form summary\n@info
", array('@info' => print_r( $rows, true))); return implode("\n", $rows); } /** * Helper function to format summary of studygroup sessions to be used as a token */ function _booking_studygroup_email_summary($node) { global $event; $rows = array(); //display study session data if enabled if (variable_get('booking_enable_studygroups', 0) == 1) { //look up the titles of the study groups $studygroups_query = db_query("SELECT * FROM {booking_studygroup_list} WHERE booking_eventid = :eid", array(':eid' => $event->eid)); $studygroups = $studygroups_query->fetchAllAssoc('sid'); //for ($i = 1; $i <= variable_get('booking_studygroup_count','0'); $i++) foreach ($studygroups as $studygroup) { //calculate the session references $sessionid = "session" . $studygroup->sid; $roleid = $sessionid . "_role"; //check that this study group session has been defined for this attendee if (!empty($node->$sessionid)) { $rows[] = t($studygroup->booking_studygroup_descrip . ": Group " . $node->$sessionid . ", " . _booking_studygroup_role_lookup($node->$roleid)); } } } foreach ($rows as $key => $value) $rows[$key] = wordwrap($value); return implode("\n", $rows); } /** * Helper function to format information matching leaders and helpers, to be used as a token */ function _booking_leader_helper_email_summary($node) { global $event; $rows = array(); $found = FALSE; //display study session data if enabled if (variable_get('booking_enable_studygroups', 0) == 1) { //look up the titles of the study groups $studygroups_query = db_query("SELECT * FROM {booking_studygroup_list} WHERE booking_eventid = :eid", array(':eid' => $event->eid)); $studygroups = $studygroups_query->fetchAllAssoc('sid'); foreach ($studygroups as $studygroup) { //don't print info about the readings groups if ($studygroup->booking_is_readinggroup == 'Y') { continue; } //calculate the session references $sessionid = "session" . $studygroup->sid; $roleid = $sessionid . "_role"; $otherperson_name = "TBA"; $otherperson_email = ""; $otherperson_phone = ""; //check that this study group session has been defined for this attendee and that they have a role to perform if (!empty($node->$sessionid) && $node->$roleid > 0) { //if they're a leader or reserver leader, then the matching person is the helper if ($node->$roleid == 1 || $node->$roleid == 3) { $role = "Leader"; $otherrole = "Helper"; $otherrole_id = 2; } //otherwise the matching person is the leader else { $role = "Helper"; $otherrole = "Leader"; $otherrole_id = 1; } //find the other person $otherperson_query = db_query("SELECT m.*, p.* FROM {booking_studygroup_mapping} m " . " INNER JOIN {booking_person} p on m.booking_node_id = p.nid " . " WHERE p.booking_eventid = :eid " . " AND booking_studygroup_id = :group AND booking_studygroup_role = :role AND booking_session_id = :session", array(':eid' => $event->eid, ':group' => $studygroup->sid, ':role' => $otherrole_id, ':session' => $node->$sessionid, )); $otherperson = $otherperson_query->fetchAll(); //watchdog('booking', "
Other person for studygroup !group and role !role result:\n@info
", // array('!group' => $studygroup->sid, '!role' => $otherrole_id, '@info' => print_r( $otherperson, true))); //create the text for the token foreach ($otherperson as $other) { $otherperson_name = $other->booking_firstname . ' ' . $other->booking_lastname; $otherperson_email = $other->booking_email; $otherperson_phone = $other->booking_mobile; } $rows[] = t('!role for !descrip. Your !otherrole is !other. You can contact them on !phone or !email.', array('!role' => $role, '!id' => $studygroup->sid, '!descrip' => $studygroup->booking_studygroup_descrip, '!otherrole' => $otherrole, '!other' => $otherperson_name, '!phone' => $otherperson_phone, '!email' => $otherperson_email, )); } } } //format the output to be used in an email foreach ($rows as $key => $value) { $rows[$key] = wordwrap($value); } return implode("\n", $rows); } /** * Helper function to format summary of room allocation to be used as a token */ function _booking_room_email_summary($node) { global $event; $rows = array(); //display study session data if enabled if (variable_get('booking_enable_roomallocations', 0) == 1) { //check that this attendee has had a room allocated if (! empty($node->rid)) { //$rows[] = t("Room Location: " . _booking_room_location_lookup($node->booking_room_location_id)); $rows[] = t("Room Location: " . $node->booking_roomlocation_descrip); $rows[] = t("Room Number: " . $node->booking_room_number); $rows[] = t("Bed Type: " . _booking_room_bedtype_lookup($node->booking_room_bedtype)); } else $rows[] = t("\tNo room currently allocated."); } foreach ($rows as $key => $value) $rows[$key] = wordwrap($value); return implode("\n", $rows); } /** * Helper function to create the mean, median, mode or average of an array * @see http://www.phpsnips.com/45/Mean,-Median,-Mode,-Range-Of-An-Array */ function _booking_mmmr($array, $output = 'mean'){ if(!is_array($array)) { return FALSE; } else { switch($output){ case 'mean': $count = count($array); $sum = array_sum($array); $total = $sum / $count; break; case 'median': rsort($array); $middle = round(count($array) / 2); $total = $array[$middle-1]; break; case 'mode': $v = array_count_values($array); arsort($v); foreach($v as $k => $v){$total = $k; break;} break; case 'range': sort($array); $sml = $array[0]; rsort($array); $lrg = $array[0]; $total = $lrg - $sml; break; } return $total; } } /** * @brief Generates a Universally Unique IDentifier, version 4. * * This function generates a truly random UUID. The built in CakePHP String::uuid() function * is not cryptographically secure. You should uses this function instead. * * @see http://tools.ietf.org/html/rfc4122#section-4.4 * @see http://en.wikipedia.org/wiki/UUID * @return string A UUID, made up of 32 hex digits and 4 hyphens. */ function _booking_uuidSecure() { $pr_bits = null; $fp = @fopen('/dev/urandom','rb'); if ($fp !== false) { $pr_bits .= @fread($fp, 16); @fclose($fp); } else { // If /dev/urandom isn't available (eg: in non-unix systems), use mt_rand(). $pr_bits = ""; for($cnt=0; $cnt < 16; $cnt++) { $pr_bits .= chr(mt_rand(0, 255)); } } $time_low = bin2hex(substr($pr_bits,0, 4)); $time_mid = bin2hex(substr($pr_bits,4, 2)); $time_hi_and_version = bin2hex(substr($pr_bits,6, 2)); $clock_seq_hi_and_reserved = bin2hex(substr($pr_bits,8, 2)); $node = bin2hex(substr($pr_bits,10, 6)); /** * Set the four most significant bits (bits 12 through 15) of the * time_hi_and_version field to the 4-bit version number from * Section 4.1.3. * @see http://tools.ietf.org/html/rfc4122#section-4.1.3 */ $time_hi_and_version = hexdec($time_hi_and_version); $time_hi_and_version = $time_hi_and_version >> 4; $time_hi_and_version = $time_hi_and_version | 0x4000; /** * Set the two most significant bits (bits 6 and 7) of the * clock_seq_hi_and_reserved to zero and one, respectively. */ $clock_seq_hi_and_reserved = hexdec($clock_seq_hi_and_reserved); $clock_seq_hi_and_reserved = $clock_seq_hi_and_reserved >> 2; $clock_seq_hi_and_reserved = $clock_seq_hi_and_reserved | 0x8000; return sprintf('%08s-%04s-%04x-%04x-%012s', $time_low, $time_mid, $time_hi_and_version, $clock_seq_hi_and_reserved, $node); }