Parent Directory
|
Revision Log
|
Revision Graph
#314859 - moved unrelated function out of actions file so that triggers is not required.
| 1 | <?php |
| 2 | // $Id$ |
| 3 | |
| 4 | if (module_exists('trigger')) { |
| 5 | include_once(drupal_get_path('module', 'library') .'/library.actions.inc'); |
| 6 | } |
| 7 | |
| 8 | /** |
| 9 | * Item type is not in the library. |
| 10 | */ |
| 11 | define('LIBRARY_ITEM_NOT_IN_LIBRARY', 0); |
| 12 | |
| 13 | /** |
| 14 | * Item type is part of the library collection. |
| 15 | */ |
| 16 | define('LIBRARY_ITEM_IN_LIBRARY', 1); |
| 17 | |
| 18 | /** |
| 19 | * Library Item is in circulation. |
| 20 | */ |
| 21 | define('LIBRARY_CIRCULATION', 0); |
| 22 | |
| 23 | /** |
| 24 | * Library Item is for reference only. |
| 25 | */ |
| 26 | define('LIBRARY_REFERENCE_ONLY', 1); |
| 27 | |
| 28 | /** |
| 29 | * Library Item is available. |
| 30 | */ |
| 31 | define('LIBRARY_ITEM_AVAILABLE', 0); |
| 32 | |
| 33 | /** |
| 34 | * Library Item is not available. |
| 35 | */ |
| 36 | define('LIBRARY_ITEM_UNAVAILABLE', 1); |
| 37 | |
| 38 | /** |
| 39 | * Library Items do not have barcodes. |
| 40 | */ |
| 41 | define('LIBRARY_NO_BARCODES', 0); |
| 42 | |
| 43 | /** |
| 44 | * Library Items have barcodes. |
| 45 | */ |
| 46 | define('LIBRARY_BARCODES', 1); |
| 47 | |
| 48 | define('LIBRARY_UNIQUE_TITLES', 1); |
| 49 | |
| 50 | /** |
| 51 | * Library action that does not change item status. |
| 52 | */ |
| 53 | define('LIBRARY_ACTION_NO_CHANGE', 0); |
| 54 | |
| 55 | /** |
| 56 | * Library action that makes an item unavailable. |
| 57 | */ |
| 58 | define('LIBRARY_ACTION_TYPE_UNAVAILABLE', 1); |
| 59 | |
| 60 | /** |
| 61 | * Library action that makes an item available. |
| 62 | */ |
| 63 | define('LIBRARY_ACTION_TYPE_AVAILABLE', 2); |
| 64 | |
| 65 | /** |
| 66 | * Number of results to display per page |
| 67 | */ |
| 68 | define('LIBRARY_RESULTS_PER_PAGE', 50); |
| 69 | |
| 70 | /** |
| 71 | * Valid permissions for this module |
| 72 | * @return array An array of valid permissions for this module |
| 73 | */ |
| 74 | function library_perm() { |
| 75 | $permissions = array( |
| 76 | 'administer library', |
| 77 | 'administer transactions', |
| 78 | 'view library history', |
| 79 | 'view own library history', |
| 80 | ); |
| 81 | foreach (library_actions() as $aid => $action) { |
| 82 | $permissions[] = 'submit library '. $action['name']; |
| 83 | } |
| 84 | return $permissions; |
| 85 | } |
| 86 | |
| 87 | /* |
| 88 | * Determine whether a user may perform any library action |
| 89 | */ |
| 90 | function library_action_access($aid) { |
| 91 | $may_view_patron = FALSE; |
| 92 | if (user_access('view patron content')) { |
| 93 | $may_view_patron = TRUE; |
| 94 | } |
| 95 | else { |
| 96 | global $user; |
| 97 | $user_patron = patron_load_by_uid($user->uid); |
| 98 | if (is_object($user_patron)) { |
| 99 | $may_view_patron = TRUE; |
| 100 | } |
| 101 | } |
| 102 | if (user_access('administer transactions') && $may_view_patron) { |
| 103 | return TRUE; |
| 104 | } |
| 105 | elseif ($aid && $may_view_patron) { |
| 106 | $action = library_get_action($aid); |
| 107 | if ($action->name) { |
| 108 | return user_access('submit library '. $action->name); |
| 109 | } |
| 110 | } |
| 111 | return FALSE; |
| 112 | } |
| 113 | |
| 114 | function library_history_access($node) { |
| 115 | if (user_access('view library history')) { |
| 116 | return TRUE; |
| 117 | } |
| 118 | else if (user_access('view own library history')) { |
| 119 | global $user; |
| 120 | $user_patron = patron_load_by_uid($user->uid); |
| 121 | if (is_object($user_patron) && $user_patron->nid == $node->nid) { |
| 122 | return TRUE; |
| 123 | } |
| 124 | } |
| 125 | return FALSE; |
| 126 | } |
| 127 | |
| 128 | /** |
| 129 | * Implementation of hook_help() |
| 130 | */ |
| 131 | function library_help($path, $arg) { |
| 132 | global $user; |
| 133 | |
| 134 | switch ($path) { |
| 135 | case 'admin/settings/library': |
| 136 | return t('<p>Below are display options for library items and lists. </p>'); |
| 137 | case 'admin/settings/library/duedates': |
| 138 | return t('<p>Due date and overdue item functionality are disabled by default. Below are options for handling how long items may be unavailable. To enable due date functionality, set a number of days greater than zero for the period an item may be made unavailable for one of the actions below. You may add further actions on the <a href="@libraryactions">Library Actions</a> page.</p>', array('@libraryactions' => url('admin/settings/library/actions'))); |
| 139 | case 'admin/settings/library/actions': |
| 140 | return t('<p>Two actions are included by default: Check In and Check Out. You may rename these by clicking "edit action" or add more actions below. You must always have at least one action that makes items available and one that makes items unavailable. Each library action generates a custom trigger to which additional Drupal actions may be assigned. See <a href="@link">Tiggers</a> and <a href="@link2">Actions</a></p>', array('@link' => url('admin/build/trigger/library'), '@link2' => url('admin/settings/actions'))); |
| 141 | case 'library-items/overdue': |
| 142 | return t('<p>Below is a list of all overdue library items. If you are a library administrator, you may <a href="@sendemail">send an email notifying all patrons with overdue items</a>.</p>', array('@sendemail' => url('library-items/overdue/email'))); |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | function library_content_extra_fields($type_name) { |
| 147 | $extra = array(); |
| 148 | if (module_exists('content') && variable_get('library_'. $type_name, LIBRARY_ITEM_NOT_IN_LIBRARY) == LIBRARY_ITEM_IN_LIBRARY) { |
| 149 | $extra['item_wrapper'] = array('label' => 'Library', 'weight' => -4); |
| 150 | } |
| 151 | return $extra; |
| 152 | } |
| 153 | |
| 154 | /** |
| 155 | * Implementation of hook_form_alter() |
| 156 | */ |
| 157 | function library_form_alter(&$form, $form_state, $form_id) { |
| 158 | if ($form_id == 'node_type_form' && isset($form['identity']['type']) && $form['#node_type']->type <> 'patron') { |
| 159 | $form['workflow']['library'] = array( |
| 160 | '#type' => 'radios', |
| 161 | '#title' => t('Library Item'), |
| 162 | '#default_value' => variable_get('library_'. $form['#node_type']->type, LIBRARY_ITEM_NOT_IN_LIBRARY), |
| 163 | '#options' => array(LIBRARY_ITEM_IN_LIBRARY => t('Yes'), LIBRARY_ITEM_NOT_IN_LIBRARY => t('No')), |
| 164 | '#description' => t('Library items will appear in library views.') |
| 165 | ); |
| 166 | } |
| 167 | else if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id) { |
| 168 | $node = $form['#node']; |
| 169 | $node_type = $form['type']['#value']; |
| 170 | if (variable_get('library_'. $node_type, LIBRARY_ITEM_NOT_IN_LIBRARY) == LIBRARY_ITEM_IN_LIBRARY) { |
| 171 | $form['#cache'] = TRUE; |
| 172 | |
| 173 | if (isset($form_state['item_count'])) { |
| 174 | $item_count = $form_state['item_count']; |
| 175 | } |
| 176 | else { |
| 177 | $item_count = max(1, empty($node->items) ? 1 : count($node->items)); |
| 178 | } |
| 179 | |
| 180 | if (variable_get('library_unique_titles', 0) == LIBRARY_UNIQUE_TITLES) { |
| 181 | $type = node_get_types('type', $node_type); |
| 182 | if ($type->has_title) { |
| 183 | unset($form['title']); |
| 184 | } |
| 185 | $form['title_wrapper'] = array( |
| 186 | '#tree' => FALSE, |
| 187 | '#prefix' => '<div class="clear-block" id="title-wrapper">', |
| 188 | '#suffix' => '</div>', |
| 189 | '#weight' => -5, |
| 190 | ); |
| 191 | $form['title_wrapper']['title'] = array( |
| 192 | '#type' => 'textfield', |
| 193 | '#title' => check_plain($type->title_label), |
| 194 | '#required' => TRUE, |
| 195 | '#default_value' => $node->title, |
| 196 | '#maxlength' => 255, |
| 197 | '#ahah' => array( |
| 198 | 'path' => 'library/title_js', |
| 199 | 'wrapper' => 'title-wrapper', |
| 200 | ), |
| 201 | '#weight' => -5, |
| 202 | ); |
| 203 | } |
| 204 | |
| 205 | // Add a wrapper for the items and more button. |
| 206 | $form['item_wrapper'] = array( |
| 207 | '#tree' => FALSE, |
| 208 | '#weight' => -4, |
| 209 | '#prefix' => '<div class="clear-block" id="library-item-wrapper">', |
| 210 | '#suffix' => '</div>', |
| 211 | ); |
| 212 | // Container for just the library items. |
| 213 | $form['item_wrapper']['items'] = array( |
| 214 | '#prefix' => '<div id="library-items">', |
| 215 | '#suffix' => '</div>', |
| 216 | '#theme' => 'library_items_field', |
| 217 | ); |
| 218 | // Add the current choices to the form. |
| 219 | for ($delta = 0; $delta < $item_count; $delta++) { |
| 220 | $form['item_wrapper']['items'][$delta] = _library_item_form($delta, $node->items[$delta]); |
| 221 | } |
| 222 | |
| 223 | // We name our button 'library_more' to avoid conflicts with other modules using |
| 224 | // AHAH-enabled buttons with the id 'more'. |
| 225 | $form['item_wrapper']['library_more'] = array( |
| 226 | '#type' => 'submit', |
| 227 | '#value' => t('Add an Item'), |
| 228 | '#weight' => 1, |
| 229 | '#submit' => array('library_more_items_submit'), // If no javascript action. |
| 230 | '#ahah' => array( |
| 231 | 'path' => 'library/js', |
| 232 | 'wrapper' => 'library-items', |
| 233 | 'method' => 'replace', |
| 234 | 'effect' => 'fade', |
| 235 | ), |
| 236 | ); |
| 237 | $form['#submit'][] = 'library_node_form_submit'; |
| 238 | } |
| 239 | } |
| 240 | else if ($form_id == 'search_form' && $form['module']['#value'] == 'library' && user_access('use advanced search')) { |
| 241 | // Keyword boxes: |
| 242 | $form['advanced'] = array( |
| 243 | '#type' => 'fieldset', |
| 244 | '#title' => t('More Search Options'), |
| 245 | '#collapsible' => TRUE, |
| 246 | '#collapsed' => TRUE, |
| 247 | '#attributes' => array('class' => 'search-advanced'), |
| 248 | ); |
| 249 | $form['advanced']['keywords'] = array( |
| 250 | '#prefix' => '<div class="criterion">', |
| 251 | '#suffix' => '</div>', |
| 252 | ); |
| 253 | $form['advanced']['keywords']['or'] = array( |
| 254 | '#type' => 'textfield', |
| 255 | '#title' => t('Containing any of the words'), |
| 256 | '#size' => 30, |
| 257 | '#maxlength' => 255, |
| 258 | ); |
| 259 | $form['advanced']['keywords']['phrase'] = array( |
| 260 | '#type' => 'textfield', |
| 261 | '#title' => t('Containing the phrase'), |
| 262 | '#size' => 30, |
| 263 | '#maxlength' => 255, |
| 264 | ); |
| 265 | $form['advanced']['keywords']['negative'] = array( |
| 266 | '#type' => 'textfield', |
| 267 | '#title' => t('Containing none of the words'), |
| 268 | '#size' => 30, |
| 269 | '#maxlength' => 255, |
| 270 | ); |
| 271 | |
| 272 | // Taxonomy box: |
| 273 | if ($taxonomy = module_invoke('taxonomy', 'form_all', 1)) { |
| 274 | $form['advanced']['category'] = array( |
| 275 | '#type' => 'select', |
| 276 | '#title' => t('Only in the category(s)'), |
| 277 | '#prefix' => '<div class="criterion">', |
| 278 | '#size' => 10, |
| 279 | '#suffix' => '</div>', |
| 280 | '#options' => $taxonomy, |
| 281 | '#multiple' => TRUE, |
| 282 | ); |
| 283 | } |
| 284 | |
| 285 | // Node types: |
| 286 | $types = array_map('check_plain', library_get_item_types('names')); |
| 287 | |
| 288 | $form['advanced']['type'] = array( |
| 289 | '#type' => 'checkboxes', |
| 290 | '#title' => t('Only of the type(s)'), |
| 291 | '#prefix' => '<div class="criterion">', |
| 292 | '#suffix' => '</div>', |
| 293 | '#options' => $types, |
| 294 | ); |
| 295 | |
| 296 | $form['advanced']['submit'] = array( |
| 297 | '#type' => 'submit', |
| 298 | '#value' => t('Advanced search'), |
| 299 | '#prefix' => '<div class="action">', |
| 300 | '#suffix' => '</div>', |
| 301 | ); |
| 302 | |
| 303 | $form['#validate'][] = 'node_search_validate'; |
| 304 | } |
| 305 | else if (module_exists('content') && $form_id == 'content_field_edit_form') { |
| 306 | $node_type = $form['type_name']['#value']; |
| 307 | if (variable_get('library_'. $node_type, LIBRARY_ITEM_NOT_IN_LIBRARY) == LIBRARY_ITEM_IN_LIBRARY) { |
| 308 | $newform = array(); |
| 309 | $newform['library_field_settings'] = array( |
| 310 | '#type' => 'fieldset', |
| 311 | '#title' => t('Library Settings'), |
| 312 | ); |
| 313 | $newform['library_field_settings']['library_display_field_'. $form['field_name']['#value']] = array( |
| 314 | '#type' => 'checkbox', |
| 315 | '#title' => t('Display this field in the library'), |
| 316 | '#default_value' => variable_get('library_display_field_'. $form['field_name']['#value'], 0), |
| 317 | '#return_value' => 1, |
| 318 | ); |
| 319 | $pos = array_search('widget', array_keys($form)); |
| 320 | |
| 321 | $form = array_merge(array_slice($form, 0, $pos), $newform, array_slice($form, $pos)); |
| 322 | $form['#submit'][] = 'library_field_submit'; |
| 323 | } |
| 324 | } |
| 325 | else if ($form_id == '') { |
| 326 | } |
| 327 | else if ($form_id == 'search_block_form' && variable_get('library_search_block', 0) == 1) { |
| 328 | $form['#submit'][] = 'library_search_box_form_submit'; |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | function library_field_submit($form_id, &$form_values) { |
| 333 | $values = $form_values['values']; |
| 334 | variable_set('library_display_field_'. $values['field_name'], $values['library_display_field_'. $values['field_name']]); |
| 335 | } |
| 336 | |
| 337 | function library_search_box_form_submit($form, &$form_state) { |
| 338 | $form_id = $form['form_id']['#value']; |
| 339 | $form_state['redirect'] = 'search/library/'. trim($form_state['values'][$form_id]); |
| 340 | } |
| 341 | |
| 342 | /* |
| 343 | * Gets the node object, modifies the title, and updates the node in the form_state |
| 344 | */ |
| 345 | function library_node_form_submit($form, &$form_state) { |
| 346 | if (variable_get('library_item_barcodes', LIBRARY_NO_BARCODES) == LIBRARY_BARCODES) { |
| 347 | $node = node_submit($form_state['values']); |
| 348 | $items = $node->items; |
| 349 | $row = 0; |
| 350 | $last_key = count($items) - 1; |
| 351 | foreach ($items as $key => $item) { |
| 352 | //Remove empty item instance if it's not being used |
| 353 | if ($key > 0 && $key == $last_key && empty($item['id']) && empty($item['barcode'])) { |
| 354 | unset($node->items[$key]); |
| 355 | } |
| 356 | $row++; |
| 357 | } |
| 358 | $form_state['values'] = (array)$node; |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | /** |
| 363 | * Submit handler to add another instance of a library item to a node form. This handler is used when |
| 364 | * javascript is not available. It makes changes to the form state and the |
| 365 | * entire form is rebuilt during the page reload. |
| 366 | */ |
| 367 | function library_more_items_submit($form, &$form_state) { |
| 368 | // Set the form to rebuild and run submit handlers. |
| 369 | node_form_submit_build_node($form, $form_state); |
| 370 | |
| 371 | // Make the changes we want to the form state. |
| 372 | if ($form_state['values']['library_more']) { |
| 373 | $form_state['item_count'] = count($form_state['values']['items']) + 1; |
| 374 | } |
| 375 | } |
| 376 | |
| 377 | |
| 378 | /* |
| 379 | * Subform for an instance of a library item on node create/edit |
| 380 | */ |
| 381 | function _library_item_form($delta, $item = array()) { |
| 382 | |
| 383 | $form = array( |
| 384 | '#tree' => TRUE, |
| 385 | ); |
| 386 | |
| 387 | $form['id'] = array( |
| 388 | '#type' => 'hidden', |
| 389 | '#value' => isset($item['id']) ? $item['id'] : '', |
| 390 | '#parents' => array('items', $delta, 'id'), |
| 391 | ); |
| 392 | if (variable_get('library_item_barcodes', LIBRARY_NO_BARCODES) == LIBRARY_BARCODES) { |
| 393 | $form['barcode'] = array( |
| 394 | '#type' => 'textfield', |
| 395 | '#title' => t('Barcode'), |
| 396 | '#default_value' => isset($item['barcode']) ? $item['barcode'] : '', |
| 397 | '#required' => TRUE, |
| 398 | '#parents' => array('items', $delta, 'barcode'), |
| 399 | ); |
| 400 | } |
| 401 | $form['in_circulation'] = array( |
| 402 | '#type' => 'checkbox', |
| 403 | '#title' => t('Reference Only'), |
| 404 | '#default_value' => isset($item['in_circulation']) ? $item['in_circulation'] : LIBRARY_CIRCULATION, |
| 405 | '#return_value' => LIBRARY_REFERENCE_ONLY, |
| 406 | '#parents' => array('items', $delta, 'in_circulation'), |
| 407 | ); |
| 408 | $form['notes'] = array( |
| 409 | '#type' => 'textfield', |
| 410 | '#title' => t('Notes'), |
| 411 | '#size' => 20, |
| 412 | '#maxlength' => 128, |
| 413 | '#default_value' => isset($item['notes']) ? $item['notes'] : '', |
| 414 | '#parents' => array('items', $delta, 'notes'), |
| 415 | ); |
| 416 | if ($delta > 0) { |
| 417 | $form['delete'] = array( |
| 418 | '#type' => 'checkbox', |
| 419 | '#title' => t('Delete'), |
| 420 | '#default_value' => 0, |
| 421 | '#return_value' => 1, |
| 422 | '#parents' => array('items', $delta, 'delete'), |
| 423 | ); |
| 424 | } |
| 425 | if ($item['library_status'] == LIBRARY_ITEM_UNAVAILABLE) { |
| 426 | $form['in_circulation']['#disabled'] = TRUE; |
| 427 | } |
| 428 | |
| 429 | return $form; |
| 430 | } |
| 431 | |
| 432 | |
| 433 | /** |
| 434 | * Implementation of hook_init(). |
| 435 | */ |
| 436 | function library_init() { |
| 437 | drupal_add_css(drupal_get_path('module', 'library') .'/library.css'); |
| 438 | } |
| 439 | |
| 440 | /** |
| 441 | * Menu callback; loads a library object |
| 442 | */ |
| 443 | function library_load($item_id) { |
| 444 | if (!is_numeric($item_id)) { |
| 445 | return FALSE; |
| 446 | } |
| 447 | else { |
| 448 | $item = db_fetch_object(db_query_range("SELECT * FROM {library} l, {node} n WHERE n.nid = l.nid AND id = %d", $item_id, 0, 1)); |
| 449 | |
| 450 | if ($item->in_circulation == LIBRARY_CIRCULATION && $item->library_status == LIBRARY_ITEM_UNAVAILABLE) { |
| 451 | $last = library_get_last_transaction_by_item($item, LIBRARY_ACTION_TYPE_UNAVAILABLE); |
| 452 | if ($last) { |
| 453 | $item->last_patron_id = $last->patron_id; |
| 454 | $item->last_transaction_id = $last->tid; |
| 455 | $item->last_transaction_name = $last->action_name; |
| 456 | if (!empty($last->duedate)) { |
| 457 | $item->last_due_date = $last->duedate; |
| 458 | } |
| 459 | } |
| 460 | } |
| 461 | } |
| 462 | return $item; |
| 463 | } |
| 464 | |
| 465 | /** |
| 466 | * Implementation of hook_menu(). |
| 467 | */ |
| 468 | function library_menu() { |
| 469 | $items['library-items'] = array( |
| 470 | 'title' => 'Library', |
| 471 | 'page callback' => 'library_display_items', |
| 472 | 'access arguments' => array('access content'), |
| 473 | 'type' => MENU_SUGGESTED_ITEM, |
| 474 | 'file' => 'library.pages.inc', |
| 475 | ); |
| 476 | $items['node/%node/library/history'] = array( |
| 477 | 'title' => 'History', |
| 478 | 'page callback' => 'library_history', |
| 479 | 'page arguments' => array(1), |
| 480 | 'access callback' => 'library_history_access', |
| 481 | 'access arguments' => array(1), |
| 482 | 'type' => MENU_LOCAL_TASK, |
| 483 | 'weight' => 2, |
| 484 | 'file' => 'library.pages.inc', |
| 485 | ); |
| 486 | $items['library-items/transaction/view/%'] = array( |
| 487 | 'title' => 'View a Transaction', |
| 488 | 'page callback' => 'library_transaction_view', |
| 489 | 'page arguments' => array(3), |
| 490 | 'access arguments' => array('administer transactions'), |
| 491 | 'type' => MENU_CALLBACK, |
| 492 | 'file' => 'library.pages.inc', |
| 493 | ); |
| 494 | $items['library-items/transaction/%/%library'] = array( |
| 495 | 'title' => 'Perform a Library Transaction', |
| 496 | 'page callback' => 'drupal_get_form', |
| 497 | 'page arguments' => array('library_transaction_form', 2, 3), |
| 498 | 'access callback' => 'library_action_access', |
| 499 | 'access arguments' => array(2), |
| 500 | 'type' => MENU_CALLBACK, |
| 501 | 'file' => 'library.pages.inc', |
| 502 | ); |
| 503 | $items['library-items/overdue'] = array( |
| 504 | 'title' => 'Overdue Items', |
| 505 | 'page callback' => 'library_overdue_items', |
| 506 | 'access arguments' => array('administer transactions'), |
| 507 | 'type' => MENU_SUGGESTED_ITEM, |
| 508 | 'file' => 'library.pages.inc', |
| 509 | ); |
| 510 | $items['library-items/overdue/email'] = array( |
| 511 | 'title' => 'Email patrons with overdue items', |
| 512 | 'page callback' => 'library_notify_overdue', |
| 513 | 'access arguments' => array('administer transactions'), |
| 514 | 'type' => MENU_CALLBACK, |
| 515 | 'file' => 'library.admin.inc', |
| 516 | ); |
| 517 | |
| 518 | $items['admin/settings/library'] = array( |
| 519 | 'title' => 'Library Settings', |
| 520 | 'description' => 'Edit Library Settings.', |
| 521 | 'page callback' => 'drupal_get_form', |
| 522 | 'page arguments' => array('library_admin_settings'), |
| 523 | 'access arguments' => array('administer library'), |
| 524 | 'file' => 'library.admin.inc', |
| 525 | ); |
| 526 | $items['admin/settings/library/display'] = array( |
| 527 | 'title' => 'Display', |
| 528 | 'type' => MENU_DEFAULT_LOCAL_TASK, |
| 529 | 'weight' => -10, |
| 530 | ); |
| 531 | $items['admin/settings/library/duedates'] = array( |
| 532 | 'title' => 'Loan Periods', |
| 533 | 'description' => 'Enable loan periods for checkouts and configure overdue emails.', |
| 534 | 'page callback' => 'drupal_get_form', |
| 535 | 'page arguments' => array('library_admin_settings_overdue'), |
| 536 | 'access arguments' => array('administer library'), |
| 537 | 'file' => 'library.admin.inc', |
| 538 | 'type' => MENU_LOCAL_TASK, |
| 539 | ); |
| 540 | $items['admin/settings/library/actions'] = array( |
| 541 | 'title' => 'Library Actions', |
| 542 | 'description' => 'View, edit, or add library actions.', |
| 543 | 'page callback' => 'drupal_get_form', |
| 544 | 'page arguments' => array('library_admin_new_action'), |
| 545 | 'access arguments' => array('administer library'), |
| 546 | 'type' => MENU_LOCAL_TASK, |
| 547 | 'file' => 'library.admin.inc', |
| 548 | ); |
| 549 | $items['admin/settings/library/actions/edit'] = array( |
| 550 | 'title' => 'Edit Library Action', |
| 551 | 'page arguments' => array('library_admin_action'), |
| 552 | 'access arguments' => array('administer library'), |
| 553 | 'type' => MENU_CALLBACK, |
| 554 | 'file' => 'library.admin.inc', |
| 555 | ); |
| 556 | $items['library-items/autocomplete'] = array( |
| 557 | 'title' => t('Library Autocomplete'), |
| 558 | 'page callback' => 'library_autocomplete', |
| 559 | 'access arguments' => array('access content'), |
| 560 | 'type' => MENU_CALLBACK, |
| 561 | 'file' => 'library.admin.inc', |
| 562 | ); |
| 563 | $items['library/js'] = array( |
| 564 | 'title' => 'Javascript Add More Form', |
| 565 | 'page callback' => 'library_item_js', |
| 566 | 'access arguments' => array('access content'), |
| 567 | 'type' => MENU_CALLBACK, |
| 568 | ); |
| 569 | $items['library/title_js'] = array( |
| 570 | 'title' => 'Javascript Title Validation', |
| 571 | 'page callback' => 'library_title_js', |
| 572 | 'access arguments' => array('access content'), |
| 573 | 'type' => MENU_CALLBACK, |
| 574 | ); |
| 575 | return $items; |
| 576 | } |
| 577 | |
| 578 | /** |
| 579 | * Implementation of hook_forms(). |
| 580 | */ |
| 581 | function library_forms() { |
| 582 | $forms['library_admin_new_action']['callback'] = 'library_admin_action'; |
| 583 | return $forms; |
| 584 | } |
| 585 | |
| 586 | /** |
| 587 | * Menu callback for AHAH additions. |
| 588 | */ |
| 589 | function library_item_js() { |
| 590 | $delta = count($_POST['items']); |
| 591 | |
| 592 | $items = $_POST['items']; |
| 593 | // Build the new form. |
| 594 | $form_state = array('submitted' => FALSE); |
| 595 | $form_build_id = $_POST['form_build_id']; |
| 596 | // Add the new element to the stored form. Without adding the element to the |
| 597 | // form, Drupal is not aware of this new elements existence and will not |
| 598 | // process it. We retreive the cached form, add the element, and resave. |
| 599 | $form = form_get_cache($form_build_id, $form_state); |
| 600 | unset($form['item_wrapper']['items'], $form['item_wrapper']['library_more']); |
| 601 | foreach ($items as $key => $item) { |
| 602 | $form['item_wrapper']['items'][$key] = _library_item_form($key, $item); |
| 603 | } |
| 604 | $form['item_wrapper']['items'][$delta] = _library_item_form($delta); |
| 605 | form_set_cache($form_build_id, $form, $form_state); |
| 606 | |
| 607 | $form += array( |
| 608 | '#post' => $_POST, |
| 609 | '#programmed' => FALSE, |
| 610 | ); |
| 611 | |
| 612 | // Rebuild the form. |
| 613 | $form = form_builder($form['type']['#value'] .'_node_form', $form, $form_state); |
| 614 | |
| 615 | // Render the new output. |
| 616 | $item_form = $form['item_wrapper']['items']; |
| 617 | unset($item_form['#prefix'], $item_form['#suffix']); // Prevent duplicate wrappers. |
| 618 | $item_form['#theme'] = 'library_items_field'; |
| 619 | $item_form[$delta]['#attributes']['class'] = empty($item_form[$delta]['#attributes']['class']) ? 'ahah-new-content' : $item_form[$delta]['#attributes']['class'] .' ahah-new-content'; |
| 620 | $output = theme('status_messages') . drupal_render($item_form); |
| 621 | |
| 622 | drupal_json(array('status' => TRUE, 'data' => $output)); |
| 623 | } |
| 624 | |
| 625 | /** |
| 626 | * Menu callback for AHAH additions. |
| 627 | * Checks whether the title is unique |
| 628 | */ |
| 629 | function library_title_js() { |
| 630 | $title = $_POST['title']; |
| 631 | |
| 632 | $form_state = array('submitted' => FALSE); |
| 633 | $form_build_id = $_POST['form_build_id']; |
| 634 | $form = form_get_cache($form_build_id, $form_state); |
| 635 | |
| 636 | $nid = $form['nid']['#value']; |
| 637 | $type = $form['type']['#value']; |
| 638 | $title_label = $form['title_wrapper']['title']['#title']; |
| 639 | |
| 640 | unset($form['title_wrapper']['title']); |
| 641 | $form['title_wrapper']['title'] = array( |
| 642 | '#type' => 'textfield', |
| 643 | '#title' => check_plain($title_label), |
| 644 | '#required' => TRUE, |
| 645 | '#default_value' => $title, |
| 646 | '#maxlength' => 255, |
| 647 | '#ahah' => array( |
| 648 | 'path' => 'library/title_js', |
| 649 | 'wrapper' => 'title-wrapper', |
| 650 | ), |
| 651 | '#weight' => -5, |
| 652 | ); |
| 653 | |
| 654 | form_set_cache($form_build_id, $form, $form_state); |
| 655 | |
| 656 | $form += array( |
| 657 | '#post' => $_POST, |
| 658 | '#programmed' => FALSE, |
| 659 | ); |
| 660 | |
| 661 | // Rebuild the form. |
| 662 | $form = form_builder($form['type']['#value'] .'_node_form', $form, $form_state); |
| 663 | $title_field = $form['title_wrapper']['title']; |
| 664 | |
| 665 | if (is_numeric($nid)) { |
| 666 | $repeats = db_fetch_object(db_query_range("SELECT nid FROM {node} WHERE title = '%s' AND type = '%s' and nid <> %d", check_plain($title), $type, $nid, 0, 1)); |
| 667 | } |
| 668 | else { |
| 669 | $repeats = db_fetch_object(db_query_range("SELECT nid FROM {node} WHERE title = '%s' AND type = '%s'", $title, $type, 0, 1)); |
| 670 | } |
| 671 | if ($repeats) { |
| 672 | drupal_json(array('status' => TRUE, 'data' => drupal_render($title_field) .'<p class="ahah-new-content warning">WARNING: Title is not unique. You may want to add this as a copy to the existing node. '. l('See Duplicate', 'node/'. $repeats->nid) .'</p>')); |
| 673 | } |
| 674 | else { |
| 675 | drupal_json(array('status' => TRUE, 'data' => drupal_render($title_field) .'<p class="ahah-new-content ok">Title is unique.</p>')); |
| 676 | } |
| 677 | } |
| 678 | |
| 679 | /** |
| 680 | * Implementation of hook_search() |
| 681 | */ |
| 682 | function library_search($op = 'search', $keys = NULL, $skip_access_check = FALSE) { |
| 683 | switch ($op) { |
| 684 | case 'name': |
| 685 | return t('Library'); |
| 686 | case 'search': |
| 687 | // Build matching conditions |
| 688 | list($join1, $where1) = _db_rewrite_sql(); |
| 689 | $arguments1 = array(); |
| 690 | $conditions1 = 'n.status = 1'; |
| 691 | |
| 692 | if ($type = search_query_extract($keys, 'type')) { |
| 693 | $types = array(); |
| 694 | foreach (explode(',', $type) as $t) { |
| 695 | $types[] = "n.type = '%s'"; |
| 696 | $arguments1[] = $t; |
| 697 | } |
| 698 | $conditions1 .= ' AND ('. implode(' OR ', $types) .')'; |
| 699 | $keys = search_query_insert($keys, 'type'); |
| 700 | } |
| 701 | else { |
| 702 | $types = array(); |
| 703 | |
| 704 | foreach (library_get_item_types() as $t) { |
| 705 | $types[] = "n.type = '%s'"; |
| 706 | $arguments1[] = $t; |
| 707 | } |
| 708 | $conditions1 .= ' AND ('. implode(' OR ', $types) .')'; |
| 709 | $keys = search_query_insert($keys, 'type'); |
| 710 | } |
| 711 | |
| 712 | if ($category = search_query_extract($keys, 'category')) { |
| 713 | $categories = array(); |
| 714 | foreach (explode(',', $category) as $c) { |
| 715 | $categories[] = "tn.tid = %d"; |
| 716 | $arguments1[] = $c; |
| 717 | } |
| 718 | $conditions1 .= ' AND ('. implode(' OR ', $categories) .')'; |
| 719 | $join1 .= ' INNER JOIN {term_node} tn ON n.vid = tn.vid'; |
| 720 | $keys = search_query_insert($keys, 'category'); |
| 721 | } |
| 722 | // Build ranking expression (we try to map each parameter to a |
| 723 | // uniform distribution in the range 0..1). |
| 724 | $ranking = array(); |
| 725 | $arguments2 = array(); |
| 726 | $join2 = ''; |
| 727 | // Used to avoid joining on node_comment_statistics twice |
| 728 | $stats_join = FALSE; |
| 729 | $total = 0; |
| 730 | if ($weight = (int)variable_get('node_rank_relevance', 5)) { |
| 731 | // Average relevance values hover around 0.15 |
| 732 | $ranking[] = '%d * i.relevance'; |
| 733 | $arguments2[] = $weight; |
| 734 | $total += $weight; |
| 735 | } |
| 736 | if (module_exists('statistics') && variable_get('statistics_count_content_views', 0) && |
| 737 | $weight = (int)variable_get('node_rank_views', 5)) { |
| 738 | // Inverse law that maps the highest view count on the site to 1 and 0 to 0. |
| 739 | $scale = variable_get('node_cron_views_scale', 0.0); |
| 740 | $ranking[] = '%d * (2.0 - 2.0 / (1.0 + MAX(nc.totalcount) * %f))'; |
| 741 | $arguments2[] = $weight; |
| 742 | $arguments2[] = $scale; |
| 743 | $join2 .= ' LEFT JOIN {node_counter} nc ON nc.nid = i.sid'; |
| 744 | $total += $weight; |
| 745 | } |
| 746 | |
| 747 | // When all search factors are disabled (ie they have a weight of zero), |
| 748 | // the default score is based only on keyword relevance and there is no need to |
| 749 | // adjust the score of each item. |
| 750 | if ($total == 0) { |
| 751 | $select2 = 'i.relevance AS score'; |
| 752 | $total = 1; |
| 753 | } |
| 754 | else { |
| 755 | $select2 = implode(' + ', $ranking) .' AS score'; |
| 756 | } |
| 757 | |
| 758 | // Do search. |
| 759 | $find = do_search($keys, 'node', 'INNER JOIN {node} n ON n.nid = i.sid '. $join1, $conditions1 . (empty($where1) ? '' : ' AND '. $where1), $arguments1, $select2, $join2, $arguments2, 'ORDER BY n.title, score DESC'); |
| 760 | |
| 761 | // Load results. |
| 762 | $results = array(); |
| 763 | $var = array(); |
| 764 | $var = library_get_table_header(); |
| 765 | foreach ($find as $item) { |
| 766 | // Build the node body. |
| 767 | $node = node_load($item->sid); |
| 768 | $node_rows = array(); |
| 769 | |
| 770 | $node_rows = library_get_table_row($node, $var); |
| 771 | foreach ($node_rows as $row) { |
| 772 | $results[] = $row; |
| 773 | } |
| 774 | |
| 775 | } |
| 776 | return $results; |
| 777 | } |
| 778 | } |
| 779 | |
| 780 | /** |
| 781 | * Implementation of hook_search_page() |
| 782 | */ |
| 783 | function library_search_page($results) { |
| 784 | $var = library_get_table_header(); |
| 785 | |
| 786 | $header = $var['header']; |
| 787 | $rows = $results; |
| 788 | |
| 789 | $output = theme('table', $header, $rows, array('class' => 'library-list')); |
| 790 | $output .= theme('pager', NULL, 10); |
| 791 | return $output; |
| 792 | } |
| 793 | |
| 794 | /** |
| 795 | * Implementation of hook_nodeapi() |
| 796 | */ |
| 797 | function library_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { |
| 798 | if (library_item_in_library($node)) { |
| 799 | switch ($op) { |
| 800 | case 'load': |
| 801 | $result = array(); |
| 802 | $result = library_load_items($node); |
| 803 | return $result; |
| 804 | break; |
| 805 | |
| 806 | case 'validate': |
| 807 | case 'submit': |
| 808 | $node = library_validate_items($node); |
| 809 | break; |
| 810 | |
| 811 | case 'insert': |
| 812 | case 'update': |
| 813 | library_update_items($node); |
| 814 | break; |
| 815 | |
| 816 | case 'delete': |
| 817 | db_query('DELETE FROM {library} WHERE nid = %d', $node->nid); |
| 818 | break; |
| 819 | |
| 820 | case 'view': |
| 821 | $item_weight = -4; |
| 822 | if (module_exists('content')) { |
| 823 | foreach (variable_get('content_extra_weights_'. $node->type, array()) as $key => $value) { |
| 824 | if ($key == 'item_wrapper') { |
| 825 | $item_weight = $value; |
| 826 | } |
| 827 | } |
| 828 | } |
| 829 | $node->content['items'] = array( |
| 830 | '#value' => theme('library_items', $node), |
| 831 | '#weight' => $item_weight, |
| 832 | ); |
| 833 | break; |
| 834 | } |
| 835 | } |
| 836 | } |
| 837 | |
| 838 | /** |
| 839 | * Load Library Item Data for a given node |
| 840 | */ |
| 841 | function library_load_items($node) { |
| 842 | $result = db_query('SELECT id FROM {library} WHERE nid = %d ORDER BY id', $node->nid); |
| 843 | $items = array(); |
| 844 | $row = 0; |
| 845 | if ($result) { |
| 846 | while ($item = db_fetch_object($result)) { |
| 847 | $library_item = library_load($item->id); |
| 848 | $items[$row]['library_status'] = ($library_item->library_status ? $library_item->library_status : LIBRARY_ITEM_AVAILABLE); |
| 849 | $items[$row]['last_patron_id'] = ($library_item->last_patron_id ? $library_item->last_patron_id : ''); |
| 850 | $items[$row]['last_due_date'] = ($library_item->last_due_date ? $library_item->last_due_date : ''); |
| 851 | $items[$row]['last_transaction_id'] = ($library_item->last_transaction_id ? $library_item->last_transaction_id : ''); |
| 852 | $items[$row]['last_transaction_name'] = ($library_item->last_transaction_name ? $library_item->last_transaction_name : ''); |
| 853 | $items[$row]['id'] = $item->id; |
| 854 | $items[$row]['in_circulation'] = $library_item->in_circulation; |
| 855 | $items[$row]['barcode'] = check_plain($library_item->barcode); |
| 856 | $items[$row]['notes'] = check_plain($library_item->notes); |
| 857 | $row++; |
| 858 | } |
| 859 | } |
| 860 | else { |
| 861 | db_query('INSERT INTO {library} (nid, in_circulation, library_status, created) VALUES (%d, %d, %d, %d)', $node->nid, LIBRARY_CIRCULATION, LIBRARY_ITEM_AVAILABLE, time()); |
| 862 | $items[$row]['id'] = db_last_insert_id('library', 'id'); |
| 863 | $items[$row]['in_circulation'] = LIBRARY_CIRCULATION; |
| 864 | $items[$row]['library_status'] = LIBRARY_ITEM_AVAILABLE; |
| 865 | } |
| 866 | return array('items' => $items); |
| 867 | } |
| 868 | |
| 869 | /** |
| 870 | * Update Library Item Data for a given node |
| 871 | */ |
| 872 | function library_update_items($node) { |
| 873 | $items = $node->items; |
| 874 | $row = 0; |
| 875 | if ($items) { |
| 876 | foreach ($items as $key => $item) { |
| 877 | if ($item['delete'] == 1) { |
| 878 | db_query('DELETE FROM {library} WHERE id = %d', $item['id']); |
| 879 | unset($node->items[$key]); |
| 880 | } |
| 881 | else if (empty($item['id'])) { |
| 882 | db_query("INSERT INTO {library} (nid, barcode, in_circulation, library_status, notes, created) VALUES (%d, '%s', %d, %d, '%s', %d)", $node->nid, check_plain($item['barcode'] .''), $item['in_circulation'], LIBRARY_ITEM_AVAILABLE, $item['notes'], time()); |
| 883 | $node->items[$row]['id'] = db_last_insert_id('library', 'id'); |
| 884 | } |
| 885 | else { |
| 886 | db_query("UPDATE {library} SET barcode = '%s', in_circulation = %d, notes = '%s' WHERE id = %d", check_plain($item['barcode'] .''), $item['in_circulation'], check_plain($item['notes']), $item['id']); |
| 887 | } |
| 888 | |
| 889 | $row++; |
| 890 | } |
| 891 | } |
| 892 | } |
| 893 | |
| 894 | /** |
| 895 | * Validate Library Item Data for a given node |
| 896 | */ |
| 897 | function library_validate_items($node) { |
| 898 | if (variable_get('library_item_barcodes', LIBRARY_NO_BARCODES) == LIBRARY_BARCODES) { |
| 899 | $items = $node->items; |
| 900 | if ($items) { |
| 901 | global $base_path; |
| 902 | //Check that each barcode is unique |
| 903 | foreach ($items as $key => $item) { |
| 904 | $result = db_result(db_query("SELECT COUNT(*) FROM {library} WHERE barcode = '%s' AND barcode <> ''", $item['barcode'])); |
| 905 | if ((empty($item['id']) && $result) || (!empty($item['id']) && $result > 1)) { |
| 906 | form_set_error('items]['. $key .'][barcode', t('The barcode %barcode already exists. Please enter a different barcode.', array('%barcode' => $item['barcode']))); |
| 907 | } |
| 908 | } |
| 909 | } |
| 910 | else { |
| 911 | form_set_error('items', t('You must enter information for at least one item.')); |
| 912 | } |
| 913 | } |
| 914 | } |
| 915 | |
| 916 | /** |
| 917 | * Check whether a given item (based on its item type) is part of the library |
| 918 | * @returns Boolean |
| 919 | */ |
| 920 | function library_item_in_library($node = NULL, $item_id = NULL) { |
| 921 | if ($node && variable_get('library_'. $node->type, LIBRARY_ITEM_NOT_IN_LIBRARY) == LIBRARY_ITEM_IN_LIBRARY) { |
| 922 | return TRUE; |
| 923 | } |
| 924 | else if ($item_id && db_result(db_query("SELECT COUNT(*) FROM {library} WHERE id = %d", $item_id))) { |
| 925 | return TRUE; |
| 926 | } |
| 927 | else { |
| 928 | return FALSE; |
| 929 | } |
| 930 | } |
| 931 | |
| 932 | /** |
| 933 | * Returns a list of overdue library items |
| 934 | */ |
| 935 | function library_get_overdue_items() { |
| 936 | //Select all the nodes that have ever had an item made unavailable |
| 937 | $items = db_query("SELECT id FROM {library} WHERE library_status = %d", LIBRARY_ITEM_UNAVAILABLE); |
| 938 | $overdueitems = array(); |
| 939 | while ($result = db_fetch_object($items)) { |
| 940 | $item = library_load($result->id); |
| 941 | if (!empty($item->last_patron_id) && !empty($item->last_due_date) && (time() > $item->last_due_date)) { |
| 942 | $patron = node_load($item->last_patron_id); |
| 943 | if (!isset($overdueitems[$item->last_patron_id]['patron']['patron_email'])) { |
| 944 | $overdueitems[$item->last_patron_id]['patron']['patron_email'] = $patron->email; |
| 945 | $overdueitems[$item->last_patron_id]['patron']['patron_name'] = $patron->name_first .' '. $patron->name_last; |
| 946 | } |
| 947 | $overdueitems[$item->last_patron_id]['items'][$item->id] = array('item_name' => $item->title, 'nid' => $item->nid, 'due_date' => $item->last_due_date, 'in_circulation' => $item->in_circulation); |
| 948 | } |
| 949 | } |
| 950 | return $overdueitems; |
| 951 | } |
| 952 | |
| 953 | /** |
| 954 | * Get the due date given a check out date |
| 955 | * |
| 956 | * @param $checkout_date |
| 957 | * The date an item was made unavailable |
| 958 | * @param $action |
| 959 | * The clean name of the action performed |
| 960 | * @param $type |
| 961 | * The node type |
| 962 | * @returns a UNIX TIMESTAMP if due dates are enabled else it returns NULL |
| 963 | */ |
| 964 | function library_get_due_date($checkout_date = NULL, $action, $type) { |
| 965 | if (empty($checkout_date)) { |
| 966 | $checkout_date = time(); |
| 967 | } |
| 968 | $allowed = variable_get('library_period_for_'. $type .'_'. $action, 0); |
| 969 | if ($allowed > 0) { |
| 970 | return ($checkout_date + $allowed); |
| 971 | } |
| 972 | else { |
| 973 | return NULL; |
| 974 | } |
| 975 | } |
| 976 | |
| 977 | /** |
| 978 | * Check to see if due dates are enabled for any actions |
| 979 | * |
| 980 | * @returns BOOLEAN |
| 981 | */ |
| 982 | function library_duedates_enabled($type = NULL) { |
| 983 | if (is_null($type)) { |
| 984 | $duedates = 0; |
| 985 | foreach (library_get_item_types() as $type) { |
| 986 | if ($duedates == 0) { |
| 987 | $duedates = variable_get('library_'. $type .'_due_dates', 0); |
| 988 | if ($duedates > 0) { |
| 989 | return TRUE; |
| 990 | } |
| 991 | } |
| 992 | else { |
| 993 | return TRUE; |
| 994 | } |
| 995 | } |
| 996 | return FALSE; |
| 997 | } |
| 998 | else { |
| 999 | $duedates = variable_get('library_'. $type .'_due_dates', 0); |
| 1000 | return ($duedates > 0); |
| 1001 | } |
| 1002 | } |
| 1003 | |
| 1004 | function library_get_transactions_by_item($item) { |
| 1005 | $result = db_query('SELECT lt.created, lt.tid, la.aid, la.name as "action_name", |
| 1006 | la.status_change, lt.patron_id, lt.item_id, lt.duedate, lt.notes, l.in_circulation, l.barcode, n.title as "item_name", n.nid |
| 1007 | FROM {library_transactions} lt, {library_actions} la, {library} l, {node} n |
| 1008 | WHERE la.aid = lt.action_aid AND n.nid = l.nid AND lt.item_id = l.id AND l.id = %d |
| 1009 | ORDER BY lt.created DESC', $item->id); |
| 1010 | while ($transaction = db_fetch_object($result)) { |
| 1011 | $transaction->library_status = isset($item->library_status) ? $item->library_status : LIBRARY_ITEM_AVAILABLE; |
| 1012 | $transactions[] = $transaction; |
| 1013 | } |
| 1014 | if (!empty($transactions)) { |
| 1015 | return $transactions; |
| 1016 | } |
| 1017 | else { |
| 1018 | return NULL; |
| 1019 | } |
| 1020 | } |
| 1021 | |
| 1022 | function library_get_transactions_by_node($node) { |
| 1023 | if ($node->type == 'patron') { |
| 1024 | $temp_transactions = library_get_transactions_by_patron($node); |
| 1025 | if (!empty($temp_transactions)) { |
| 1026 | $transactions[] = $temp_transactions; |
| 1027 | } |
| 1028 | } |
| 1029 | else { |
| 1030 | foreach ($node->items as $instance) { |
| 1031 | $item = (object) $instance; |
| 1032 | $temp_transactions = library_get_transactions_by_item($item); |
| 1033 | if (!empty($temp_transactions)) { |
| 1034 | $transactions[] = library_get_transactions_by_item($item); |
| 1035 | } |
| 1036 | } |
| 1037 | } |
| 1038 | return $transactions; |
| 1039 | } |
| 1040 | |
| 1041 | function library_get_transactions_by_patron($node) { |
| 1042 | $result = db_query('SELECT lt.created, lt.tid, la.aid, la.name as "action_name", la.status_change, lt.patron_id, lt.item_id, lt.duedate, lt.notes, n.title as "item_name", n.nid FROM {library_transactions} lt, {library_actions} la, {node} n WHERE la.aid = lt.action_aid AND n.nid = lt.nid AND lt.patron_id = %d ORDER BY lt.created DESC', $node->nid); |
| 1043 | |
| 1044 | $items_result = db_query('SELECT DISTINCT item_id FROM {library_transactions} WHERE patron_id = %d', $node->nid); |
| 1045 | $statuses = array(); |
| 1046 | $barcodes = array(); |
| 1047 | $circulation = array(); |
| 1048 | while ($instance = db_fetch_object($items_result)) { |
| 1049 | $item = library_load($instance->item_id); |
| 1050 | $barcodes[$item->id] = $item->barcode; |
| 1051 | $statuses[$item->id] = $item->library_status; |
| 1052 | $circulation[$item->id] = $item->in_circulation; |
| 1053 | } |
| 1054 | $transactions = array(); |
| 1055 | while ($transaction = db_fetch_object($result)) { |
| 1056 | $transaction->library_status = $statuses[$transaction->item_id]; |
| 1057 | $transaction->barcode = $barcodes[$transaction->item_id]; |
| 1058 | $transaction->in_circulation = $circulation[$transaction->item_id]; |
| 1059 | $transactions[] = $transaction; |
| 1060 | } |
| 1061 | if (!empty($transactions)) { |
| 1062 | return $transactions; |
| 1063 | } |
| 1064 | else { |
| 1065 | return NULL; |
| 1066 | } |
| 1067 | } |
| 1068 | |
| 1069 | function library_get_transaction_by_tid($tid) { |
| 1070 | if (isset($tid) && is_numeric($tid)) { |
| 1071 | $result = db_fetch_object(db_query('SELECT lt.created, la.name as "action_name", la.status_change, lp.nid as "patron_id", lp.name_last, lp.name_first, n.title as "item_name", n.type as "item_type", lt.item_id as "item_id", lt.nid as "nid", lt.duedate, lt.notes FROM {library_transactions} lt, {library_actions} la, {library_patrons} lp, {node} n WHERE la.aid = lt.action_aid AND lp.nid = lt.patron_id AND n.nid = lt.nid AND lt.tid = %d', $tid)); |
| 1072 | return $result; |
| 1073 | } |
| 1074 | else { |
| 1075 | return NULL; |
| 1076 | } |
| 1077 | } |
| 1078 | |
| 1079 | /** |
| 1080 | * @param $node |
| 1081 | * Node object or array |
| 1082 | * @param $transaction_type |
| 1083 | * (optional) Type of transaction to return |
| 1084 | * @return |
| 1085 | * Transaction array or NULL if none found |
| 1086 | */ |
| 1087 | function library_get_last_transaction_by_item($item, $type = NULL) { |
| 1088 | $transactions = library_get_transactions_by_item($item); |
| 1089 | if (isset($transactions)) { |
| 1090 | foreach ($transactions as $transaction) { |
| 1091 | if ($type && $type == $transaction->status_change) { |
| 1092 | return $transaction; |