diff --git a/booking.constants.inc b/booking.constants.inc index 5f38872..d2b0f4b 100644 --- a/booking.constants.inc +++ b/booking.constants.inc @@ -28,7 +28,7 @@ function _booking_status_generate($input = NULL) $status_options[2] = t('Waiting List'); $status_options[3] = t('No Longer Coming'); $status_options[4] = t('Missed Payment Deadline'); - + $status_options[5] = t('Hosts'); if ($input != NULL) return $status_options[$input]; else diff --git a/booking.helper.inc b/booking.helper.inc index 8ebd41d..3a451c3 100644 --- a/booking.helper.inc +++ b/booking.helper.inc @@ -389,11 +389,49 @@ function _booking_shuffle_assoc($list) { 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) +function _booking_assign_attendee_group($nid, $session_id, $gender, $age, &$attendee_list, &$session_count, &$log_array) { $previous_session = 0; @@ -407,9 +445,9 @@ function _booking_assign_attendee_group($nid, $session_id, $gender, $age, &$atte //check if this person had already been processsed if ($attendee_list[$nid]->processed == 1 && $attendee_list[$nid]->session > 0) { - drupal_set_message(t('Detected re-assignment of id !id previously assigned to session !session.', + $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; @@ -497,8 +535,8 @@ function _booking_studygroups_cleanup($nid) foreach ($to_remove as $group) { - $message = t("Removing id !nid from group id !group with role !role", - array('!nid' => $nid, '!group' => $group->booking_studygroup_id, + $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) ) ); @@ -531,8 +569,8 @@ function _booking_generate_statistics($booking_list) foreach ($booking_list as $person) { - //ignore people that havent paid or are no longer coming - if ($person->booking_status == 0 || $person->booking_status == 3) + //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') @@ -899,44 +937,6 @@ function _booking_process_refund($person) return $refund; } -/** - * 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) -{ - $cycle = 0; - while ($list[$i][$field] >= $maximum) - { - drupal_set_message(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) - { - drupal_set_message(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++;; - } - } -} - /** * Helper function to generate paypal form for payments diff --git a/booking.module b/booking.module index 7f7144c..9e80d2b 100644 --- a/booking.module +++ b/booking.module @@ -382,13 +382,13 @@ function booking_menu() { 'type' => MENU_LOCAL_ACTION, ); - $items['admin/booking/studygroups/update'] = array( + $items['admin/booking/studygroups/%/update'] = array( 'title' => 'Update Study Groups', 'description' => 'Calculate updated Study Group memberships', 'page callback' => 'drupal_get_form', - 'page arguments' => array('booking_studygroups_update'), + 'page arguments' => array('booking_studygroups_update', 3), 'access arguments' => array('edit study groups'), - 'type' => MENU_LOCAL_ACTION, + //'type' => MENU_LOCAL_ACTION, ); $items['admin/booking/studygroups/colours'] = array( diff --git a/booking.studygroups.inc b/booking.studygroups.inc index d75b935..7e0b90d 100644 --- a/booking.studygroups.inc +++ b/booking.studygroups.inc @@ -12,8 +12,8 @@ function booking_studygroups_view_summary() { global $event; $output = ""; - $header = array('Link','Study Group', 'Session Count', 'Select Leaders'); - $attributes = array('style' => 'max-width:40%'); + $header = array('Study Group', 'Session Count', 'View', 'Select Leaders', 'Auto-Update'); + $attributes = array('style' => 'max-width:50%'); //get study groups $query = db_select('booking_studygroup_list', 's') @@ -23,10 +23,11 @@ function booking_studygroups_view_summary() { foreach ($result as $group) { $rows[] = array( - l(t('View', array('!id' => $group->sid)), t('admin/booking/studygroups/!id/view', array('!id' => $group->sid))), $group->booking_studygroup_descrip, $group->booking_num_group_sessions, + l(t('View', array('!id' => $group->sid)), t('admin/booking/studygroups/!id/view', array('!id' => $group->sid))), l(t('Edit Leaders/Helpers', array('!id' => $group->sid)), t('admin/booking/studygroups/!id/selectleaders', array('!id' => $group->sid))), + l(t('Auto Update', array('!id' => $group->sid)), t('admin/booking/studygroups/!id/update', array('!id' => $group->sid))), ); } @@ -571,8 +572,8 @@ function booking_studygroups_edit_form_submit($form, &$form_state) { //check for an existing study group mapping to change elseif ((!empty($person_groups[$key])) && $person_groups[$key]->booking_session_id != $value) { - watchdog('booking', "Updating Study Group session from: @key to @value", - array('@key' => $person_groups[$key]->booking_session_id, '@value' => $value)); + watchdog('booking', "Updating Study Group session from: @key to @value for id @id", + array('@key' => $person_groups[$key]->booking_session_id, '@value' => $value, '@id' => $nid)); db_update('booking_studygroup_mapping') ->fields(array( @@ -962,7 +963,7 @@ function booking_studygroups_calculate() { /** * Function for calculating who belongs to which study group */ -function booking_studygroups_update() { +function booking_studygroups_update($node, &$form_state, $sid) { global $event; //master attendee list @@ -971,11 +972,34 @@ function booking_studygroups_update() { $working_list = array(); //create an array to keep track of the number of people in each session for each group $session_count = array(); + //the form to return + $form = array(); + $calculation_messages = array(); + $update_messages = array(); + $prefix = ""; + $intro_text = ""; + $reading_group_id = variable_get('booking_readinggroup_id','7'); + + //verify that $nid is a number + if (! preg_match('/^[0-9]+$/', $sid)) { + drupal_set_message("Error: Invalid group ID '" . $sid . "' supplied. Unable to update study group session.", 'error', FALSE); + drupal_goto('admin/booking/studygroups'); + return ""; + } - //select all the study groups for this event id - $studygroups_query = db_query("SELECT * FROM {booking_studygroup_list} WHERE booking_eventid = :eid", array(':eid' => $event->eid)); + //select the study group for the supplied ID + //$studygroups_query = db_query("SELECT * FROM {booking_studygroup_list} WHERE booking_eventid = :eid", array(':eid' => $event->eid)); + $studygroups_query = db_query("SELECT * FROM {booking_studygroup_list} WHERE sid = :sid", array(':sid' => $sid)); $studygroups = $studygroups_query->fetchAllAssoc('sid'); + //throw an error if we got no groups + if (! $studygroups) + { + drupal_set_message("Error: Unable to find group with corresponding ID '" . $sid . "'.", 'error', FALSE); + drupal_goto('admin/booking/studygroups'); + return ""; + } + //calculate the max number of attendees in a group $firstgroup = reset($studygroups); $limit = variable_get('booking_regn_limit','500'); @@ -983,7 +1007,7 @@ function booking_studygroups_update() { $fudge_factor = 1; $max_people = (int) ($limit / $firstgroup->booking_num_group_sessions) + $fudge_factor; - //select all the attendees booked in + //select all the attendees for this event $query = db_query("SELECT * FROM {booking_person} WHERE booking_event_id = :eid", array(':eid' => $event->eid)); $attendees = $query->fetchAllAssoc('nid'); @@ -1001,14 +1025,9 @@ function booking_studygroups_update() { '20to25' => ceil(($statistics['20to25'] / $limit) * ($max_people - $fudge_factor)), 'over25' => ceil(($statistics['over25'] / $limit) * ($max_people - $fudge_factor)), ); - - drupal_set_message(t('Aiming for !males males, !females females in group. Made up of !20s under 20, !low20s between 20 and 25, and !high20s over 25. Total count in group is !max.', - array('!20s' => $maximums['under20'], '!low20s' => $maximums['20to25'], '!high20s' => $maximums['over25'], - '!males' => $maximums['male'], '!females' => $maximums['female'], '!max' => $max_people) - )); //select any entries already in the mapping table - $group_mapping_query = db_query("SELECT * FROM {booking_studygroup_mapping} WHERE booking_eventid = :eid", array(':eid' => $event->eid)); + $group_mapping_query = db_query("SELECT * FROM {booking_studygroup_mapping} WHERE booking_eventid = :eid AND booking_studygroup_id = :sid", array(':eid' => $event->eid, ':sid' => $sid)); $group_mapping = $group_mapping_query->fetchAllAssoc('sid'); //TODO: Move this to a helper function @@ -1054,8 +1073,13 @@ function booking_studygroups_update() { //process each study group (eg Monday Tuesday Wednesday etc) foreach ($studygroups as $group) { - drupal_set_message(t('Processing study group !group with !sessions sessions.', - array('!group' => $group->booking_studygroup_descrip, '!sessions' => $group->booking_num_group_sessions))); + + $prefix .= t('
Aiming for !males males, !females females in group. Made up of !20s under 20, !low20s between 20 and 25, and !high20s over 25. Total count in group is !max.
', + array('!20s' => $maximums['under20'], '!low20s' => $maximums['20to25'], '!high20s' => $maximums['over25'], + '!males' => $maximums['male'], '!females' => $maximums['female'], '!max' => $max_people) + ); //create a temporary copy of the attendee list to work with for this study group $working_list = array(); @@ -1090,39 +1114,40 @@ function booking_studygroups_update() { //if the study group id matches the group we're currently looking at, and they have a role defined //or if the group id matches, they are a committee member and this is the readings group if (($person->booking_studygroup_id == $group->sid && $person->booking_studygroup_role > 0) || - ($person->booking_studygroup_id == $group->sid && $committee_flag == 'Y' && $group->sid == variable_get('booking_readinggroup_id','7'))) + ($person->booking_studygroup_id == $group->sid && $committee_flag == 'Y' && $group->sid == $reading_group_id)) { - drupal_set_message(t('Leader/helper/committee with id !id assigned to session !session (currently with !num people).', + $calculation_messages[] = t('Leader/helper/committee with id !id assigned to session !session (currently with !num people).', array('!id' => $person->booking_node_id, '!session' => $person->booking_session_id, '!num' => $session_count[$person->booking_session_id]['total']) - )); + ); //mark this position as being used + $working_list[$person->booking_node_id]->booking_studygroup_role = $person->booking_studygroup_role; $age = _booking_get_age_years($working_list[$person->booking_node_id]->booking_dob); - _booking_assign_attendee_group($person->booking_node_id, $session_id, 'male', $age, $working_list, $session_count); + _booking_assign_attendee_group($person->booking_node_id, $session_id, 'male', $age, $working_list, $session_count, $calculation_messages); //make sure the leader/helper's partner gets updated now, otherwise they could still end up in different groups if ($spouse_id > 0) { //also mark their spouse as allocated to this group - drupal_set_message(t('Spouse with id !id assigned to session !session (currently with !num people).', + $calculation_messages[] = t('Spouse with id !id assigned to session !session (currently with !num people).', array('!id' => $spouse_id, '!session' => $person->booking_session_id, '!num' => $session_count[$person->booking_session_id]['total']) - )); + ); $age = _booking_get_age_years($working_list[$spouse_id]->booking_dob); $spouse_gender = $working_list[$spouse_id]->booking_gender == 'M' ? 'male' : 'female'; - _booking_assign_attendee_group($spouse_id, $session_id, $spouse_gender, $age, $working_list, $session_count); + _booking_assign_attendee_group($spouse_id, $session_id, $spouse_gender, $age, $working_list, $session_count, $calculation_messages); } elseif ($bf_gf_id > 0) { //also mark their boyfriend/girlfriend as allocated to this group - drupal_set_message(t('BF/GF with id !id assigned to session !session (currently with !num people).', + $calculation_messages[] = t('BF/GF with id !id assigned to session !session (currently with !num people).', array('!id' => $bf_gf_id, '!session' => $person->booking_session_id, '!num' => $session_count[$person->booking_session_id]['total']) - )); + ); $age = _booking_get_age_years($working_list[$bf_gf_id]->booking_dob); $bfgf_gender = $working_list[$bf_gf_id]->booking_gender == 'M' ? 'male' : 'female'; - _booking_assign_attendee_group($bf_gf_id, $session_id, $bfgf_gender, $age, $working_list, $session_count); + _booking_assign_attendee_group($bf_gf_id, $session_id, $bfgf_gender, $age, $working_list, $session_count, $calculation_messages); } } @@ -1138,21 +1163,21 @@ function booking_studygroups_update() { } //mark this person as allocated to this group - drupal_set_message(t('Married person with id !id assigned to session !session (currently with !num people).', + $calculation_messages[] = t('Married person with id !id assigned to session !session (currently with !num people).', array('!id' => $person->booking_node_id, '!session' => $person->booking_session_id, '!num' => $session_count[$person->booking_session_id]['total']) - )); + ); $age = _booking_get_age_years($working_list[$person->booking_node_id]->booking_dob); - _booking_assign_attendee_group($person->booking_node_id, $session_id, $gender, $age, $working_list, $session_count); + _booking_assign_attendee_group($person->booking_node_id, $session_id, $gender, $age, $working_list, $session_count, $calculation_messages); //also mark their spouse as allocated to this group - drupal_set_message(t('Spouse with id !id assigned to session !session (currently with !num people).', + $calculation_messages[] = t('Spouse with id !id assigned to session !session (currently with !num people).', array('!id' => $spouse_id, '!session' => $person->booking_session_id, '!num' => $session_count[$person->booking_session_id]['total']) - )); + ); $age = _booking_get_age_years($working_list[$spouse_id]->booking_dob); $spouse_gender = $working_list[$spouse_id]->booking_gender == 'M' ? 'male' : 'female'; - _booking_assign_attendee_group($spouse_id, $session_id, $spouse_gender, $age, $working_list, $session_count); + _booking_assign_attendee_group($spouse_id, $session_id, $spouse_gender, $age, $working_list, $session_count, $calculation_messages); } elseif ($bf_gf_id > 0) { @@ -1163,21 +1188,21 @@ function booking_studygroups_update() { } //mark this person as allocated to this group - drupal_set_message(t('Person with id !id in relationship assigned to session !session (currently with !num people).', + $calculation_messages[] = t('Person with id !id in relationship assigned to session !session (currently with !num people).', array('!id' => $person->booking_node_id, '!session' => $person->booking_session_id, '!num' => $session_count[$person->booking_session_id]['total']) - )); + ); $age = _booking_get_age_years($working_list[$person->booking_node_id]->booking_dob); - _booking_assign_attendee_group($person->booking_node_id, $session_id, $gender, $age, $working_list, $session_count); + _booking_assign_attendee_group($person->booking_node_id, $session_id, $gender, $age, $working_list, $session_count, $calculation_messages); //also mark their boyfriend/girlfriend as allocated to this group - drupal_set_message(t('BF/GF with id !id assigned to session !session (currently with !num people).', + $calculation_messages[] = t('BF/GF with id !id assigned to session !session (currently with !num people).', array('!id' => $bf_gf_id, '!session' => $person->booking_session_id, '!num' => $session_count[$person->booking_session_id]['total']) - )); + ); $age = _booking_get_age_years($working_list[$bf_gf_id]->booking_dob); $bfgf_gender = $working_list[$bf_gf_id]->booking_gender == 'M' ? 'male' : 'female'; - _booking_assign_attendee_group($bf_gf_id, $session_id, $bfgf_gender, $age, $working_list, $session_count); + _booking_assign_attendee_group($bf_gf_id, $session_id, $bfgf_gender, $age, $working_list, $session_count, $calculation_messages); } //for anyone else, just record what session they're currently in else @@ -1234,19 +1259,19 @@ function booking_studygroups_update() { $age_type = 'over25'; //make sure this person is going to fit in with our calculated gender ratios - _booking_loop_carefully($session_count, $gender, $start, $maximums[$gender], $group->booking_num_group_sessions, 3); + _booking_loop_carefully($session_count, $gender, $start, $maximums[$gender], $group->booking_num_group_sessions, 3, $calculation_messages); //make sure this person is going to fit in with our calculated age ratios - _booking_loop_carefully($session_count, $age_type, $start, $maximums[$age_type], $group->booking_num_group_sessions, 3); + _booking_loop_carefully($session_count, $age_type, $start, $maximums[$age_type], $group->booking_num_group_sessions, 3, $calculation_messages); //check for maximum group size - _booking_loop_carefully($session_count, 'total', $start, $max_people, $group->booking_num_group_sessions, 4); + _booking_loop_carefully($session_count, 'total', $start, $max_people, $group->booking_num_group_sessions, 4, $calculation_messages); - drupal_set_message(t('Assigning person with id !id with gender !gender and age group !age to session !session (currently with !num people).', + $calculation_messages[] = t('Assigning person with id !id with gender !gender and age group !age to session !session (currently with !num people).', array('!id' => $it->key(), '!session' => $start, '!num' => $session_count[$start]['total'], '!gender' => $gender, '!age' => $age_type ) - )); + ); - _booking_assign_attendee_group($it->key(), $start, $gender, $age, $working_list, $session_count); + _booking_assign_attendee_group($it->key(), $start, $gender, $age, $working_list, $session_count, $calculation_messages); } //end processed check @@ -1269,7 +1294,7 @@ function booking_studygroups_update() { foreach($working_list as $person) { - //watchdog('booking', "Working list person:\n@info", array('@info' => print_r( $person, true))); + //watchdog('booking', "
Working list role person:\n@info", array('@info' => print_r( $person, true))); //check to update existing records rather than inserting new one // if already in $group_mapping then just run an update query here @@ -1281,16 +1306,19 @@ function booking_studygroups_update() { if ($person->nid == $mapping->booking_node_id && $group->sid == $mapping->booking_studygroup_id) { $found = TRUE; - + //if the existing session is not the same as our newly calculated session, run an update query - if ($mapping->booking_session_id !== $person->session) + if ($mapping->booking_session_id !== $person->session && $group->sid != $reading_group_id) { - drupal_set_message(t('Found existing study group session for user !id. Changing old session !old to !session. Role id is !role', + $message = t('Found existing study group session for user !id (!name). Changing old session !old to !session. Role id is !role', array('!id' => $person->nid, '!old' => $mapping->booking_session_id, '!session' => $person->session, - '!role' => $person->booking_studygroup_role))); + '!role' => $person->booking_studygroup_role, '!name' => $person->booking_firstname . " " . $person->booking_lastname)); + $update_messages[] = $message; + //drupal_set_message($message, 'status', FALSE); + watchdog('booking', $message); //update the entry - + /* db_update('booking_studygroup_mapping') ->fields(array( 'booking_session_id' => $person->session, @@ -1298,8 +1326,28 @@ function booking_studygroups_update() { )) ->condition('sid', $mapping->sid) ->execute(); - + */ } + elseif ($mapping->booking_session_id !== $person->session && $group->sid == $reading_group_id) + { + $message = t('Found existing reading group session for user !id (!name). Changing old session !old to !session. Role id is !role', + array('!id' => $person->nid, '!old' => $mapping->booking_session_id, '!session' => $person->session, + '!role' => $person->booking_studygroup_role, '!name' => $person->booking_firstname . " " . $person->booking_lastname)); + $update_messages[] = $message; + //drupal_set_message($message, 'status', FALSE); + watchdog('booking', $message); + + //update the entry + /* + db_update('booking_studygroup_mapping') + ->fields(array( + 'booking_session_id' => $person->session, + 'booking_studygroup_role' => $person->booking_studygroup_role, + )) + ->condition('sid', $mapping->sid) + ->execute(); + */ + } else { //drupal_set_message(t('Found existing study group session for user !id, but old session !old matches new value !session.', @@ -1314,8 +1362,13 @@ function booking_studygroups_update() { //if we didn't find an existing record, add it to the list to insert if (! $found && $person->session <> 0) { - drupal_set_message(t('Found no existing study group session for user id !id. Adding to list of inserts.', - array('!id' => $person->nid, '!sid' => $mapping->sid, '!session' => $person->session))); + $message = t('Found no existing study group session for user id !id (!name). Adding to list of inserts.', + array('!id' => $person->nid, '!sid' => $mapping->sid, '!session' => $person->session, + '!name' => $person->booking_firstname . " " . $person->booking_lastname + )); + //drupal_set_message($message, 'status', FALSE); + $update_messages[] = $message; + watchdog('booking', $message); $record = array( 'booking_eventid' => $event->eid, @@ -1328,7 +1381,7 @@ function booking_studygroups_update() { } } - $insert_query->execute(); + //$insert_query->execute(); //watchdog('booking', "
Session statistics list:\n@info", array('@info' => print_r( $session_count, true))); @@ -1340,8 +1393,44 @@ function booking_studygroups_update() { } //finished processing study groups - booking_studygroups_process_colours(); + //make sure to update team colours if necessary + if ($sid == $reading_group_id) + { + booking_studygroups_process_colours(); + } + //watchdog('booking', "Attendee list final version: @info", array('@info' => var_export($attendees, TRUE))); + + $form['log'] = array( + '#type' => 'fieldset', + '#title' => 'Calculated Actions', + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + $form['log']['messages'] = array( + '#type' => 'item', + '#title' => '', + '#markup' => "
" . implode("
\n", $calculation_messages) . "
" . implode("
\n", $update_messages) . "