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 $mod_item_params->{$field} = $course_item->{$field};
596 ModItem
( $mod_item_params, undef, $course_item->{'itemnumber'} ) if $mod_item_params && %$mod_item_params;
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'});
612 my %course_item_fields;
615 if ( defined( $course_item->{$_} ) ) {
616 $course_item_fields{$_} = $course_item->{$_};
617 $item_fields{$_} = $item->$_ || q{};
621 ModItem
( \
%course_item_fields, undef, $course_item->{'itemnumber'} ) if %course_item_fields;
622 _ModStoredFields
( %item_fields, ci_id
=> $ci_id );
625 =head2 GetCourseItems {
627 $course_items = GetCourseItems(
628 [course_id => $course_id]
629 [, itemnumber => $itemnumber ]
636 warn identify_myself
(%params) if $DEBUG;
638 my $course_id = $params{'course_id'};
639 my $itemnumber = $params{'itemnumber'};
641 return unless ($course_id);
646 my $query = "SELECT * FROM course_items";
648 if ( keys %params ) {
652 foreach my $key ( keys %params ) {
653 push( @query_keys, " $key LIKE ? " );
654 push( @query_values, $params{$key} );
657 $query .= join( ' AND ', @query_keys );
660 my $dbh = C4
::Context
->dbh;
661 my $sth = $dbh->prepare($query);
662 $sth->execute(@query_values);
664 return $sth->fetchall_arrayref( {} );
667 =head2 DelCourseItem {
669 DelCourseItem( ci_id => $cr_id );
675 warn identify_myself
(%params) if $DEBUG;
677 my $ci_id = $params{'ci_id'};
679 return unless ($ci_id);
681 _RevertFields
( ci_id
=> $ci_id );
684 DELETE FROM course_items
687 C4
::Context
->dbh->do( $query, undef, $ci_id );
690 =head2 GetCourseReserve {
692 $course_item = GetCourseReserve( %params );
696 sub GetCourseReserve
{
698 warn identify_myself
(%params) if $DEBUG;
700 my $cr_id = $params{'cr_id'};
701 my $course_id = $params{'course_id'};
702 my $ci_id = $params{'ci_id'};
704 return unless ( $cr_id || ( $course_id && $ci_id ) );
706 my $dbh = C4
::Context
->dbh;
711 SELECT * FROM course_reserves
714 $sth = $dbh->prepare($query);
715 $sth->execute($cr_id);
718 SELECT * FROM course_reserves
719 WHERE course_id = ? AND ci_id = ?
721 $sth = $dbh->prepare($query);
722 $sth->execute( $course_id, $ci_id );
725 my $course_reserve = $sth->fetchrow_hashref();
726 return $course_reserve;
729 =head2 ModCourseReserve
731 $id = ModCourseReserve( %params );
735 sub ModCourseReserve
{
737 warn identify_myself
(%params) if $DEBUG;
739 my $course_id = $params{'course_id'};
740 my $ci_id = $params{'ci_id'};
741 my $staff_note = $params{'staff_note'};
742 my $public_note = $params{'public_note'};
744 return unless ( $course_id && $ci_id );
746 my $course_reserve = GetCourseReserve
( course_id
=> $course_id, ci_id
=> $ci_id );
749 my $dbh = C4
::Context
->dbh;
751 if ($course_reserve) {
752 $cr_id = $course_reserve->{'cr_id'};
755 UPDATE course_reserves
756 SET staff_note = ?, public_note = ?
759 $dbh->do( $query, undef, $staff_note, $public_note, $cr_id );
762 INSERT INTO course_reserves SET
768 $dbh->do( $query, undef, $course_id, $ci_id, $staff_note, $public_note );
769 $cr_id = $dbh->last_insert_id( undef, undef, 'course_reserves', 'cr_id' );
772 EnableOrDisableCourseItem
(
773 ci_id
=> $params{'ci_id'},
779 =head2 GetCourseReserves {
781 $course_reserves = GetCourseReserves( %params );
788 include_courses => 1,
792 sub GetCourseReserves
{
794 warn identify_myself
(%params) if $DEBUG;
796 my $course_id = $params{'course_id'};
797 my $ci_id = $params{'ci_id'};
798 my $include_items = $params{'include_items'};
799 my $include_count = $params{'include_count'};
800 my $include_courses = $params{'include_courses'};
802 return unless ( $course_id || $ci_id );
804 my $field = ($course_id) ?
'course_id' : 'ci_id';
805 my $value = ($course_id) ?
$course_id : $ci_id;
808 SELECT cr.*, ci.itemnumber
809 FROM course_reserves cr, course_items ci
811 AND cr.ci_id = ci.ci_id
813 my $dbh = C4
::Context
->dbh;
814 my $sth = $dbh->prepare($query);
815 $sth->execute($value);
817 my $course_reserves = $sth->fetchall_arrayref( {} );
819 if ($include_items) {
820 foreach my $cr (@
$course_reserves) {
821 my $item = Koha
::Items
->find( $cr->{itemnumber
} );
822 my $biblio = $item->biblio;
823 my $biblioitem = $biblio->biblioitem;
824 $cr->{'course_item'} = GetCourseItem
( ci_id
=> $cr->{'ci_id'} );
825 $cr->{'item'} = $item;
826 $cr->{'biblio'} = $biblio;
827 $cr->{'biblioitem'} = $biblioitem;
828 $cr->{'issue'} = GetOpenIssue
( $cr->{'itemnumber'} );
832 if ($include_count) {
833 foreach my $cr (@
$course_reserves) {
834 $cr->{'reserves_count'} = CountCourseReservesForItem
( ci_id
=> $cr->{'ci_id'} );
838 if ($include_courses) {
839 foreach my $cr (@
$course_reserves) {
840 $cr->{'courses'} = GetCourses
( itemnumber
=> $cr->{'itemnumber'} );
844 return $course_reserves;
847 =head2 DelCourseReserve {
849 DelCourseReserve( cr_id => $cr_id );
853 sub DelCourseReserve
{
855 warn identify_myself
(%params) if $DEBUG;
857 my $cr_id = $params{'cr_id'};
859 return unless ($cr_id);
861 my $dbh = C4
::Context
->dbh;
863 my $course_reserve = GetCourseReserve
( cr_id
=> $cr_id );
866 DELETE FROM course_reserves
869 $dbh->do( $query, undef, $cr_id );
871 ## If there are no other course reserves for this item
872 ## delete the course_item as well
873 unless ( CountCourseReservesForItem
( ci_id
=> $course_reserve->{'ci_id'} ) ) {
874 DelCourseItem
( ci_id
=> $course_reserve->{'ci_id'} );
879 =head2 GetItemCourseReservesInfo
881 my $arrayref = GetItemCourseReservesInfo( itemnumber => $itemnumber );
883 For a given item, returns an arrayref of reserves hashrefs,
884 with a course hashref under the key 'course'
888 sub GetItemCourseReservesInfo
{
890 warn identify_myself
(%params) if $DEBUG;
892 my $itemnumber = $params{'itemnumber'};
894 return unless ($itemnumber);
896 my $course_item = GetCourseItem
( itemnumber
=> $itemnumber );
898 return unless ( keys %$course_item );
900 my $course_reserves = GetCourseReserves
( ci_id
=> $course_item->{'ci_id'} );
902 foreach my $cr (@
$course_reserves) {
903 $cr->{'course'} = GetCourse
( $cr->{'course_id'} );
906 return $course_reserves;
909 =head2 CountCourseReservesForItem
911 $bool = CountCourseReservesForItem( %params );
913 ci_id - course_item id
915 itemnumber - course_item itemnumber
917 enabled = 'yes' or 'no'
918 Optional, if not supplied, counts reserves
919 for both enabled and disabled courses
923 sub CountCourseReservesForItem
{
925 warn identify_myself
(%params) if $DEBUG;
927 my $ci_id = $params{'ci_id'};
928 my $itemnumber = $params{'itemnumber'};
929 my $enabled = $params{'enabled'};
931 return unless ( $ci_id || $itemnumber );
933 my $course_item = GetCourseItem
( ci_id
=> $ci_id, itemnumber
=> $itemnumber );
935 my @params = ( $course_item->{'ci_id'} );
936 push( @params, $enabled ) if ($enabled);
939 SELECT COUNT(*) AS count
940 FROM course_reserves cr
941 LEFT JOIN courses c ON ( c.course_id = cr.course_id )
944 $query .= "AND c.enabled = ?" if ($enabled);
946 my $dbh = C4
::Context
->dbh;
947 my $sth = $dbh->prepare($query);
948 $sth->execute(@params);
950 my $row = $sth->fetchrow_hashref();
952 return $row->{'count'};
957 my $courses = SearchCourses( term => $search_term, enabled => 'yes' );
963 warn identify_myself
(%params) if $DEBUG;
965 my $term = $params{'term'};
967 my $enabled = $params{'enabled'} || '%';
971 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
973 LEFT JOIN course_instructors ci
974 ON ( c.course_id = ci.course_id )
975 LEFT JOIN borrowers b
976 ON ( ci.borrowernumber = b.borrowernumber )
977 LEFT JOIN authorised_values av
978 ON ( c.department = av.authorised_value )
980 ( av.category = 'DEPARTMENT' OR av.category = 'TERM' )
984 course_number LIKE ? OR
986 course_name LIKE ? OR
988 public_note LIKE ? OR
989 CONCAT(surname,' ',firstname) LIKE ? OR
990 CONCAT(firstname,' ',surname) LIKE ? OR
996 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
1001 @params = ($term) x
10;
1003 $query .= " ORDER BY department, course_number, section, term, course_name ";
1005 my $dbh = C4
::Context
->dbh;
1006 my $sth = $dbh->prepare($query);
1008 $sth->execute( @params, $enabled );
1010 my $courses = $sth->fetchall_arrayref( {} );
1012 foreach my $c (@
$courses) {
1013 $c->{'instructors'} = GetCourseInstructors
( $c->{'course_id'} );
1019 sub whoami
{ ( caller(1) )[3] }
1020 sub whowasi
{ ( caller(2) )[3] }
1022 sub stringify_params
{
1027 foreach my $key ( keys %params ) {
1028 $string .= " $key => " . $params{$key} . "\n";
1031 return "( $string )";
1034 sub identify_myself
{
1037 return whowasi
() . stringify_params
(%params);
1044 Kyle M Hall <kyle@bywatersolutions.com>