1 package C4
::CourseReserves
;
3 # This file is part of Koha.
5 # Koha is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # Koha is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with Koha; if not, see <http://www.gnu.org/licenses>.
20 use List
::MoreUtils
qw(any);
23 use C4
::Circulation
qw(GetOpenIssue);
25 use vars
qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG @FIELDS);
49 &GetItemCourseReservesInfo
51 %EXPORT_TAGS = ( 'all' => \
@EXPORT_OK );
54 @FIELDS = ( 'itype', 'ccode', 'holdingbranch', 'location' );
59 C4::CourseReserves - Koha course reserves module
63 use C4::CourseReserves;
67 This module deals with course reserves.
73 $course = GetCourse( $course_id );
79 warn whoami
() . "( $course_id )" if $DEBUG;
81 my $query = "SELECT * FROM courses WHERE course_id = ?";
82 my $dbh = C4
::Context
->dbh;
83 my $sth = $dbh->prepare($query);
84 $sth->execute($course_id);
86 my $course = $sth->fetchrow_hashref();
89 SELECT b.* FROM course_instructors ci
90 LEFT JOIN borrowers b ON ( ci.borrowernumber = b.borrowernumber )
93 $sth = $dbh->prepare($query);
94 $sth->execute($course_id);
95 $course->{'instructors'} = $sth->fetchall_arrayref( {} );
102 ModCourse( [ course_id => $id ] [, course_name => $course_name ] [etc...] );
108 warn identify_myself
(%params) if $DEBUG;
110 my $dbh = C4
::Context
->dbh;
113 if ( defined $params{'course_id'} ) {
114 $course_id = $params{'course_id'};
115 delete $params{'course_id'};
123 $query .= ($course_id) ?
' UPDATE ' : ' INSERT ';
124 $query .= ' courses SET ';
126 foreach my $key ( keys %params ) {
127 push( @query_keys, "$key=?" );
128 push( @query_values, $params{$key} );
130 $query .= join( ',', @query_keys );
133 $query .= " WHERE course_id = ?";
134 push( @query_values, $course_id );
137 $dbh->do( $query, undef, @query_values );
139 $course_id = $course_id
140 || $dbh->last_insert_id( undef, undef, 'courses', 'course_id' );
142 EnableOrDisableCourseItems
(
143 course_id
=> $course_id,
144 enabled
=> $params{'enabled'}
152 @courses = GetCourses( [ fieldname => $value ] [, fieldname2 => $value2 ] [etc...] );
158 warn identify_myself
(%params) if $DEBUG;
164 SELECT c.course_id, c.department, c.course_number, c.section, c.course_name, c.term, c.staff_note, c.public_note, c.students_count, c.enabled, c.timestamp
166 LEFT JOIN course_reserves ON course_reserves.course_id = c.course_id
167 LEFT JOIN course_items ON course_items.ci_id = course_reserves.ci_id
170 if ( keys %params ) {
174 foreach my $key ( keys %params ) {
175 push( @query_keys, " $key LIKE ? " );
176 push( @query_values, $params{$key} );
179 $query .= join( ' AND ', @query_keys );
182 $query .= " GROUP BY c.course_id, c.department, c.course_number, c.section, c.course_name, c.term, c.staff_note, c.public_note, c.students_count, c.enabled, c.timestamp ";
184 my $dbh = C4
::Context
->dbh;
185 my $sth = $dbh->prepare($query);
186 $sth->execute(@query_values);
188 my $courses = $sth->fetchall_arrayref( {} );
190 foreach my $c (@
$courses) {
191 $c->{'instructors'} = GetCourseInstructors
( $c->{'course_id'} );
199 DelCourse( $course_id );
204 my ($course_id) = @_;
206 my $course_reserves = GetCourseReserves
( course_id
=> $course_id );
208 foreach my $res (@
$course_reserves) {
209 DelCourseReserve
( cr_id
=> $res->{'cr_id'} );
213 DELETE FROM course_instructors
216 C4
::Context
->dbh->do( $query, undef, $course_id );
222 C4
::Context
->dbh->do( $query, undef, $course_id );
225 =head2 EnableOrDisableCourseItems
227 EnableOrDisableCourseItems( course_id => $course_id, enabled => $enabled );
229 For each item on reserve for this course,
230 if the course item has no active course reserves,
231 swap the fields for the item to make it 'normal'
234 enabled => 'yes' to enable course items
235 enabled => 'no' to disable course items
239 sub EnableOrDisableCourseItems
{
241 warn identify_myself
(%params) if $DEBUG;
243 my $course_id = $params{'course_id'};
244 my $enabled = $params{'enabled'} || 0;
246 my $lookfor = ( $enabled eq 'yes' ) ?
'no' : 'yes';
248 return unless ( $course_id && $enabled );
249 return unless ( $enabled eq 'yes' || $enabled eq 'no' );
251 my $course_reserves = GetCourseReserves
( course_id
=> $course_id );
253 if ( $enabled eq 'yes' ) {
254 foreach my $course_reserve (@
$course_reserves) {
255 if (CountCourseReservesForItem
(
256 ci_id
=> $course_reserve->{'ci_id'},
260 EnableOrDisableCourseItem
(
261 ci_id
=> $course_reserve->{'ci_id'},
266 if ( $enabled eq 'no' ) {
267 foreach my $course_reserve (@
$course_reserves) {
269 CountCourseReservesForItem
(
270 ci_id
=> $course_reserve->{'ci_id'},
274 EnableOrDisableCourseItem
(
275 ci_id
=> $course_reserve->{'ci_id'},
282 =head2 EnableOrDisableCourseItem
284 EnableOrDisableCourseItem( ci_id => $ci_id );
288 sub EnableOrDisableCourseItem
{
290 warn identify_myself
(%params) if $DEBUG;
292 my $ci_id = $params{'ci_id'};
294 return unless ( $ci_id );
296 my $course_item = GetCourseItem
( ci_id
=> $ci_id );
298 my $info = GetItemCourseReservesInfo
( itemnumber
=> $course_item->{itemnumber
} );
300 my $enabled = any
{ $_->{course
}->{enabled
} eq 'yes' } @
$info;
301 $enabled = $enabled ?
'yes' : 'no';
303 ## We don't want to 'enable' an already enabled item,
304 ## or disable and already disabled item,
305 ## as that would cause the fields to swap
306 if ( $course_item->{'enabled'} ne $enabled ) {
307 _SwapAllFields
($ci_id);
315 C4
::Context
->dbh->do( $query, undef, $enabled, $ci_id );
321 =head2 GetCourseInstructors
323 @$borrowers = GetCourseInstructors( $course_id );
327 sub GetCourseInstructors
{
328 my ($course_id) = @_;
329 warn "C4::CourseReserves::GetCourseInstructors( $course_id )"
333 SELECT * FROM borrowers
334 RIGHT JOIN course_instructors ON ( course_instructors.borrowernumber = borrowers.borrowernumber )
335 WHERE course_instructors.course_id = ?
338 my $dbh = C4
::Context
->dbh;
339 my $sth = $dbh->prepare($query);
340 $sth->execute($course_id);
342 return $sth->fetchall_arrayref( {} );
345 =head2 ModCourseInstructors
347 ModCourseInstructors( mode => $mode, course_id => $course_id, [ cardnumbers => $cardnumbers ] OR [ borrowernumbers => $borrowernumbers );
349 $mode can be 'replace', 'add', or 'delete'
351 $cardnumbers and $borrowernumbers are both references to arrays
353 Use either cardnumbers or borrowernumber, but not both.
357 sub ModCourseInstructors
{
359 warn identify_myself
(%params) if $DEBUG;
361 my $course_id = $params{'course_id'};
362 my $mode = $params{'mode'};
363 my $cardnumbers = $params{'cardnumbers'};
364 my $borrowernumbers = $params{'borrowernumbers'};
366 return unless ($course_id);
368 unless ( $mode eq 'replace'
370 || $mode eq 'delete' );
371 return unless ( $cardnumbers || $borrowernumbers );
372 return if ( $cardnumbers && $borrowernumbers );
374 my ( @cardnumbers, @borrowernumbers );
375 @cardnumbers = @
$cardnumbers if ( ref($cardnumbers) eq 'ARRAY' );
376 @borrowernumbers = @
$borrowernumbers
377 if ( ref($borrowernumbers) eq 'ARRAY' );
379 my $field = (@cardnumbers) ?
'cardnumber' : 'borrowernumber';
380 my @fields = (@cardnumbers) ?
@cardnumbers : @borrowernumbers;
381 my $placeholders = join( ',', ('?') x
scalar @fields );
383 my $dbh = C4
::Context
->dbh;
385 $dbh->do( "DELETE FROM course_instructors WHERE course_id = ?", undef, $course_id )
386 if ( $mode eq 'replace' );
390 if ( $mode eq 'add' || $mode eq 'replace' ) {
392 INSERT INTO course_instructors ( course_id, borrowernumber )
393 SELECT ?, borrowernumber
395 WHERE $field IN ( $placeholders )
399 DELETE FROM course_instructors
401 AND borrowernumber IN (
402 SELECT borrowernumber FROM borrowers WHERE $field IN ( $placeholders )
407 my $sth = $dbh->prepare($query);
409 $sth->execute( $course_id, @fields ) if (@fields);
412 =head2 GetCourseItem {
414 $course_item = GetCourseItem( itemnumber => $itemnumber [, ci_id => $ci_id );
420 warn identify_myself
(%params) if $DEBUG;
422 my $ci_id = $params{'ci_id'};
423 my $itemnumber = $params{'itemnumber'};
425 return unless ( $itemnumber || $ci_id );
427 my $field = ($itemnumber) ?
'itemnumber' : 'ci_id';
428 my $value = ($itemnumber) ?
$itemnumber : $ci_id;
430 my $query = "SELECT * FROM course_items WHERE $field = ?";
431 my $dbh = C4
::Context
->dbh;
432 my $sth = $dbh->prepare($query);
433 $sth->execute($value);
435 my $course_item = $sth->fetchrow_hashref();
438 $query = "SELECT * FROM course_reserves WHERE ci_id = ?";
439 $sth = $dbh->prepare($query);
440 $sth->execute( $course_item->{'ci_id'} );
441 my $course_reserves = $sth->fetchall_arrayref( {} );
443 $course_item->{'course_reserves'} = $course_reserves
444 if ($course_reserves);
449 =head2 ModCourseItem {
451 ModCourseItem( %params );
453 Creates or modifies an existing course item.
459 warn identify_myself
(%params) if $DEBUG;
461 my $itemnumber = $params{'itemnumber'};
463 return unless ($itemnumber);
465 my $course_item = GetCourseItem
( itemnumber
=> $itemnumber );
470 $ci_id = $course_item->{'ci_id'};
474 course_item
=> $course_item,
478 $ci_id = _AddCourseItem
(%params);
485 =head2 _AddCourseItem
487 my $ci_id = _AddCourseItem( %params );
493 warn identify_myself
(%params) if $DEBUG;
495 my ( @fields, @values );
497 push( @fields, 'itemnumber = ?' );
498 push( @values, $params{'itemnumber'} );
501 push( @fields, "$_ = ?" );
502 push( @values, $params{$_} || undef );
505 my $query = "INSERT INTO course_items SET " . join( ',', @fields );
506 my $dbh = C4
::Context
->dbh;
507 $dbh->do( $query, undef, @values );
509 my $ci_id = $dbh->last_insert_id( undef, undef, 'course_items', 'ci_id' );
514 =head2 _UpdateCourseItem
516 _UpdateCourseItem( %params );
520 sub _UpdateCourseItem
{
522 warn identify_myself
(%params) if $DEBUG;
524 my $ci_id = $params{'ci_id'};
525 my $course_item = $params{'course_item'};
527 return unless ( $ci_id || $course_item );
529 $course_item = GetCourseItem
( ci_id
=> $ci_id )
530 unless ($course_item);
531 $ci_id = $course_item->{'ci_id'} unless ($ci_id);
535 defined $params{$_} && $params{$_} ne ''
536 ?
( $_ => $params{$_} )
540 Koha
::Items
->find( $course_item->{itemnumber
} )
541 ->set( \
%mod_params )
545 =head2 _ModStoredFields
547 _ModStoredFields( %params );
549 Updates the values for the 'original' fields in course_items
554 sub _ModStoredFields
{
556 warn identify_myself
(%params) if $DEBUG;
558 return unless ( $params{'ci_id'} );
560 my ( @fields_to_update, @values_to_update );
563 if ( defined($params{$_}) ) {
564 push( @fields_to_update, $_ );
565 push( @values_to_update, $params{$_} );
569 my $query = "UPDATE course_items SET " . join( ',', map { "$_=?" } @fields_to_update ) . " WHERE ci_id = ?";
571 C4
::Context
->dbh->do( $query, undef, @values_to_update, $params{'ci_id'} )
572 if (@values_to_update);
578 _RevertFields( ci_id => $ci_id, fields => \@fields_to_revert );
584 warn identify_myself
(%params) if $DEBUG;
586 my $ci_id = $params{'ci_id'};
588 return unless ($ci_id);
590 my $course_item = GetCourseItem
( ci_id
=> $params{'ci_id'} );
591 my $course_item_object = Koha
::Items
->find($course_item->{'itemnumber'});
592 foreach my $field ( @FIELDS ) {
593 next unless defined $course_item->{$field};
594 $course_item_object->$field($course_item->{$field});
596 $course_item_object->store;
599 =head2 _SwapAllFields
601 _SwapAllFields( $ci_id );
607 warn "C4::CourseReserves::_SwapFields( $ci_id )" if $DEBUG;
609 my $course_item = GetCourseItem
( ci_id
=> $ci_id );
610 my $item = Koha
::Items
->find($course_item->{'itemnumber'});
614 if ( defined( $course_item->{$_} ) ) {
615 $item_fields{$_} = $item->$_ || q{};
616 $item->$_($course_item->{$_});
620 _ModStoredFields
( %item_fields, ci_id
=> $ci_id );
623 =head2 GetCourseItems {
625 $course_items = GetCourseItems(
626 [course_id => $course_id]
627 [, itemnumber => $itemnumber ]
634 warn identify_myself
(%params) if $DEBUG;
636 my $course_id = $params{'course_id'};
637 my $itemnumber = $params{'itemnumber'};
639 return unless ($course_id);
644 my $query = "SELECT * FROM course_items";
646 if ( keys %params ) {
650 foreach my $key ( keys %params ) {
651 push( @query_keys, " $key LIKE ? " );
652 push( @query_values, $params{$key} );
655 $query .= join( ' AND ', @query_keys );
658 my $dbh = C4
::Context
->dbh;
659 my $sth = $dbh->prepare($query);
660 $sth->execute(@query_values);
662 return $sth->fetchall_arrayref( {} );
665 =head2 DelCourseItem {
667 DelCourseItem( ci_id => $cr_id );
673 warn identify_myself
(%params) if $DEBUG;
675 my $ci_id = $params{'ci_id'};
677 return unless ($ci_id);
679 _RevertFields
( ci_id
=> $ci_id );
682 DELETE FROM course_items
685 C4
::Context
->dbh->do( $query, undef, $ci_id );
688 =head2 GetCourseReserve {
690 $course_item = GetCourseReserve( %params );
694 sub GetCourseReserve
{
696 warn identify_myself
(%params) if $DEBUG;
698 my $cr_id = $params{'cr_id'};
699 my $course_id = $params{'course_id'};
700 my $ci_id = $params{'ci_id'};
702 return unless ( $cr_id || ( $course_id && $ci_id ) );
704 my $dbh = C4
::Context
->dbh;
709 SELECT * FROM course_reserves
712 $sth = $dbh->prepare($query);
713 $sth->execute($cr_id);
716 SELECT * FROM course_reserves
717 WHERE course_id = ? AND ci_id = ?
719 $sth = $dbh->prepare($query);
720 $sth->execute( $course_id, $ci_id );
723 my $course_reserve = $sth->fetchrow_hashref();
724 return $course_reserve;
727 =head2 ModCourseReserve
729 $id = ModCourseReserve( %params );
733 sub ModCourseReserve
{
735 warn identify_myself
(%params) if $DEBUG;
737 my $course_id = $params{'course_id'};
738 my $ci_id = $params{'ci_id'};
739 my $staff_note = $params{'staff_note'};
740 my $public_note = $params{'public_note'};
742 return unless ( $course_id && $ci_id );
744 my $course_reserve = GetCourseReserve
( course_id
=> $course_id, ci_id
=> $ci_id );
747 my $dbh = C4
::Context
->dbh;
749 if ($course_reserve) {
750 $cr_id = $course_reserve->{'cr_id'};
753 UPDATE course_reserves
754 SET staff_note = ?, public_note = ?
757 $dbh->do( $query, undef, $staff_note, $public_note, $cr_id );
760 INSERT INTO course_reserves SET
766 $dbh->do( $query, undef, $course_id, $ci_id, $staff_note, $public_note );
767 $cr_id = $dbh->last_insert_id( undef, undef, 'course_reserves', 'cr_id' );
770 EnableOrDisableCourseItem
(
771 ci_id
=> $params{'ci_id'},
777 =head2 GetCourseReserves {
779 $course_reserves = GetCourseReserves( %params );
786 include_courses => 1,
790 sub GetCourseReserves
{
792 warn identify_myself
(%params) if $DEBUG;
794 my $course_id = $params{'course_id'};
795 my $ci_id = $params{'ci_id'};
796 my $include_items = $params{'include_items'};
797 my $include_count = $params{'include_count'};
798 my $include_courses = $params{'include_courses'};
800 return unless ( $course_id || $ci_id );
802 my $field = ($course_id) ?
'course_id' : 'ci_id';
803 my $value = ($course_id) ?
$course_id : $ci_id;
806 SELECT cr.*, ci.itemnumber
807 FROM course_reserves cr, course_items ci
809 AND cr.ci_id = ci.ci_id
811 my $dbh = C4
::Context
->dbh;
812 my $sth = $dbh->prepare($query);
813 $sth->execute($value);
815 my $course_reserves = $sth->fetchall_arrayref( {} );
817 if ($include_items) {
818 foreach my $cr (@
$course_reserves) {
819 my $item = Koha
::Items
->find( $cr->{itemnumber
} );
820 my $biblio = $item->biblio;
821 my $biblioitem = $biblio->biblioitem;
822 $cr->{'course_item'} = GetCourseItem
( ci_id
=> $cr->{'ci_id'} );
823 $cr->{'item'} = $item;
824 $cr->{'biblio'} = $biblio;
825 $cr->{'biblioitem'} = $biblioitem;
826 $cr->{'issue'} = GetOpenIssue
( $cr->{'itemnumber'} );
830 if ($include_count) {
831 foreach my $cr (@
$course_reserves) {
832 $cr->{'reserves_count'} = CountCourseReservesForItem
( ci_id
=> $cr->{'ci_id'} );
836 if ($include_courses) {
837 foreach my $cr (@
$course_reserves) {
838 $cr->{'courses'} = GetCourses
( itemnumber
=> $cr->{'itemnumber'} );
842 return $course_reserves;
845 =head2 DelCourseReserve {
847 DelCourseReserve( cr_id => $cr_id );
851 sub DelCourseReserve
{
853 warn identify_myself
(%params) if $DEBUG;
855 my $cr_id = $params{'cr_id'};
857 return unless ($cr_id);
859 my $dbh = C4
::Context
->dbh;
861 my $course_reserve = GetCourseReserve
( cr_id
=> $cr_id );
864 DELETE FROM course_reserves
867 $dbh->do( $query, undef, $cr_id );
869 ## If there are no other course reserves for this item
870 ## delete the course_item as well
871 unless ( CountCourseReservesForItem
( ci_id
=> $course_reserve->{'ci_id'} ) ) {
872 DelCourseItem
( ci_id
=> $course_reserve->{'ci_id'} );
877 =head2 GetItemCourseReservesInfo
879 my $arrayref = GetItemCourseReservesInfo( itemnumber => $itemnumber );
881 For a given item, returns an arrayref of reserves hashrefs,
882 with a course hashref under the key 'course'
886 sub GetItemCourseReservesInfo
{
888 warn identify_myself
(%params) if $DEBUG;
890 my $itemnumber = $params{'itemnumber'};
892 return unless ($itemnumber);
894 my $course_item = GetCourseItem
( itemnumber
=> $itemnumber );
896 return unless ( keys %$course_item );
898 my $course_reserves = GetCourseReserves
( ci_id
=> $course_item->{'ci_id'} );
900 foreach my $cr (@
$course_reserves) {
901 $cr->{'course'} = GetCourse
( $cr->{'course_id'} );
904 return $course_reserves;
907 =head2 CountCourseReservesForItem
909 $bool = CountCourseReservesForItem( %params );
911 ci_id - course_item id
913 itemnumber - course_item itemnumber
915 enabled = 'yes' or 'no'
916 Optional, if not supplied, counts reserves
917 for both enabled and disabled courses
921 sub CountCourseReservesForItem
{
923 warn identify_myself
(%params) if $DEBUG;
925 my $ci_id = $params{'ci_id'};
926 my $itemnumber = $params{'itemnumber'};
927 my $enabled = $params{'enabled'};
929 return unless ( $ci_id || $itemnumber );
931 my $course_item = GetCourseItem
( ci_id
=> $ci_id, itemnumber
=> $itemnumber );
933 my @params = ( $course_item->{'ci_id'} );
934 push( @params, $enabled ) if ($enabled);
937 SELECT COUNT(*) AS count
938 FROM course_reserves cr
939 LEFT JOIN courses c ON ( c.course_id = cr.course_id )
942 $query .= "AND c.enabled = ?" if ($enabled);
944 my $dbh = C4
::Context
->dbh;
945 my $sth = $dbh->prepare($query);
946 $sth->execute(@params);
948 my $row = $sth->fetchrow_hashref();
950 return $row->{'count'};
955 my $courses = SearchCourses( term => $search_term, enabled => 'yes' );
961 warn identify_myself
(%params) if $DEBUG;
963 my $term = $params{'term'};
965 my $enabled = $params{'enabled'} || '%';
969 SELECT c.course_id, c.department, c.course_number, c.section, c.course_name, c.term, c.staff_note, c.public_note, c.students_count, c.enabled, c.timestamp
971 LEFT JOIN course_instructors ci
972 ON ( c.course_id = ci.course_id )
973 LEFT JOIN borrowers b
974 ON ( ci.borrowernumber = b.borrowernumber )
975 LEFT JOIN authorised_values av
976 ON ( c.department = av.authorised_value )
978 ( av.category = 'DEPARTMENT' OR av.category = 'TERM' )
982 course_number LIKE ? OR
984 course_name LIKE ? OR
986 public_note LIKE ? OR
987 CONCAT(surname,' ',firstname) LIKE ? OR
988 CONCAT(firstname,' ',surname) LIKE ? OR
994 GROUP BY c.course_id, c.department, c.course_number, c.section, c.course_name, c.term, c.staff_note, c.public_note, c.students_count, c.enabled, c.timestamp
999 @params = ($term) x
10;
1001 $query .= " ORDER BY department, course_number, section, term, course_name ";
1003 my $dbh = C4
::Context
->dbh;
1004 my $sth = $dbh->prepare($query);
1006 $sth->execute( @params, $enabled );
1008 my $courses = $sth->fetchall_arrayref( {} );
1010 foreach my $c (@
$courses) {
1011 $c->{'instructors'} = GetCourseInstructors
( $c->{'course_id'} );
1017 sub whoami
{ ( caller(1) )[3] }
1018 sub whowasi
{ ( caller(2) )[3] }
1020 sub stringify_params
{
1025 foreach my $key ( keys %params ) {
1026 $string .= " $key => " . $params{$key} . "\n";
1029 return "( $string )";
1032 sub identify_myself
{
1035 return whowasi
() . stringify_params
(%params);
1042 Kyle M Hall <kyle@bywatersolutions.com>