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);
536 defined $params{$_} && $params{$_} ne ''
537 ?
( $_ => $params{$_} )
541 ModItem
( \
%mod_params, undef, $course_item->{'itemnumber'} );
544 =head2 _ModStoredFields
546 _ModStoredFields( %params );
548 Updates the values for the 'original' fields in course_items
553 sub _ModStoredFields
{
555 warn identify_myself
(%params) if $DEBUG;
557 return unless ( $params{'ci_id'} );
559 my ( @fields_to_update, @values_to_update );
562 if ( defined($params{$_}) ) {
563 push( @fields_to_update, $_ );
564 push( @values_to_update, $params{$_} );
568 my $query = "UPDATE course_items SET " . join( ',', map { "$_=?" } @fields_to_update ) . " WHERE ci_id = ?";
570 C4
::Context
->dbh->do( $query, undef, @values_to_update, $params{'ci_id'} )
571 if (@values_to_update);
577 _RevertFields( ci_id => $ci_id, fields => \@fields_to_revert );
583 warn identify_myself
(%params) if $DEBUG;
585 my $ci_id = $params{'ci_id'};
587 return unless ($ci_id);
589 my $course_item = GetCourseItem
( ci_id
=> $params{'ci_id'} );
592 foreach my $field ( @FIELDS ) {
593 next unless defined $course_item->{$field};
594 $mod_item_params->{$field} = $course_item->{$field};
597 ModItem
( $mod_item_params, undef, $course_item->{'itemnumber'} ) if $mod_item_params && %$mod_item_params;
600 =head2 _SwapAllFields
602 _SwapAllFields( $ci_id );
608 warn "C4::CourseReserves::_SwapFields( $ci_id )" if $DEBUG;
610 my $course_item = GetCourseItem
( ci_id
=> $ci_id );
611 my $item = Koha
::Items
->find($course_item->{'itemnumber'});
613 my %course_item_fields;
616 if ( defined( $course_item->{$_} ) ) {
617 $course_item_fields{$_} = $course_item->{$_};
618 $item_fields{$_} = $item->$_ || q{};
622 ModItem
( \
%course_item_fields, undef, $course_item->{'itemnumber'} ) if %course_item_fields;
623 _ModStoredFields
( %item_fields, ci_id
=> $ci_id );
626 =head2 GetCourseItems {
628 $course_items = GetCourseItems(
629 [course_id => $course_id]
630 [, itemnumber => $itemnumber ]
637 warn identify_myself
(%params) if $DEBUG;
639 my $course_id = $params{'course_id'};
640 my $itemnumber = $params{'itemnumber'};
642 return unless ($course_id);
647 my $query = "SELECT * FROM course_items";
649 if ( keys %params ) {
653 foreach my $key ( keys %params ) {
654 push( @query_keys, " $key LIKE ? " );
655 push( @query_values, $params{$key} );
658 $query .= join( ' AND ', @query_keys );
661 my $dbh = C4
::Context
->dbh;
662 my $sth = $dbh->prepare($query);
663 $sth->execute(@query_values);
665 return $sth->fetchall_arrayref( {} );
668 =head2 DelCourseItem {
670 DelCourseItem( ci_id => $cr_id );
676 warn identify_myself
(%params) if $DEBUG;
678 my $ci_id = $params{'ci_id'};
680 return unless ($ci_id);
682 _RevertFields
( ci_id
=> $ci_id );
685 DELETE FROM course_items
688 C4
::Context
->dbh->do( $query, undef, $ci_id );
691 =head2 GetCourseReserve {
693 $course_item = GetCourseReserve( %params );
697 sub GetCourseReserve
{
699 warn identify_myself
(%params) if $DEBUG;
701 my $cr_id = $params{'cr_id'};
702 my $course_id = $params{'course_id'};
703 my $ci_id = $params{'ci_id'};
705 return unless ( $cr_id || ( $course_id && $ci_id ) );
707 my $dbh = C4
::Context
->dbh;
712 SELECT * FROM course_reserves
715 $sth = $dbh->prepare($query);
716 $sth->execute($cr_id);
719 SELECT * FROM course_reserves
720 WHERE course_id = ? AND ci_id = ?
722 $sth = $dbh->prepare($query);
723 $sth->execute( $course_id, $ci_id );
726 my $course_reserve = $sth->fetchrow_hashref();
727 return $course_reserve;
730 =head2 ModCourseReserve
732 $id = ModCourseReserve( %params );
736 sub ModCourseReserve
{
738 warn identify_myself
(%params) if $DEBUG;
740 my $course_id = $params{'course_id'};
741 my $ci_id = $params{'ci_id'};
742 my $staff_note = $params{'staff_note'};
743 my $public_note = $params{'public_note'};
745 return unless ( $course_id && $ci_id );
747 my $course_reserve = GetCourseReserve
( course_id
=> $course_id, ci_id
=> $ci_id );
750 my $dbh = C4
::Context
->dbh;
752 if ($course_reserve) {
753 $cr_id = $course_reserve->{'cr_id'};
756 UPDATE course_reserves
757 SET staff_note = ?, public_note = ?
760 $dbh->do( $query, undef, $staff_note, $public_note, $cr_id );
763 INSERT INTO course_reserves SET
769 $dbh->do( $query, undef, $course_id, $ci_id, $staff_note, $public_note );
770 $cr_id = $dbh->last_insert_id( undef, undef, 'course_reserves', 'cr_id' );
773 EnableOrDisableCourseItem
(
774 ci_id
=> $params{'ci_id'},
780 =head2 GetCourseReserves {
782 $course_reserves = GetCourseReserves( %params );
789 include_courses => 1,
793 sub GetCourseReserves
{
795 warn identify_myself
(%params) if $DEBUG;
797 my $course_id = $params{'course_id'};
798 my $ci_id = $params{'ci_id'};
799 my $include_items = $params{'include_items'};
800 my $include_count = $params{'include_count'};
801 my $include_courses = $params{'include_courses'};
803 return unless ( $course_id || $ci_id );
805 my $field = ($course_id) ?
'course_id' : 'ci_id';
806 my $value = ($course_id) ?
$course_id : $ci_id;
809 SELECT cr.*, ci.itemnumber
810 FROM course_reserves cr, course_items ci
812 AND cr.ci_id = ci.ci_id
814 my $dbh = C4
::Context
->dbh;
815 my $sth = $dbh->prepare($query);
816 $sth->execute($value);
818 my $course_reserves = $sth->fetchall_arrayref( {} );
820 if ($include_items) {
821 foreach my $cr (@
$course_reserves) {
822 my $item = Koha
::Items
->find( $cr->{itemnumber
} );
823 my $biblio = $item->biblio;
824 my $biblioitem = $biblio->biblioitem;
825 $cr->{'course_item'} = GetCourseItem
( ci_id
=> $cr->{'ci_id'} );
826 $cr->{'item'} = $item;
827 $cr->{'biblio'} = $biblio;
828 $cr->{'biblioitem'} = $biblioitem;
829 $cr->{'issue'} = GetOpenIssue
( $cr->{'itemnumber'} );
833 if ($include_count) {
834 foreach my $cr (@
$course_reserves) {
835 $cr->{'reserves_count'} = CountCourseReservesForItem
( ci_id
=> $cr->{'ci_id'} );
839 if ($include_courses) {
840 foreach my $cr (@
$course_reserves) {
841 $cr->{'courses'} = GetCourses
( itemnumber
=> $cr->{'itemnumber'} );
845 return $course_reserves;
848 =head2 DelCourseReserve {
850 DelCourseReserve( cr_id => $cr_id );
854 sub DelCourseReserve
{
856 warn identify_myself
(%params) if $DEBUG;
858 my $cr_id = $params{'cr_id'};
860 return unless ($cr_id);
862 my $dbh = C4
::Context
->dbh;
864 my $course_reserve = GetCourseReserve
( cr_id
=> $cr_id );
867 DELETE FROM course_reserves
870 $dbh->do( $query, undef, $cr_id );
872 ## If there are no other course reserves for this item
873 ## delete the course_item as well
874 unless ( CountCourseReservesForItem
( ci_id
=> $course_reserve->{'ci_id'} ) ) {
875 DelCourseItem
( ci_id
=> $course_reserve->{'ci_id'} );
880 =head2 GetItemCourseReservesInfo
882 my $arrayref = GetItemCourseReservesInfo( itemnumber => $itemnumber );
884 For a given item, returns an arrayref of reserves hashrefs,
885 with a course hashref under the key 'course'
889 sub GetItemCourseReservesInfo
{
891 warn identify_myself
(%params) if $DEBUG;
893 my $itemnumber = $params{'itemnumber'};
895 return unless ($itemnumber);
897 my $course_item = GetCourseItem
( itemnumber
=> $itemnumber );
899 return unless ( keys %$course_item );
901 my $course_reserves = GetCourseReserves
( ci_id
=> $course_item->{'ci_id'} );
903 foreach my $cr (@
$course_reserves) {
904 $cr->{'course'} = GetCourse
( $cr->{'course_id'} );
907 return $course_reserves;
910 =head2 CountCourseReservesForItem
912 $bool = CountCourseReservesForItem( %params );
914 ci_id - course_item id
916 itemnumber - course_item itemnumber
918 enabled = 'yes' or 'no'
919 Optional, if not supplied, counts reserves
920 for both enabled and disabled courses
924 sub CountCourseReservesForItem
{
926 warn identify_myself
(%params) if $DEBUG;
928 my $ci_id = $params{'ci_id'};
929 my $itemnumber = $params{'itemnumber'};
930 my $enabled = $params{'enabled'};
932 return unless ( $ci_id || $itemnumber );
934 my $course_item = GetCourseItem
( ci_id
=> $ci_id, itemnumber
=> $itemnumber );
936 my @params = ( $course_item->{'ci_id'} );
937 push( @params, $enabled ) if ($enabled);
940 SELECT COUNT(*) AS count
941 FROM course_reserves cr
942 LEFT JOIN courses c ON ( c.course_id = cr.course_id )
945 $query .= "AND c.enabled = ?" if ($enabled);
947 my $dbh = C4
::Context
->dbh;
948 my $sth = $dbh->prepare($query);
949 $sth->execute(@params);
951 my $row = $sth->fetchrow_hashref();
953 return $row->{'count'};
958 my $courses = SearchCourses( term => $search_term, enabled => 'yes' );
964 warn identify_myself
(%params) if $DEBUG;
966 my $term = $params{'term'};
968 my $enabled = $params{'enabled'} || '%';
972 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
974 LEFT JOIN course_instructors ci
975 ON ( c.course_id = ci.course_id )
976 LEFT JOIN borrowers b
977 ON ( ci.borrowernumber = b.borrowernumber )
978 LEFT JOIN authorised_values av
979 ON ( c.department = av.authorised_value )
981 ( av.category = 'DEPARTMENT' OR av.category = 'TERM' )
985 course_number LIKE ? OR
987 course_name LIKE ? OR
989 public_note LIKE ? OR
990 CONCAT(surname,' ',firstname) LIKE ? OR
991 CONCAT(firstname,' ',surname) LIKE ? OR
997 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
1002 @params = ($term) x
10;
1004 $query .= " ORDER BY department, course_number, section, term, course_name ";
1006 my $dbh = C4
::Context
->dbh;
1007 my $sth = $dbh->prepare($query);
1009 $sth->execute( @params, $enabled );
1011 my $courses = $sth->fetchall_arrayref( {} );
1013 foreach my $c (@
$courses) {
1014 $c->{'instructors'} = GetCourseInstructors
( $c->{'course_id'} );
1020 sub whoami
{ ( caller(1) )[3] }
1021 sub whowasi
{ ( caller(2) )[3] }
1023 sub stringify_params
{
1028 foreach my $key ( keys %params ) {
1029 $string .= " $key => " . $params{$key} . "\n";
1032 return "( $string )";
1035 sub identify_myself
{
1038 return whowasi
() . stringify_params
(%params);
1045 Kyle M Hall <kyle@bywatersolutions.com>