Bug 23083: Fix course reserve item editing if one of the value is set to UNCHANGED
[koha.git] / C4 / CourseReserves.pm
1 package C4::CourseReserves;
2
3 # This file is part of Koha.
4 #
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.
9 #
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.
14 #
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>.
17
18 use Modern::Perl;
19
20 use List::MoreUtils qw(any);
21
22 use C4::Context;
23 use C4::Items qw(ModItem);
24 use C4::Circulation qw(GetOpenIssue);
25
26 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG @FIELDS);
27
28 BEGIN {
29     require Exporter;
30     @ISA       = qw(Exporter);
31     @EXPORT_OK = qw(
32       &GetCourse
33       &ModCourse
34       &GetCourses
35       &DelCourse
36
37       &GetCourseInstructors
38       &ModCourseInstructors
39
40       &GetCourseItem
41       &ModCourseItem
42
43       &GetCourseReserve
44       &ModCourseReserve
45       &GetCourseReserves
46       &DelCourseReserve
47
48       &SearchCourses
49
50       &GetItemCourseReservesInfo
51     );
52     %EXPORT_TAGS = ( 'all' => \@EXPORT_OK );
53
54     $DEBUG = 0;
55     @FIELDS = ( 'itype', 'ccode', 'holdingbranch', 'location' );
56 }
57
58 =head1 NAME
59
60 C4::CourseReserves - Koha course reserves module
61
62 =head1 SYNOPSIS
63
64 use C4::CourseReserves;
65
66 =head1 DESCRIPTION
67
68 This module deals with course reserves.
69
70 =head1 FUNCTIONS
71
72 =head2 GetCourse
73
74     $course = GetCourse( $course_id );
75
76 =cut
77
78 sub GetCourse {
79     my ($course_id) = @_;
80     warn whoami() . "( $course_id )" if $DEBUG;
81
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);
86
87     my $course = $sth->fetchrow_hashref();
88
89     $query = "
90         SELECT b.* FROM course_instructors ci
91         LEFT JOIN borrowers b ON ( ci.borrowernumber = b.borrowernumber )
92         WHERE course_id =  ?
93     ";
94     $sth = $dbh->prepare($query);
95     $sth->execute($course_id);
96     $course->{'instructors'} = $sth->fetchall_arrayref( {} );
97
98     return $course;
99 }
100
101 =head2 ModCourse
102
103     ModCourse( [ course_id => $id ] [, course_name => $course_name ] [etc...] );
104
105 =cut
106
107 sub ModCourse {
108     my (%params) = @_;
109     warn identify_myself(%params) if $DEBUG;
110
111     my $dbh = C4::Context->dbh;
112
113     my $course_id;
114     if ( defined $params{'course_id'} ) {
115         $course_id = $params{'course_id'};
116         delete $params{'course_id'};
117     }
118
119     my @query_keys;
120     my @query_values;
121
122     my $query;
123
124     $query .= ($course_id) ? ' UPDATE ' : ' INSERT ';
125     $query .= ' courses SET ';
126
127     foreach my $key ( keys %params ) {
128         push( @query_keys,   "$key=?" );
129         push( @query_values, $params{$key} );
130     }
131     $query .= join( ',', @query_keys );
132
133     if ($course_id) {
134         $query .= " WHERE course_id = ?";
135         push( @query_values, $course_id );
136     }
137
138     $dbh->do( $query, undef, @query_values );
139
140     $course_id = $course_id
141       || $dbh->last_insert_id( undef, undef, 'courses', 'course_id' );
142
143     EnableOrDisableCourseItems(
144         course_id => $course_id,
145         enabled   => $params{'enabled'}
146     );
147
148     return $course_id;
149 }
150
151 =head2 GetCourses
152
153   @courses = GetCourses( [ fieldname => $value ] [, fieldname2 => $value2 ] [etc...] );
154
155 =cut
156
157 sub GetCourses {
158     my (%params) = @_;
159     warn identify_myself(%params) if $DEBUG;
160
161     my @query_keys;
162     my @query_values;
163
164     my $query = "
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
166         FROM courses c
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
169     ";
170
171     if ( keys %params ) {
172
173         $query .= " WHERE ";
174
175         foreach my $key ( keys %params ) {
176             push( @query_keys,   " $key LIKE ? " );
177             push( @query_values, $params{$key} );
178         }
179
180         $query .= join( ' AND ', @query_keys );
181     }
182
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 ";
184
185     my $dbh = C4::Context->dbh;
186     my $sth = $dbh->prepare($query);
187     $sth->execute(@query_values);
188
189     my $courses = $sth->fetchall_arrayref( {} );
190
191     foreach my $c (@$courses) {
192         $c->{'instructors'} = GetCourseInstructors( $c->{'course_id'} );
193     }
194
195     return $courses;
196 }
197
198 =head2 DelCourse
199
200   DelCourse( $course_id );
201
202 =cut
203
204 sub DelCourse {
205     my ($course_id) = @_;
206
207     my $course_reserves = GetCourseReserves( course_id => $course_id );
208
209     foreach my $res (@$course_reserves) {
210         DelCourseReserve( cr_id => $res->{'cr_id'} );
211     }
212
213     my $query = "
214         DELETE FROM course_instructors
215         WHERE course_id = ?
216     ";
217     C4::Context->dbh->do( $query, undef, $course_id );
218
219     $query = "
220         DELETE FROM courses
221         WHERE course_id = ?
222     ";
223     C4::Context->dbh->do( $query, undef, $course_id );
224 }
225
226 =head2 EnableOrDisableCourseItems
227
228   EnableOrDisableCourseItems( course_id => $course_id, enabled => $enabled );
229
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'
233   again.
234
235   enabled => 'yes' to enable course items
236   enabled => 'no' to disable course items
237
238 =cut
239
240 sub EnableOrDisableCourseItems {
241     my (%params) = @_;
242     warn identify_myself(%params) if $DEBUG;
243
244     my $course_id = $params{'course_id'};
245     my $enabled = $params{'enabled'} || 0;
246
247     my $lookfor = ( $enabled eq 'yes' ) ? 'no' : 'yes';
248
249     return unless ( $course_id && $enabled );
250     return unless ( $enabled eq 'yes' || $enabled eq 'no' );
251
252     my $course_reserves = GetCourseReserves( course_id => $course_id );
253
254     if ( $enabled eq 'yes' ) {
255         foreach my $course_reserve (@$course_reserves) {
256             if (CountCourseReservesForItem(
257                     ci_id   => $course_reserve->{'ci_id'},
258                     enabled => 'yes'
259                 )
260               ) {
261                 EnableOrDisableCourseItem(
262                     ci_id   => $course_reserve->{'ci_id'},
263                 );
264             }
265         }
266     }
267     if ( $enabled eq 'no' ) {
268         foreach my $course_reserve (@$course_reserves) {
269             unless (
270                 CountCourseReservesForItem(
271                     ci_id   => $course_reserve->{'ci_id'},
272                     enabled => 'yes'
273                 )
274               ) {
275                 EnableOrDisableCourseItem(
276                     ci_id   => $course_reserve->{'ci_id'},
277                 );
278             }
279         }
280     }
281 }
282
283 =head2 EnableOrDisableCourseItem
284
285     EnableOrDisableCourseItem( ci_id => $ci_id );
286
287 =cut
288
289 sub EnableOrDisableCourseItem {
290     my (%params) = @_;
291     warn identify_myself(%params) if $DEBUG;
292
293     my $ci_id   = $params{'ci_id'};
294
295     return unless ( $ci_id );
296
297     my $course_item = GetCourseItem( ci_id => $ci_id );
298
299     my $info = GetItemCourseReservesInfo( itemnumber => $course_item->{itemnumber} );
300
301     my $enabled = any { $_->{course}->{enabled} eq 'yes' } @$info;
302     $enabled = $enabled ? 'yes' : 'no';
303
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);
309
310         my $query = "
311             UPDATE course_items
312             SET enabled = ?
313             WHERE ci_id = ?
314         ";
315
316         C4::Context->dbh->do( $query, undef, $enabled, $ci_id );
317
318     }
319
320 }
321
322 =head2 GetCourseInstructors
323
324     @$borrowers = GetCourseInstructors( $course_id );
325
326 =cut
327
328 sub GetCourseInstructors {
329     my ($course_id) = @_;
330     warn "C4::CourseReserves::GetCourseInstructors( $course_id )"
331       if $DEBUG;
332
333     my $query = "
334         SELECT * FROM borrowers
335         RIGHT JOIN course_instructors ON ( course_instructors.borrowernumber = borrowers.borrowernumber )
336         WHERE course_instructors.course_id = ?
337     ";
338
339     my $dbh = C4::Context->dbh;
340     my $sth = $dbh->prepare($query);
341     $sth->execute($course_id);
342
343     return $sth->fetchall_arrayref( {} );
344 }
345
346 =head2 ModCourseInstructors
347
348     ModCourseInstructors( mode => $mode, course_id => $course_id, [ cardnumbers => $cardnumbers ] OR [ borrowernumbers => $borrowernumbers  );
349
350     $mode can be 'replace', 'add', or 'delete'
351
352     $cardnumbers and $borrowernumbers are both references to arrays
353
354     Use either cardnumbers or borrowernumber, but not both.
355
356 =cut
357
358 sub ModCourseInstructors {
359     my (%params) = @_;
360     warn identify_myself(%params) if $DEBUG;
361
362     my $course_id       = $params{'course_id'};
363     my $mode            = $params{'mode'};
364     my $cardnumbers     = $params{'cardnumbers'};
365     my $borrowernumbers = $params{'borrowernumbers'};
366
367     return unless ($course_id);
368     return
369       unless ( $mode eq 'replace'
370         || $mode eq 'add'
371         || $mode eq 'delete' );
372     return unless ( $cardnumbers || $borrowernumbers );
373     return if ( $cardnumbers && $borrowernumbers );
374
375     my ( @cardnumbers, @borrowernumbers );
376     @cardnumbers = @$cardnumbers if ( ref($cardnumbers) eq 'ARRAY' );
377     @borrowernumbers = @$borrowernumbers
378       if ( ref($borrowernumbers) eq 'ARRAY' );
379
380     my $field  = (@cardnumbers) ? 'cardnumber' : 'borrowernumber';
381     my @fields = (@cardnumbers) ? @cardnumbers : @borrowernumbers;
382     my $placeholders = join( ',', ('?') x scalar @fields );
383
384     my $dbh = C4::Context->dbh;
385
386     $dbh->do( "DELETE FROM course_instructors WHERE course_id = ?", undef, $course_id )
387       if ( $mode eq 'replace' );
388
389     my $query;
390
391     if ( $mode eq 'add' || $mode eq 'replace' ) {
392         $query = "
393             INSERT INTO course_instructors ( course_id, borrowernumber )
394             SELECT ?, borrowernumber
395             FROM borrowers
396             WHERE $field IN ( $placeholders )
397         ";
398     } else {
399         $query = "
400             DELETE FROM course_instructors
401             WHERE course_id = ?
402             AND borrowernumber IN (
403                 SELECT borrowernumber FROM borrowers WHERE $field IN ( $placeholders )
404             )
405         ";
406     }
407
408     my $sth = $dbh->prepare($query);
409
410     $sth->execute( $course_id, @fields ) if (@fields);
411 }
412
413 =head2 GetCourseItem {
414
415   $course_item = GetCourseItem( itemnumber => $itemnumber [, ci_id => $ci_id );
416
417 =cut
418
419 sub GetCourseItem {
420     my (%params) = @_;
421     warn identify_myself(%params) if $DEBUG;
422
423     my $ci_id      = $params{'ci_id'};
424     my $itemnumber = $params{'itemnumber'};
425
426     return unless ( $itemnumber || $ci_id );
427
428     my $field = ($itemnumber) ? 'itemnumber' : 'ci_id';
429     my $value = ($itemnumber) ? $itemnumber  : $ci_id;
430
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);
435
436     my $course_item = $sth->fetchrow_hashref();
437
438     if ($course_item) {
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( {} );
443
444         $course_item->{'course_reserves'} = $course_reserves
445           if ($course_reserves);
446     }
447     return $course_item;
448 }
449
450 =head2 ModCourseItem {
451
452   ModCourseItem( %params );
453
454   Creates or modifies an existing course item.
455
456 =cut
457
458 sub ModCourseItem {
459     my (%params) = @_;
460     warn identify_myself(%params) if $DEBUG;
461
462     my $itemnumber = $params{'itemnumber'};
463
464     return unless ($itemnumber);
465
466     my $course_item = GetCourseItem( itemnumber => $itemnumber );
467
468     my $ci_id;
469
470     if ($course_item) {
471         $ci_id = $course_item->{'ci_id'};
472
473         _UpdateCourseItem(
474             ci_id       => $ci_id,
475             course_item => $course_item,
476             %params
477         );
478     } else {
479         $ci_id = _AddCourseItem(%params);
480     }
481
482     return $ci_id;
483
484 }
485
486 =head2 _AddCourseItem
487
488     my $ci_id = _AddCourseItem( %params );
489
490 =cut
491
492 sub _AddCourseItem {
493     my (%params) = @_;
494     warn identify_myself(%params) if $DEBUG;
495
496     my ( @fields, @values );
497
498     push( @fields, 'itemnumber = ?' );
499     push( @values, $params{'itemnumber'} );
500
501     foreach (@FIELDS) {
502         push( @fields, "$_ = ?" );
503         push( @values, $params{$_} || undef );
504     }
505
506     my $query = "INSERT INTO course_items SET " . join( ',', @fields );
507     my $dbh = C4::Context->dbh;
508     $dbh->do( $query, undef, @values );
509
510     my $ci_id = $dbh->last_insert_id( undef, undef, 'course_items', 'ci_id' );
511
512     return $ci_id;
513 }
514
515 =head2 _UpdateCourseItem
516
517   _UpdateCourseItem( %params );
518
519 =cut
520
521 sub _UpdateCourseItem {
522     my (%params) = @_;
523     warn identify_myself(%params) if $DEBUG;
524
525     my $ci_id         = $params{'ci_id'};
526     my $course_item   = $params{'course_item'};
527
528     return unless ( $ci_id || $course_item );
529
530     $course_item = GetCourseItem( ci_id => $ci_id )
531       unless ($course_item);
532     $ci_id = $course_item->{'ci_id'} unless ($ci_id);
533
534     my %mod_params =
535       map {
536         defined $params{$_} && $params{$_} ne ''
537           ? ( $_ => $params{$_} )
538           : ()
539       } @FIELDS;
540
541     ModItem( \%mod_params, undef, $course_item->{'itemnumber'} );
542 }
543
544 =head2 _ModStoredFields
545
546     _ModStoredFields( %params );
547
548     Updates the values for the 'original' fields in course_items
549     for a given ci_id
550
551 =cut
552
553 sub _ModStoredFields {
554     my (%params) = @_;
555     warn identify_myself(%params) if $DEBUG;
556
557     return unless ( $params{'ci_id'} );
558
559     my ( @fields_to_update, @values_to_update );
560
561     foreach (@FIELDS) {
562         if ( defined($params{$_}) ) {
563             push( @fields_to_update, $_ );
564             push( @values_to_update, $params{$_} );
565         }
566     }
567
568     my $query = "UPDATE course_items SET " . join( ',', map { "$_=?" } @fields_to_update ) . " WHERE ci_id = ?";
569
570     C4::Context->dbh->do( $query, undef, @values_to_update, $params{'ci_id'} )
571       if (@values_to_update);
572
573 }
574
575 =head2 _RevertFields
576
577     _RevertFields( ci_id => $ci_id, fields => \@fields_to_revert );
578
579 =cut
580
581 sub _RevertFields {
582     my (%params) = @_;
583     warn identify_myself(%params) if $DEBUG;
584
585     my $ci_id = $params{'ci_id'};
586
587     return unless ($ci_id);
588
589     my $course_item = GetCourseItem( ci_id => $params{'ci_id'} );
590
591     my $mod_item_params;
592     foreach my $field ( @FIELDS ) {
593         $mod_item_params->{$field} = $course_item->{$field};
594     }
595
596     ModItem( $mod_item_params, undef, $course_item->{'itemnumber'} ) if $mod_item_params && %$mod_item_params;
597 }
598
599 =head2 _SwapAllFields
600
601     _SwapAllFields( $ci_id );
602
603 =cut
604
605 sub _SwapAllFields {
606     my ($ci_id) = @_;
607     warn "C4::CourseReserves::_SwapFields( $ci_id )" if $DEBUG;
608
609     my $course_item = GetCourseItem( ci_id => $ci_id );
610     my $item = Koha::Items->find($course_item->{'itemnumber'});
611
612     my %course_item_fields;
613     my %item_fields;
614     foreach (@FIELDS) {
615         if ( defined( $course_item->{$_} ) ) {
616             $course_item_fields{$_} = $course_item->{$_};
617             $item_fields{$_}        = $item->$_ || q{};
618         }
619     }
620
621     ModItem( \%course_item_fields, undef, $course_item->{'itemnumber'} ) if %course_item_fields;
622     _ModStoredFields( %item_fields, ci_id => $ci_id );
623 }
624
625 =head2 GetCourseItems {
626
627   $course_items = GetCourseItems(
628       [course_id => $course_id]
629       [, itemnumber => $itemnumber ]
630   );
631
632 =cut
633
634 sub GetCourseItems {
635     my (%params) = @_;
636     warn identify_myself(%params) if $DEBUG;
637
638     my $course_id  = $params{'course_id'};
639     my $itemnumber = $params{'itemnumber'};
640
641     return unless ($course_id);
642
643     my @query_keys;
644     my @query_values;
645
646     my $query = "SELECT * FROM course_items";
647
648     if ( keys %params ) {
649
650         $query .= " WHERE ";
651
652         foreach my $key ( keys %params ) {
653             push( @query_keys,   " $key LIKE ? " );
654             push( @query_values, $params{$key} );
655         }
656
657         $query .= join( ' AND ', @query_keys );
658     }
659
660     my $dbh = C4::Context->dbh;
661     my $sth = $dbh->prepare($query);
662     $sth->execute(@query_values);
663
664     return $sth->fetchall_arrayref( {} );
665 }
666
667 =head2 DelCourseItem {
668
669   DelCourseItem( ci_id => $cr_id );
670
671 =cut
672
673 sub DelCourseItem {
674     my (%params) = @_;
675     warn identify_myself(%params) if $DEBUG;
676
677     my $ci_id = $params{'ci_id'};
678
679     return unless ($ci_id);
680
681     _RevertFields( ci_id => $ci_id );
682
683     my $query = "
684         DELETE FROM course_items
685         WHERE ci_id = ?
686     ";
687     C4::Context->dbh->do( $query, undef, $ci_id );
688 }
689
690 =head2 GetCourseReserve {
691
692   $course_item = GetCourseReserve( %params );
693
694 =cut
695
696 sub GetCourseReserve {
697     my (%params) = @_;
698     warn identify_myself(%params) if $DEBUG;
699
700     my $cr_id     = $params{'cr_id'};
701     my $course_id = $params{'course_id'};
702     my $ci_id     = $params{'ci_id'};
703
704     return unless ( $cr_id || ( $course_id && $ci_id ) );
705
706     my $dbh = C4::Context->dbh;
707     my $sth;
708
709     if ($cr_id) {
710         my $query = "
711             SELECT * FROM course_reserves
712             WHERE cr_id = ?
713         ";
714         $sth = $dbh->prepare($query);
715         $sth->execute($cr_id);
716     } else {
717         my $query = "
718             SELECT * FROM course_reserves
719             WHERE course_id = ? AND ci_id = ?
720         ";
721         $sth = $dbh->prepare($query);
722         $sth->execute( $course_id, $ci_id );
723     }
724
725     my $course_reserve = $sth->fetchrow_hashref();
726     return $course_reserve;
727 }
728
729 =head2 ModCourseReserve
730
731     $id = ModCourseReserve( %params );
732
733 =cut
734
735 sub ModCourseReserve {
736     my (%params) = @_;
737     warn identify_myself(%params) if $DEBUG;
738
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'};
743
744     return unless ( $course_id && $ci_id );
745
746     my $course_reserve = GetCourseReserve( course_id => $course_id, ci_id => $ci_id );
747     my $cr_id;
748
749     my $dbh = C4::Context->dbh;
750
751     if ($course_reserve) {
752         $cr_id = $course_reserve->{'cr_id'};
753
754         my $query = "
755             UPDATE course_reserves
756             SET staff_note = ?, public_note = ?
757             WHERE cr_id = ?
758         ";
759         $dbh->do( $query, undef, $staff_note, $public_note, $cr_id );
760     } else {
761         my $query = "
762             INSERT INTO course_reserves SET
763             course_id = ?,
764             ci_id = ?,
765             staff_note = ?,
766             public_note = ?
767         ";
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' );
770     }
771
772     EnableOrDisableCourseItem(
773         ci_id   => $params{'ci_id'},
774     );
775
776     return $cr_id;
777 }
778
779 =head2 GetCourseReserves {
780
781   $course_reserves = GetCourseReserves( %params );
782
783   Required:
784       course_id OR ci_id
785   Optional:
786       include_items   => 1,
787       include_count   => 1,
788       include_courses => 1,
789
790 =cut
791
792 sub GetCourseReserves {
793     my (%params) = @_;
794     warn identify_myself(%params) if $DEBUG;
795
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'};
801
802     return unless ( $course_id || $ci_id );
803
804     my $field = ($course_id) ? 'course_id' : 'ci_id';
805     my $value = ($course_id) ? $course_id  : $ci_id;
806
807     my $query = "
808         SELECT cr.*, ci.itemnumber
809         FROM course_reserves cr, course_items ci
810         WHERE cr.$field = ?
811         AND cr.ci_id = ci.ci_id
812     ";
813     my $dbh = C4::Context->dbh;
814     my $sth = $dbh->prepare($query);
815     $sth->execute($value);
816
817     my $course_reserves = $sth->fetchall_arrayref( {} );
818
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'} );
829         }
830     }
831
832     if ($include_count) {
833         foreach my $cr (@$course_reserves) {
834             $cr->{'reserves_count'} = CountCourseReservesForItem( ci_id => $cr->{'ci_id'} );
835         }
836     }
837
838     if ($include_courses) {
839         foreach my $cr (@$course_reserves) {
840             $cr->{'courses'} = GetCourses( itemnumber => $cr->{'itemnumber'} );
841         }
842     }
843
844     return $course_reserves;
845 }
846
847 =head2 DelCourseReserve {
848
849   DelCourseReserve( cr_id => $cr_id );
850
851 =cut
852
853 sub DelCourseReserve {
854     my (%params) = @_;
855     warn identify_myself(%params) if $DEBUG;
856
857     my $cr_id = $params{'cr_id'};
858
859     return unless ($cr_id);
860
861     my $dbh = C4::Context->dbh;
862
863     my $course_reserve = GetCourseReserve( cr_id => $cr_id );
864
865     my $query = "
866         DELETE FROM course_reserves
867         WHERE cr_id = ?
868     ";
869     $dbh->do( $query, undef, $cr_id );
870
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'} );
875     }
876
877 }
878
879 =head2 GetItemCourseReservesInfo
880
881     my $arrayref = GetItemCourseReservesInfo( itemnumber => $itemnumber );
882
883     For a given item, returns an arrayref of reserves hashrefs,
884     with a course hashref under the key 'course'
885
886 =cut
887
888 sub GetItemCourseReservesInfo {
889     my (%params) = @_;
890     warn identify_myself(%params) if $DEBUG;
891
892     my $itemnumber = $params{'itemnumber'};
893
894     return unless ($itemnumber);
895
896     my $course_item = GetCourseItem( itemnumber => $itemnumber );
897
898     return unless ( keys %$course_item );
899
900     my $course_reserves = GetCourseReserves( ci_id => $course_item->{'ci_id'} );
901
902     foreach my $cr (@$course_reserves) {
903         $cr->{'course'} = GetCourse( $cr->{'course_id'} );
904     }
905
906     return $course_reserves;
907 }
908
909 =head2 CountCourseReservesForItem
910
911     $bool = CountCourseReservesForItem( %params );
912
913     ci_id - course_item id
914     OR
915     itemnumber - course_item itemnumber
916
917     enabled = 'yes' or 'no'
918     Optional, if not supplied, counts reserves
919     for both enabled and disabled courses
920
921 =cut
922
923 sub CountCourseReservesForItem {
924     my (%params) = @_;
925     warn identify_myself(%params) if $DEBUG;
926
927     my $ci_id      = $params{'ci_id'};
928     my $itemnumber = $params{'itemnumber'};
929     my $enabled    = $params{'enabled'};
930
931     return unless ( $ci_id || $itemnumber );
932
933     my $course_item = GetCourseItem( ci_id => $ci_id, itemnumber => $itemnumber );
934
935     my @params = ( $course_item->{'ci_id'} );
936     push( @params, $enabled ) if ($enabled);
937
938     my $query = "
939         SELECT COUNT(*) AS count
940         FROM course_reserves cr
941         LEFT JOIN courses c ON ( c.course_id = cr.course_id )
942         WHERE ci_id = ?
943     ";
944     $query .= "AND c.enabled = ?" if ($enabled);
945
946     my $dbh = C4::Context->dbh;
947     my $sth = $dbh->prepare($query);
948     $sth->execute(@params);
949
950     my $row = $sth->fetchrow_hashref();
951
952     return $row->{'count'};
953 }
954
955 =head2 SearchCourses
956
957     my $courses = SearchCourses( term => $search_term, enabled => 'yes' );
958
959 =cut
960
961 sub SearchCourses {
962     my (%params) = @_;
963     warn identify_myself(%params) if $DEBUG;
964
965     my $term = $params{'term'};
966
967     my $enabled = $params{'enabled'} || '%';
968
969     my @params;
970     my $query = "
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
972         FROM courses c
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 )
979         WHERE
980             ( av.category = 'DEPARTMENT' OR av.category = 'TERM' )
981             AND
982             (
983                 department LIKE ? OR
984                 course_number LIKE ? OR
985                 section LIKE ? OR
986                 course_name LIKE ? OR
987                 term LIKE ? OR
988                 public_note LIKE ? OR
989                 CONCAT(surname,' ',firstname) LIKE ? OR
990                 CONCAT(firstname,' ',surname) LIKE ? OR
991                 lib LIKE ? OR
992                 lib_opac LIKE ?
993            )
994            AND
995            c.enabled LIKE ?
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
997     ";
998
999     $term //= '';
1000     $term   = "%$term%";
1001     @params = ($term) x 10;
1002
1003     $query .= " ORDER BY department, course_number, section, term, course_name ";
1004
1005     my $dbh = C4::Context->dbh;
1006     my $sth = $dbh->prepare($query);
1007
1008     $sth->execute( @params, $enabled );
1009
1010     my $courses = $sth->fetchall_arrayref( {} );
1011
1012     foreach my $c (@$courses) {
1013         $c->{'instructors'} = GetCourseInstructors( $c->{'course_id'} );
1014     }
1015
1016     return $courses;
1017 }
1018
1019 sub whoami  { ( caller(1) )[3] }
1020 sub whowasi { ( caller(2) )[3] }
1021
1022 sub stringify_params {
1023     my (%params) = @_;
1024
1025     my $string = "\n";
1026
1027     foreach my $key ( keys %params ) {
1028         $string .= "    $key => " . $params{$key} . "\n";
1029     }
1030
1031     return "( $string )";
1032 }
1033
1034 sub identify_myself {
1035     my (%params) = @_;
1036
1037     return whowasi() . stringify_params(%params);
1038 }
1039
1040 1;
1041
1042 =head1 AUTHOR
1043
1044 Kyle M Hall <kyle@bywatersolutions.com>
1045
1046 =cut