kohabug 1875 Public lists/virtualshelves are displayed and viewable whether a patron...
[koha.git] / C4 / VirtualShelves.pm
1 # -*- tab-width: 8 -*-
2 # Please use 8-character tabs for this file (indents are every 4 characters)
3
4 package C4::VirtualShelves;
5
6
7 # Copyright 2000-2002 Katipo Communications
8 #
9 # This file is part of Koha.
10 #
11 # Koha is free software; you can redistribute it and/or modify it under the
12 # terms of the GNU General Public License as published by the Free Software
13 # Foundation; either version 2 of the License, or (at your option) any later
14 # version.
15 #
16 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
17 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
18 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
19 #
20 # You should have received a copy of the GNU General Public License along with
21 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
22 # Suite 330, Boston, MA  02111-1307 USA
23
24 use strict;
25 use Carp;
26 use C4::Context;
27 use C4::Circulation;
28 use C4::Debug;
29
30 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
31
32 BEGIN {
33         # set the version for version checking
34         $VERSION = 3.02;
35         require Exporter;
36         @ISA    = qw(Exporter);
37         @EXPORT = qw(
38         &GetShelves &GetShelfContents &GetShelf
39
40         &AddToShelf &AddToShelfFromBiblio &AddShelf
41
42         &ModShelf
43         &ShelfPossibleAction
44         &DelFromShelf &DelShelf
45         );
46         @EXPORT_OK = qw(&GetShelvesSummary);
47 }
48
49 my $dbh = C4::Context->dbh;
50
51 =head1 NAME
52
53 C4::VirtualShelves - Functions for manipulating Koha virtual virtualshelves
54
55 =head1 SYNOPSIS
56
57   use C4::VirtualShelves;
58
59 =head1 DESCRIPTION
60
61 This module provides functions for manipulating virtual virtualshelves,
62 including creating and deleting virtualshelves, and adding and removing
63 items to and from virtualshelves.
64
65 =head1 FUNCTIONS
66
67 =over 2
68
69 =item GetShelves
70
71   $shelflist = &GetShelves($owner);
72   $shelflist = &GetShelves($owner, $mincategory);
73   $shelflist = &GetShelves($owner, $mincategory, $limit);
74   ($shelfnumber, $shelfhash) = each %{$shelflist};
75
76 Looks up the virtual virtualshelves, and returns a summary. C<$shelflist>
77 is a reference-to-hash. The keys are the virtualshelves numbers
78 (C<$shelfnumber>, above), and the values (C<$shelfhash>, above) are
79 themselves references-to-hash, with the following keys:
80
81 C<mincategory> : 2 if the list is for "Public", 3 for "Open".
82 virtualshelves of the owner are always selected, whatever the category
83
84 =over 4
85
86 =item C<$shelfhash-E<gt>{shelfname}>
87
88 A string. The name of the shelf.
89
90 =item C<$shelfhash-E<gt>{count}>
91
92 The number of virtuals on that virtualshelves.
93
94 =back
95
96 =cut
97
98 sub GetShelves {
99     my ($owner, $mincategory, $limit) = @_;
100         ($mincategory and $mincategory =~ /^\d+$/) or $mincategory = 2;
101         (      $limit and       $limit =~ /^\d+$/) or $limit = undef;
102     my $query = qq(
103         SELECT virtualshelves.shelfnumber, virtualshelves.shelfname,owner,surname,firstname,virtualshelves.category,virtualshelves.sortfield,
104                count(virtualshelfcontents.biblionumber) as count
105         FROM   virtualshelves
106             LEFT JOIN   virtualshelfcontents ON virtualshelves.shelfnumber = virtualshelfcontents.shelfnumber
107             LEFT JOIN   borrowers ON virtualshelves.owner = borrowers.borrowernumber
108         WHERE  owner=? OR category>=?
109         GROUP BY virtualshelves.shelfnumber
110         ORDER BY virtualshelves.category, virtualshelves.shelfname, borrowers.firstname, borrowers.surname
111     );
112         $limit and $query .= " LIMIT $limit ";
113     my $sth = $dbh->prepare($query);
114     $sth->execute( $owner, $mincategory );
115     my %shelflist;
116     while (
117         my (
118             $shelfnumber, $shelfname, $owner, $surname,
119             $firstname,   $category,  $sortfield, $count
120         )
121         = $sth->fetchrow
122       )
123     {
124         $shelflist{$shelfnumber}->{'shelfname'} = $shelfname;
125         $shelflist{$shelfnumber}->{'count'}     = $count;
126         $shelflist{$shelfnumber}->{'sortfield'} = $sortfield;
127         $shelflist{$shelfnumber}->{'category'}  = $category;
128         $shelflist{$shelfnumber}->{'owner'}     = $owner;
129         $shelflist{$shelfnumber}->{'surname'}   = $surname;
130         $shelflist{$shelfnumber}->{'firstname'} = $firstname;
131     }
132     return ( \%shelflist );
133 }
134
135 sub GetShelvesSummary {
136     my ($owner, $mincategory, $limit) = @_;
137         ($mincategory and $mincategory =~ /^\d+$/) or $mincategory = 2;
138         (      $limit and       $limit =~ /^\d+$/) or $limit = 10;
139     my $query = qq(
140                 SELECT
141                         virtualshelves.shelfnumber,
142                         virtualshelves.shelfname,
143                         owner,
144                         CONCAT(firstname, ' ', surname) AS name,
145                         virtualshelves.category,
146                         count(virtualshelfcontents.biblionumber) AS count
147                 FROM   virtualshelves
148                         LEFT JOIN  virtualshelfcontents ON virtualshelves.shelfnumber = virtualshelfcontents.shelfnumber
149                         LEFT JOIN             borrowers ON virtualshelves.owner = borrowers.borrowernumber
150                 WHERE  owner=? OR category>=?
151                 GROUP BY virtualshelves.shelfnumber
152                 ORDER BY virtualshelves.category, borrowers.surname, borrowers.firstname, virtualshelves.shelfname
153                 LIMIT ?
154         );
155         my $sth = $dbh->prepare($query);
156         $sth->execute($owner,$mincategory,$limit);
157
158     my $shelves = $sth->fetchall_arrayref({});
159     # add private flag to each shelf entry --
160     # need to do this because HTML::Template::Pro's EXPR
161     # support complains about a non-initialized 'category'
162     # if the user has no shelves -- the offending line in
163     # masthead.inc was <-- TMPL_IF EXPR="category == 1"...
164     foreach my $shelf (@{ $shelves }) {
165         $shelf->{'private'} = ($shelf->{'category'} == 1);
166     }
167     return $shelves;
168
169         # Probably NOT the final implementation since it is still bulky (repeated hash keys).
170         # might like an array of rows of delimited values:
171         # 1|2||0|blacklist|112
172         # 2|6|Josh Ferraro|51|en_fuego|106
173 }
174
175 =item GetShelf
176
177   (shelfnumber,shelfname,owner,category,sortfield) = &GetShelf($shelfnumber);
178
179 Looks up information about the contents of virtual virtualshelves number
180 C<$shelfnumber>
181
182 Returns the database's information on 'virtualshelves' table.
183
184 =cut
185
186 sub GetShelf {
187     my ($shelfnumber) = @_;
188     my $query = qq(
189         SELECT shelfnumber, shelfname, owner, category, sortfield
190         FROM   virtualshelves
191         WHERE  shelfnumber=?
192     );
193     my $sth = $dbh->prepare($query);
194     $sth->execute($shelfnumber);
195     return $sth->fetchrow;
196 }
197
198 =item GetShelfContents
199
200   $itemlist = &GetShelfContents($shelfnumber);
201
202 Looks up information about the contents of virtual virtualshelves number
203 C<$shelfnumber>.  Sorted by a field in the biblio table.  copyrightdate 
204 gives a desc sort.
205
206 Returns a reference-to-array, whose elements are references-to-hash,
207 as returned by C<C4::Biblio::GetBiblioFromItemNumber>.
208
209 Note: the notforloan status comes from the itemtype, and where it equals 0
210 it does not ensure that related items.notforloan status is likewise 0. The
211 caller has to check any items on their own, possibly with CanBookBeIssued
212 from C4::Circulation.
213
214 =cut
215
216 sub GetShelfContents {
217     my ( $shelfnumber ,$sortfield) = @_;
218     my $dbh=C4::Context->dbh();
219         if(!$sortfield) {
220                 my $sthsort = $dbh->prepare('select sortfield from virtualshelves where shelfnumber=?');
221                 $sthsort->execute($shelfnumber);
222                 ($sortfield) = $sthsort->fetchrow_array;
223         }
224     my $query =
225        " SELECT vc.biblionumber, vc.shelfnumber,
226                                 biblio.*, biblioitems.itemtype, itemtypes.*
227          FROM   virtualshelfcontents vc
228                  LEFT JOIN biblio      ON      vc.biblionumber =      biblio.biblionumber
229                  LEFT JOIN biblioitems ON  biblio.biblionumber = biblioitems.biblionumber
230                  LEFT JOIN itemtypes   ON biblioitems.itemtype = itemtypes.itemtype
231          WHERE  vc.shelfnumber=? ";
232         if($sortfield) {
233                 $query .= " ORDER BY `$sortfield` ";
234                 $query .= " DESC " if ($sortfield eq 'copyrightdate');
235         }
236     my $sth = $dbh->prepare($query);
237         $sth->execute($shelfnumber);
238         return $sth->fetchall_arrayref({});     
239         # Like the perldoc says,
240         # returns reference-to-array, where each element is reference-to-hash of the row:
241         #   like [ $sth->fetchrow_hashref(), $sth->fetchrow_hashref() ... ] 
242         # Suitable for use in TMPL_LOOP.
243         # See http://search.cpan.org/~timb/DBI-1.601/DBI.pm#fetchall_arrayref
244         # or newer, for your version of DBI.
245 }
246
247 =item AddShelf
248
249   $shelfnumber = &AddShelf( $shelfname, $owner, $category);
250
251 Creates a new virtual virtualshelves with name C<$shelfname>, owner C<$owner> and category
252 C<$category>.
253
254 Returns a code to know what's happen.
255     * -1 : if this virtualshelves already exist.
256     * $shelfnumber : if success.
257
258 =cut
259
260 sub AddShelf {
261     my ( $shelfname, $owner, $category ) = @_;
262     my $query = qq(
263         SELECT *
264         FROM   virtualshelves
265         WHERE  shelfname=? AND owner=?
266     );
267     my $sth = $dbh->prepare($query);
268     $sth->execute($shelfname,$owner);
269     ( $sth->rows ) and return (-1);
270     $query = qq(
271         INSERT INTO virtualshelves
272             (shelfname,owner,category)
273         VALUES (?,?,?)
274     );
275     $sth = $dbh->prepare($query);
276     $sth->execute( $shelfname, $owner, $category );
277     my $shelfnumber = $dbh->{'mysql_insertid'};
278     return ($shelfnumber);
279 }
280
281 =item AddToShelf
282
283   &AddToShelf($biblionumber, $shelfnumber);
284
285 Adds item number C<$biblionumber> to virtual virtualshelves number
286 C<$shelfnumber>, unless that item is already on that shelf.
287
288 =cut
289
290 #'
291 sub AddToShelf {
292     my ( $biblionumber, $shelfnumber ) = @_;
293     return unless $biblionumber;
294     my $query = qq(
295         SELECT *
296         FROM   virtualshelfcontents
297         WHERE  shelfnumber=? AND biblionumber=?
298     );
299     my $sth = $dbh->prepare($query);
300
301     $sth->execute( $shelfnumber, $biblionumber );
302     ($sth->rows) and return undef;      # already on shelf
303         $query = qq(
304                 INSERT INTO virtualshelfcontents
305                         (shelfnumber, biblionumber, flags)
306                 VALUES
307                         (?, ?, 0)
308         );
309         $sth = $dbh->prepare($query);
310         $sth->execute( $shelfnumber, $biblionumber );
311 }
312
313 =item AddToShelfFromBiblio
314  
315     &AddToShelfFromBiblio($biblionumber, $shelfnumber)
316
317     this function allow to add a virtual into the shelf number $shelfnumber
318     from biblionumber.
319
320 =cut
321
322 sub AddToShelfFromBiblio {
323     my ( $biblionumber, $shelfnumber ) = @_;
324     return unless $biblionumber;
325     my $query = qq(
326         SELECT *
327         FROM   virtualshelfcontents
328         WHERE  shelfnumber=? AND biblionumber=?
329     );
330     my $sth = $dbh->prepare($query);
331     $sth->execute( $shelfnumber, $biblionumber );
332     unless ( $sth->rows ) {
333         my $query =qq(
334             INSERT INTO virtualshelfcontents
335                 (shelfnumber, biblionumber, flags)
336             VALUES
337                 (?, ?, 0)
338         );
339         $sth = $dbh->prepare($query);
340         $sth->execute( $shelfnumber, $biblionumber );
341     }
342 }
343
344 =item ModShelf
345
346 ModShelf($shelfnumber, $hashref)
347
348 Where $hashref->{column} = param
349
350 Modify the value into virtualshelves table with values given 
351 from hashref, which each key of the hashref should be
352 the name of a column of virtualshelves.
353
354 =cut
355
356 sub ModShelf {
357     my $shelfnumber = shift;
358     my $shelf = shift;
359
360     if (exists $shelf->{shelfnumber}) {
361         carp "Should not use ModShelf to change shelfnumber";
362         return;
363     }
364     unless (defined $shelfnumber and $shelfnumber =~ /^\d+$/) {
365         carp "Invalid shelfnumber passed to ModShelf: $shelfnumber";
366         return;
367     }
368
369         my $query = "UPDATE virtualshelves SET ";
370     my @bind_params = ();
371     my @set_clauses = ();
372
373         foreach my $column (keys %$shelf) {
374         push @set_clauses, "$column = ?";
375         push @bind_params, $shelf->{$column};
376     }
377
378     if ($#set_clauses == -1) {
379         carp "No columns to update passed to ModShelf";
380         return;
381     }
382     $query .= join(", ", @set_clauses);
383
384     $query .= " WHERE shelfnumber = ? ";
385     push @bind_params, $shelfnumber;
386
387     $debug and warn "ModShelf query:\n $query\n",
388                         "ModShelf query args: ", join(',', @bind_params), "\n";
389         my $sth = $dbh->prepare($query);
390         $sth->execute( @bind_params );
391 }
392
393 =item ShelfPossibleAction
394
395 ShelfPossibleAction($loggedinuser, $shelfnumber, $action);
396
397 C<$loggedinuser,$shelfnumber,$action>
398
399 $action can be "view" or "manage".
400
401 Returns 1 if the user can do the $action in the $shelfnumber shelf.
402 Returns 0 otherwise.
403
404 =cut
405
406 sub ShelfPossibleAction {
407     my ( $user, $shelfnumber, $action ) = @_;
408     my $query = qq(
409         SELECT owner,category
410         FROM   virtualshelves
411         WHERE  shelfnumber=?
412     );
413     my $sth = $dbh->prepare($query);
414     $sth->execute($shelfnumber);
415     my ( $owner, $category ) = $sth->fetchrow;
416     return 1 if ( $category >= 3);                                                      # open list
417     return 1 if (($category >= 2) and
418                                 defined($action) and $action eq 'view');        # public list, anybody can view
419     return 1 if (defined($user)  and $owner  eq $user );        # user owns this list.  Check last.
420     return 0;
421 }
422
423 =item DelFromShelf
424
425   &DelFromShelf( $biblionumber, $shelfnumber);
426
427 Removes item number C<$biblionumber> from virtual virtualshelves number
428 C<$shelfnumber>. If the item wasn't on that virtualshelves to begin with,
429 nothing happens.
430
431 =cut
432
433 #'
434 sub DelFromShelf {
435     my ( $biblionumber, $shelfnumber ) = @_;
436     my $query = qq(
437         DELETE FROM virtualshelfcontents
438         WHERE  shelfnumber=? AND biblionumber=?
439     );
440     my $sth = $dbh->prepare($query);
441     $sth->execute( $shelfnumber, $biblionumber );
442 }
443
444 =item DelShelf (old version)
445
446   ($status, $msg) = &DelShelf($shelfnumber);
447
448 Deletes virtual virtualshelves number C<$shelfnumber>. The virtualshelves must
449 be empty.
450
451 Returns a two-element array, where C<$status> is 0 if the operation
452 was successful, or non-zero otherwise. C<$msg> is "Done" in case of
453 success, or an error message giving the reason for failure.
454
455 =item DelShelf (current version)
456
457   $Number = DelShelf($shelfnumber);
458
459 This function deletes the shelf number, and all of it's content.
460
461 =cut
462
463 sub DelShelf {
464         unless (@_) {
465                 carp "DelShelf called without valid argument (shelfnumber)";
466                 return undef;
467         }
468         my $sth = $dbh->prepare("DELETE FROM virtualshelves WHERE shelfnumber=?");
469         return $sth->execute(shift);
470 }
471
472 1;
473
474 __END__
475
476 =back
477
478 =head1 AUTHOR
479
480 Koha Developement team <info@koha.org>
481
482 =head1 SEE ALSO
483
484 C4::Circulation::Circ2(3)
485
486 =cut