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