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
::Items
qw(ModItem);
24 use C4
::Circulation
qw(GetOpenIssue);
26 use vars
qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG @FIELDS);
50 &GetItemCourseReservesInfo
52 %EXPORT_TAGS = ( 'all' => \
@EXPORT_OK );
55 @FIELDS = ( 'itype', 'ccode', 'holdingbranch', 'location' );
60 C4::CourseReserves - Koha course reserves module
64 use C4::CourseReserves;
68 This module deals with course reserves.
74 $course = GetCourse( $course_id );
80 warn whoami
() . "( $course_id )" if $DEBUG;
82 my $query = "SELECT * FROM courses WHERE course_id = ?";
83 my $dbh = C4
::Context
->dbh;
84 my $sth = $dbh->prepare($query);
85 $sth->execute($course_id);
87 my $course = $sth->fetchrow_hashref();
90 SELECT b.* FROM course_instructors ci
91 LEFT JOIN borrowers b ON ( ci.borrowernumber = b.borrowernumber )
94 $sth = $dbh->prepare($query);
95 $sth->execute($course_id);
96 $course->{'instructors'} = $sth->fetchall_arrayref( {} );
103 ModCourse( [ course_id => $id ] [, course_name => $course_name ] [etc...] );
109 warn identify_myself
(%params) if $DEBUG;
111 my $dbh = C4
::Context
->dbh;
114 if ( defined $params{'course_id'} ) {
115 $course_id = $params{'course_id'};
116 delete $params{'course_id'};
124 $query .= ($course_id) ?
' UPDATE ' : ' INSERT ';
125 $query .= ' courses SET ';
127 foreach my $key ( keys %params ) {
128 push( @query_keys, "$key=?" );
129 push( @query_values, $params{$key} );
131 $query .= join( ',', @query_keys );
134 $query .= " WHERE course_id = ?";
135 push( @query_values, $course_id );
138 $dbh->do( $query, undef, @query_values );
140 $course_id = $course_id
141 || $dbh->last_insert_id( undef, undef, 'courses', 'course_id' );
143 EnableOrDisableCourseItems
(
144 course_id
=> $course_id,
145 enabled
=> $params{'enabled'}
153 @courses = GetCourses( [ fieldname => $value ] [, fieldname2 => $value2 ] [etc...] );
159 warn identify_myself
(%params) if $DEBUG;
165 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
167 LEFT JOIN course_reserves ON course_reserves.course_id = c.course_id
168 LEFT JOIN course_items ON course_items.ci_id = course_reserves.ci_id
171 if ( keys %params ) {
175 foreach my $key ( keys %params ) {
176 push( @query_keys, " $key LIKE ? " );
177 push( @query_values, $params{$key} );
180 $query .= join( ' AND ', @query_keys );
183 $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 ";
185 my $dbh = C4
::Context
->dbh;
186 my $sth = $dbh->prepare($query);
187 $sth->execute(@query_values);
189 my $courses = $sth->fetchall_arrayref( {} );
191 foreach my $c (@
$courses) {
192 $c->{'instructors'} = GetCourseInstructors
( $c->{'course_id'} );
200 DelCourse( $course_id );
205 my ($course_id) = @_;
207 my $course_reserves = GetCourseReserves
( course_id
=> $course_id );
209 foreach my $res (@
$course_reserves) {
210 DelCourseReserve
( cr_id
=> $res->{'cr_id'} );
214 DELETE FROM course_instructors
217 C4
::Context
->dbh->do( $query, undef, $course_id );
223 C4
::Context
->dbh->do( $query, undef, $course_id );
226 =head2 EnableOrDisableCourseItems
228 EnableOrDisableCourseItems( course_id => $course_id, enabled => $enabled );
230 For each item on reserve for this course,
231 if the course item has no active course reserves,
232 swap the fields for the item to make it 'normal'
235 enabled => 'yes' to enable course items
236 enabled => 'no' to disable course items
240 sub EnableOrDisableCourseItems
{
242 warn identify_myself
(%params) if $DEBUG;
244 my $course_id = $params{'course_id'};
245 my $enabled = $params{'enabled'} || 0;
247 my $lookfor = ( $enabled eq 'yes' ) ?
'no' : 'yes';
249 return unless ( $course_id && $enabled );
250 return unless ( $enabled eq 'yes' || $enabled eq 'no' );
252 my $course_reserves = GetCourseReserves
( course_id
=> $course_id );
254 if ( $enabled eq 'yes' ) {
255 foreach my $course_reserve (@
$course_reserves) {
256 if (CountCourseReservesForItem
(
257 ci_id
=> $course_reserve->{'ci_id'},
261 EnableOrDisableCourseItem
(
262 ci_id
=> $course_reserve->{'ci_id'},
267 if ( $enabled eq 'no' ) {
268 foreach my $course_reserve (@
$course_reserves) {
270 CountCourseReservesForItem
(
271 ci_id
=> $course_reserve->{'ci_id'},
275 EnableOrDisableCourseItem
(
276 ci_id
=> $course_reserve->{'ci_id'},
283 =head2 EnableOrDisableCourseItem
285 EnableOrDisableCourseItem( ci_id => $ci_id );
289 sub EnableOrDisableCourseItem
{
291 warn identify_myself
(%params) if $DEBUG;
293 my $ci_id = $params{'ci_id'};
295 return unless ( $ci_id );
297 my $course_item = GetCourseItem
( ci_id
=> $ci_id );
299 my $info = GetItemCourseReservesInfo
( itemnumber
=> $course_item->{itemnumber
} );
301 my $enabled = any
{ $_->{course
}->{enabled
} eq 'yes' } @
$info;
302 $enabled = $enabled ?
'yes' : 'no';
304 ## We don't want to 'enable' an already enabled item,
305 ## or disable and already disabled item,
306 ## as that would cause the fields to swap
307 if ( $course_item->{'enabled'} ne $enabled ) {
308 _SwapAllFields
($ci_id);
316 C4
::Context
->dbh->do( $query, undef, $enabled, $ci_id );
322 =head2 GetCourseInstructors
324 @$borrowers = GetCourseInstructors( $course_id );
328 sub GetCourseInstructors
{
329 my ($course_id) = @_;
330 warn "C4::CourseReserves::GetCourseInstructors( $course_id )"
334 SELECT * FROM borrowers
335 RIGHT JOIN course_instructors ON ( course_instructors.borrowernumber = borrowers.borrowernumber )
336 WHERE course_instructors.course_id = ?
339 my $dbh = C4
::Context
->dbh;
340 my $sth = $dbh->prepare($query);
341 $sth->execute($course_id);
343 return $sth->fetchall_arrayref( {} );
346 =head2 ModCourseInstructors
348 ModCourseInstructors( mode => $mode, course_id => $course_id, [ cardnumbers => $cardnumbers ] OR [ borrowernumbers => $borrowernumbers );
350 $mode can be 'replace', 'add', or 'delete'
352 $cardnumbers and $borrowernumbers are both references to arrays
354 Use either cardnumbers or borrowernumber, but not both.
358 sub ModCourseInstructors
{
360 warn identify_myself
(%params) if $DEBUG;
362 my $course_id = $params{'course_id'};
363 my $mode = $params{'mode'};
364 my $cardnumbers = $params{'cardnumbers'};
365 my $borrowernumbers = $params{'borrowernumbers'};
367 return unless ($course_id);
369 unless ( $mode eq 'replace'
371 || $mode eq 'delete' );
372 return unless ( $cardnumbers || $borrowernumbers );
373 return if ( $cardnumbers && $borrowernumbers );
375 my ( @cardnumbers, @borrowernumbers );
376 @cardnumbers = @
$cardnumbers if ( ref($cardnumbers) eq 'ARRAY' );
377 @borrowernumbers = @
$borrowernumbers
378 if ( ref($borrowernumbers) eq 'ARRAY' );
380 my $field = (@cardnumbers) ?
'cardnumber' : 'borrowernumber';
381 my @fields = (@cardnumbers) ?
@cardnumbers : @borrowernumbers;
382 my $placeholders = join( ',', ('?') x
scalar @fields );
384 my $dbh = C4
::Context
->dbh;
386 $dbh->do( "DELETE FROM course_instructors WHERE course_id = ?", undef, $course_id )
387 if ( $mode eq 'replace' );
391 if ( $mode eq 'add' || $mode eq 'replace' ) {
393 INSERT INTO course_instructors ( course_id, borrowernumber )
394 SELECT ?, borrowernumber
396 WHERE $field IN ( $placeholders )
400 DELETE FROM course_instructors
402 AND borrowernumber IN (
403 SELECT borrowernumber FROM borrowers WHERE $field IN ( $placeholders )
408 my $sth = $dbh->prepare($query);
410 $sth->execute( $course_id, @fields ) if (@fields);
413 =head2 GetCourseItem {
415 $course_item = GetCourseItem( itemnumber => $itemnumber [, ci_id => $ci_id );
421 warn identify_myself
(%params) if $DEBUG;
423 my $ci_id = $params{'ci_id'};
424 my $itemnumber = $params{'itemnumber'};
426 return unless ( $itemnumber || $ci_id );
428 my $field = ($itemnumber) ?
'itemnumber' : 'ci_id';
429 my $value = ($itemnumber) ?
$itemnumber : $ci_id;
431 my $query = "SELECT * FROM course_items WHERE $field = ?";
432 my $dbh = C4
::Context
->dbh;
433 my $sth = $dbh->prepare($query);
434 $sth->execute($value);
436 my $course_item = $sth->fetchrow_hashref();
439 $query = "SELECT * FROM course_reserves WHERE ci_id = ?";
440 $sth = $dbh->prepare($query);
441 $sth->execute( $course_item->{'ci_id'} );
442 my $course_reserves = $sth->fetchall_arrayref( {} );
444 $course_item->{'course_reserves'} = $course_reserves
445 if ($course_reserves);
450 =head2 ModCourseItem {
452 ModCourseItem( %params );
454 Creates or modifies an existing course item.
460 warn identify_myself
(%params) if $DEBUG;
462 my $itemnumber = $params{'itemnumber'};
464 return unless ($itemnumber);
466 my $course_item = GetCourseItem
( itemnumber
=> $itemnumber );
471 $ci_id = $course_item->{'ci_id'};
475 course_item
=> $course_item,
479 $ci_id = _AddCourseItem
(%params);
486 =head2 _AddCourseItem
488 my $ci_id = _AddCourseItem( %params );
494 warn identify_myself
(%params) if $DEBUG;
496 my ( @fields, @values );
498 push( @fields, 'itemnumber = ?' );
499 push( @values, $params{'itemnumber'} );
502 push( @fields, "$_ = ?" );
503 push( @values, $params{$_} || undef );
506 my $query = "INSERT INTO course_items SET " . join( ',', @fields );
507 my $dbh = C4
::Context
->dbh;
508 $dbh->do( $query, undef, @values );
510 my $ci_id = $dbh->last_insert_id( undef, undef, 'course_items', 'ci_id' );
515 =head2 _UpdateCourseItem
517 _UpdateCourseItem( %params );
521 sub _UpdateCourseItem
{
523 warn identify_myself
(%params) if $DEBUG;
525 my $ci_id = $params{'ci_id'};
526 my $course_item = $params{'course_item'};
528 return unless ( $ci_id || $course_item );
530 $course_item = GetCourseItem
( ci_id
=> $ci_id )
531 unless ($course_item);
532 $ci_id = $course_item->{'ci_id'} unless ($ci_id);
537 $mod_params{$_} = $params{$_};
540 ModItem
( \
%mod_params, undef, $course_item->{'itemnumber'} );
543 =head2 _ModStoredFields
545 _ModStoredFields( %params );
547 Updates the values for the 'original' fields in course_items
552 sub _ModStoredFields
{
554 warn identify_myself
(%params) if $DEBUG;
556 return unless ( $params{'ci_id'} );
558 my ( @fields_to_update, @values_to_update );
561 if ( defined($params{$_}) ) {
562 push( @fields_to_update, $_ );
563 push( @values_to_update, $params{$_} );
567 my $query = "UPDATE course_items SET " . join( ',', map { "$_=?" } @fields_to_update ) . " WHERE ci_id = ?";
569 C4
::Context
->dbh->do( $query, undef, @values_to_update, $params{'ci_id'} )
570 if (@values_to_update);
576 _RevertFields( ci_id => $ci_id, fields => \@fields_to_revert );
582 warn identify_myself
(%params) if $DEBUG;
584 my $ci_id = $params{'ci_id'};
586 return unless ($ci_id);
588 my $course_item = GetCourseItem
( ci_id
=> $params{'ci_id'} );
591 foreach my $field ( @FIELDS ) {
592 $mod_item_params->{$field} = $course_item->{$field};
595 ModItem
( $mod_item_params, undef, $course_item->{'itemnumber'} ) if $mod_item_params && %$mod_item_params;
598 =head2 _SwapAllFields
600 _SwapAllFields( $ci_id );
606 warn "C4::CourseReserves::_SwapFields( $ci_id )" if $DEBUG;
608 my $course_item = GetCourseItem
( ci_id
=> $ci_id );
609 my $item = Koha
::Items
->find($course_item->{'itemnumber'});
611 my %course_item_fields;
614 if ( defined( $course_item->{$_} ) ) {
615 $course_item_fields{$_} = $course_item->{$_};
616 $item_fields{$_} = $item->$_ || q{};
620 ModItem
( \
%course_item_fields, undef, $course_item->{'itemnumber'} ) if %course_item_fields;
621 _ModStoredFields
( %item_fields, ci_id
=> $ci_id );
624 =head2 GetCourseItems {
626 $course_items = GetCourseItems(
627 [course_id => $course_id]
628 [, itemnumber => $itemnumber ]
635 warn identify_myself
(%params) if $DEBUG;
637 my $course_id = $params{'course_id'};
638 my $itemnumber = $params{'itemnumber'};
640 return unless ($course_id);
645 my $query = "SELECT * FROM course_items";
647 if ( keys %params ) {
651 foreach my $key ( keys %params ) {
652 push( @query_keys, " $key LIKE ? " );
653 push( @query_values, $params{$key} );
656 $query .= join( ' AND ', @query_keys );
659 my $dbh = C4
::Context
->dbh;
660 my $sth = $dbh->prepare($query);
661 $sth->execute(@query_values);
663 return $sth->fetchall_arrayref( {} );
666 =head2 DelCourseItem {
668 DelCourseItem( ci_id => $cr_id );
674 warn identify_myself
(%params) if $DEBUG;
676 my $ci_id = $params{'ci_id'};
678 return unless ($ci_id);
680 _RevertFields
( ci_id
=> $ci_id );
683 DELETE FROM course_items
686 C4
::Context
->dbh->do( $query, undef, $ci_id );
689 =head2 GetCourseReserve {
691 $course_item = GetCourseReserve( %params );
695 sub GetCourseReserve
{
697 warn identify_myself
(%params) if $DEBUG;
699 my $cr_id = $params{'cr_id'};
700 my $course_id = $params{'course_id'};
701 my $ci_id = $params{'ci_id'};
703 return unless ( $cr_id || ( $course_id && $ci_id ) );
705 my $dbh = C4
::Context
->dbh;
710 SELECT * FROM course_reserves
713 $sth = $dbh->prepare($query);
714 $sth->execute($cr_id);
717 SELECT * FROM course_reserves
718 WHERE course_id = ? AND ci_id = ?
720 $sth = $dbh->prepare($query);
721 $sth->execute( $course_id, $ci_id );
724 my $course_reserve = $sth->fetchrow_hashref();
725 return $course_reserve;
728 =head2 ModCourseReserve
730 $id = ModCourseReserve( %params );
734 sub ModCourseReserve
{
736 warn identify_myself
(%params) if $DEBUG;
738 my $course_id = $params{'course_id'};
739 my $ci_id = $params{'ci_id'};
740 my $staff_note = $params{'staff_note'};
741 my $public_note = $params{'public_note'};
743 return unless ( $course_id && $ci_id );
745 my $course_reserve = GetCourseReserve
( course_id
=> $course_id, ci_id
=> $ci_id );
748 my $dbh = C4
::Context
->dbh;
750 if ($course_reserve) {
751 $cr_id = $course_reserve->{'cr_id'};
754 UPDATE course_reserves
755 SET staff_note = ?, public_note = ?
758 $dbh->do( $query, undef, $staff_note, $public_note, $cr_id );
761 INSERT INTO course_reserves SET
767 $dbh->do( $query, undef, $course_id, $ci_id, $staff_note, $public_note );
768 $cr_id = $dbh->last_insert_id( undef, undef, 'course_reserves', 'cr_id' );
771 EnableOrDisableCourseItem
(
772 ci_id
=> $params{'ci_id'},
778 =head2 GetCourseReserves {
780 $course_reserves = GetCourseReserves( %params );
787 include_courses => 1,
791 sub GetCourseReserves
{
793 warn identify_myself
(%params) if $DEBUG;
795 my $course_id = $params{'course_id'};
796 my $ci_id = $params{'ci_id'};
797 my $include_items = $params{'include_items'};
798 my $include_count = $params{'include_count'};
799 my $include_courses = $params{'include_courses'};
801 return unless ( $course_id || $ci_id );
803 my $field = ($course_id) ?
'course_id' : 'ci_id';
804 my $value = ($course_id) ?
$course_id : $ci_id;
807 SELECT cr.*, ci.itemnumber
808 FROM course_reserves cr, course_items ci
810 AND cr.ci_id = ci.ci_id
812 my $dbh = C4
::Context
->dbh;
813 my $sth = $dbh->prepare($query);
814 $sth->execute($value);
816 my $course_reserves = $sth->fetchall_arrayref( {} );
818 if ($include_items) {
819 foreach my $cr (@
$course_reserves) {
820 my $item = Koha
::Items
->find( $cr->{itemnumber
} );
821 my $biblio = $item->biblio;
822 my $biblioitem = $biblio->biblioitem;
823 $cr->{'course_item'} = GetCourseItem
( ci_id
=> $cr->{'ci_id'} );
824 $cr->{'item'} = $item;
825 $cr->{'biblio'} = $biblio;
826 $cr->{'biblioitem'} = $biblioitem;
827 $cr->{'issue'} = GetOpenIssue
( $cr->{'itemnumber'} );
831 if ($include_count) {
832 foreach my $cr (@
$course_reserves) {
833 $cr->{'reserves_count'} = CountCourseReservesForItem
( ci_id
=> $cr->{'ci_id'} );
837 if ($include_courses) {
838 foreach my $cr (@
$course_reserves) {
839 $cr->{'courses'} = GetCourses
( itemnumber
=> $cr->{'itemnumber'} );
843 return $course_reserves;
846 =head2 DelCourseReserve {
848 DelCourseReserve( cr_id => $cr_id );
852 sub DelCourseReserve
{
854 warn identify_myself
(%params) if $DEBUG;
856 my $cr_id = $params{'cr_id'};
858 return unless ($cr_id);
860 my $dbh = C4
::Context
->dbh;
862 my $course_reserve = GetCourseReserve
( cr_id
=> $cr_id );
865 DELETE FROM course_reserves
868 $dbh->do( $query, undef, $cr_id );
870 ## If there are no other course reserves for this item
871 ## delete the course_item as well
872 unless ( CountCourseReservesForItem
( ci_id
=> $course_reserve->{'ci_id'} ) ) {
873 DelCourseItem
( ci_id
=> $course_reserve->{'ci_id'} );
878 =head2 GetItemCourseReservesInfo
880 my $arrayref = GetItemCourseReservesInfo( itemnumber => $itemnumber );
882 For a given item, returns an arrayref of reserves hashrefs,
883 with a course hashref under the key 'course'
887 sub GetItemCourseReservesInfo
{
889 warn identify_myself
(%params) if $DEBUG;
891 my $itemnumber = $params{'itemnumber'};
893 return unless ($itemnumber);
895 my $course_item = GetCourseItem
( itemnumber
=> $itemnumber );
897 return unless ( keys %$course_item );
899 my $course_reserves = GetCourseReserves
( ci_id
=> $course_item->{'ci_id'} );
901 foreach my $cr (@
$course_reserves) {
902 $cr->{'course'} = GetCourse
( $cr->{'course_id'} );
905 return $course_reserves;
908 =head2 CountCourseReservesForItem
910 $bool = CountCourseReservesForItem( %params );
912 ci_id - course_item id
914 itemnumber - course_item itemnumber
916 enabled = 'yes' or 'no'
917 Optional, if not supplied, counts reserves
918 for both enabled and disabled courses
922 sub CountCourseReservesForItem
{
924 warn identify_myself
(%params) if $DEBUG;
926 my $ci_id = $params{'ci_id'};
927 my $itemnumber = $params{'itemnumber'};
928 my $enabled = $params{'enabled'};
930 return unless ( $ci_id || $itemnumber );
932 my $course_item = GetCourseItem
( ci_id
=> $ci_id, itemnumber
=> $itemnumber );
934 my @params = ( $course_item->{'ci_id'} );
935 push( @params, $enabled ) if ($enabled);
938 SELECT COUNT(*) AS count
939 FROM course_reserves cr
940 LEFT JOIN courses c ON ( c.course_id = cr.course_id )
943 $query .= "AND c.enabled = ?" if ($enabled);
945 my $dbh = C4
::Context
->dbh;
946 my $sth = $dbh->prepare($query);
947 $sth->execute(@params);
949 my $row = $sth->fetchrow_hashref();
951 return $row->{'count'};
956 my $courses = SearchCourses( term => $search_term, enabled => 'yes' );
962 warn identify_myself
(%params) if $DEBUG;
964 my $term = $params{'term'};
966 my $enabled = $params{'enabled'} || '%';
970 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
972 LEFT JOIN course_instructors ci
973 ON ( c.course_id = ci.course_id )
974 LEFT JOIN borrowers b
975 ON ( ci.borrowernumber = b.borrowernumber )
976 LEFT JOIN authorised_values av
977 ON ( c.department = av.authorised_value )
979 ( av.category = 'DEPARTMENT' OR av.category = 'TERM' )
983 course_number LIKE ? OR
985 course_name LIKE ? OR
987 public_note LIKE ? OR
988 CONCAT(surname,' ',firstname) LIKE ? OR
989 CONCAT(firstname,' ',surname) LIKE ? OR
995 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
1000 @params = ($term) x
10;
1002 $query .= " ORDER BY department, course_number, section, term, course_name ";
1004 my $dbh = C4
::Context
->dbh;
1005 my $sth = $dbh->prepare($query);
1007 $sth->execute( @params, $enabled );
1009 my $courses = $sth->fetchall_arrayref( {} );
1011 foreach my $c (@
$courses) {
1012 $c->{'instructors'} = GetCourseInstructors
( $c->{'course_id'} );
1018 sub whoami
{ ( caller(1) )[3] }
1019 sub whowasi
{ ( caller(2) )[3] }
1021 sub stringify_params
{
1026 foreach my $key ( keys %params ) {
1027 $string .= " $key => " . $params{$key} . "\n";
1030 return "( $string )";
1033 sub identify_myself
{
1036 return whowasi
() . stringify_params
(%params);
1043 Kyle M Hall <kyle@bywatersolutions.com>