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