import of the authorized values fails on the step 3 of the web-installation (ru-RU)
[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 use C4::Members;
30 require C4::Auth;
31
32 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);
33
34 BEGIN {
35         # set the version for version checking
36         $VERSION = 3.02;
37         require Exporter;
38         @ISA    = qw(Exporter);
39         @EXPORT = qw(
40             &GetShelves &GetShelfContents &GetShelf
41             &AddToShelf &AddToShelfFromBiblio &AddShelf
42             &ModShelf
43             &ShelfPossibleAction
44             &DelFromShelf &DelShelf
45         );
46         @EXPORT_OK = qw(
47             &GetShelvesSummary &GetRecentShelves
48             &RefreshShelvesSummary &SetShelvesLimit
49         );
50 }
51
52
53 my $dbh = C4::Context->dbh;
54
55 =head1 NAME
56
57 C4::VirtualShelves - Functions for manipulating Koha virtual virtualshelves
58
59 =head1 SYNOPSIS
60
61   use C4::VirtualShelves;
62
63 =head1 DESCRIPTION
64
65 This module provides functions for manipulating virtual virtualshelves,
66 including creating and deleting virtualshelves, and adding and removing
67 items to and from virtualshelves.
68
69 =head1 FUNCTIONS
70
71 =over 2
72
73 =item GetShelves
74
75   ($shelflist, $totshelves) = &GetShelves($mincategory, $row_count, $offset, $owner);
76   ($shelfnumber, $shelfhash) = each %{$shelflist};
77
78 Returns the number of shelves specified by C<$row_count> and C<$offset> as well as the total
79 number of shelves that meet the C<$owner> and C<$mincategory> criteria.  C<$mincategory>,
80 C<$row_count>, and C<$offset> are required. C<$owner> must be supplied when C<$mincategory> == 1.
81 When C<$mincategory> is 2 or 3, supply undef as argument for C<$owner>.
82 C<$shelflist>is a reference-to-hash. The keys are the virtualshelves numbers (C<$shelfnumber>, above),
83 and the values (C<$shelfhash>, above) are themselves references-to-hash, with the following keys:
84
85 =over 4
86
87 =item C<$shelfhash-E<gt>{shelfname}>
88
89 A string. The name of the shelf.
90
91 =item C<$shelfhash-E<gt>{count}>
92
93 The number of virtuals on that virtualshelves.
94
95 =back
96
97 =cut
98
99 sub GetShelves ($$$$) {
100     my ($mincategory, $row_count, $offset, $owner) = @_;
101         my @params = ($owner, $mincategory, ($offset ? $offset : 0), $row_count);
102         my @params1 = ($owner, $mincategory);
103         if ($mincategory > 1) {
104                 shift @params;
105                 shift @params1;
106         }
107         my $total = _shelf_count($owner, $mincategory);
108     # grab only the shelves meeting the row_count/offset spec...
109     my $query = qq(
110         SELECT virtualshelves.shelfnumber, virtualshelves.shelfname,owner,surname,firstname,virtualshelves.category,virtualshelves.sortfield,
111                count(virtualshelfcontents.biblionumber) as count
112         FROM   virtualshelves
113             LEFT JOIN   virtualshelfcontents ON virtualshelves.shelfnumber = virtualshelfcontents.shelfnumber
114             LEFT JOIN   borrowers ON virtualshelves.owner = borrowers.borrowernumber );
115     $query .= ($mincategory == 1) ? "WHERE  owner=? AND category=?" : "WHERE category>=?";
116         $query .= qq(
117         GROUP BY virtualshelves.shelfnumber
118         ORDER BY virtualshelves.category
119                 DESC 
120                 LIMIT ?, ?);
121     my $sth2 = $dbh->prepare($query);
122     $sth2->execute(@params);
123     my %shelflist;
124     while ( my ( $shelfnumber, $shelfname, $owner, $surname,
125                 $firstname,   $category,  $sortfield, $count ) = $sth2->fetchrow ) {
126         $shelflist{$shelfnumber}->{'shelfname'} = $shelfname;
127         $shelflist{$shelfnumber}->{'count'}     = $count;
128         $shelflist{$shelfnumber}->{'sortfield'} = $sortfield;
129         $shelflist{$shelfnumber}->{'category'}  = $category;
130         $shelflist{$shelfnumber}->{'owner'}     = $owner;
131         $shelflist{$shelfnumber}->{'surname'}   = $surname;
132         $shelflist{$shelfnumber}->{'firstname'} = $firstname;
133     }
134     return ( \%shelflist, $total );
135 }
136
137 =item GetShelvesSummary
138
139         ($shelves, $total) = GetShelvesSummary($mincategory, $row_count, $offset, $owner)
140
141 Returns the number of shelves specified by C<$row_count> and C<$offset> as well as the total
142 number of shelves that meet the C<$owner> and/or C<$mincategory> criteria. C<$mincategory>,
143 C<$row_count>, and C<$offset> are required. C<$owner> must be supplied when C<$mincategory> == 1.
144 When C<$mincategory> is 2 or 3, supply undef as argument for C<$owner>.
145
146 =cut
147
148 sub GetShelvesSummary ($$$$) {
149     my ($mincategory, $row_count, $offset, $owner) = @_;
150         my @params = ($owner, $mincategory, ($offset ? $offset : 0), $row_count);
151         my @params1 = ($owner, $mincategory);
152         if ($mincategory > 1) {
153                 shift @params;
154                 shift @params1;
155         }
156         my $total = _shelf_count($owner, $mincategory);
157     # grab only the shelves meeting the row_count/offset spec...
158         my $query = qq(
159                 SELECT
160                         virtualshelves.shelfnumber,
161                         virtualshelves.shelfname,
162                         owner,
163                         CONCAT(firstname, ' ', surname) AS name,
164                         virtualshelves.category,
165                         count(virtualshelfcontents.biblionumber) AS count
166                 FROM   virtualshelves
167                         LEFT JOIN  virtualshelfcontents ON virtualshelves.shelfnumber = virtualshelfcontents.shelfnumber
168                         LEFT JOIN             borrowers ON virtualshelves.owner = borrowers.borrowernumber );
169     $query .= ($mincategory == 1) ? "WHERE  owner=? AND category=?" : "WHERE category>=?";
170         $query .= qq(
171                 GROUP BY virtualshelves.shelfnumber
172                 ORDER BY virtualshelves.category
173                 DESC 
174                 LIMIT ?, ?);
175         my $sth2 = $dbh->prepare($query);
176         $sth2->execute(@params);
177     my $shelves = $sth2->fetchall_arrayref({});
178     return ($shelves, $total);
179
180         # Probably NOT the final implementation since it is still bulky (repeated hash keys).
181         # might like an array of rows of delimited values:
182         # 1|2||0|blacklist|112
183         # 2|6|Josh Ferraro|51|en_fuego|106
184 }
185
186 =item GetRecentShelves
187
188         ($shelflist) = GetRecentShelves(1, $limit, $owner)
189
190 This function returns a references to an array of hashrefs containing specified shelves sorted
191 by the date the shelf was last modified in descending order limited to the number of records
192 specified by C<$row_count>. If calling with C<$mincategory> other than 1, use undef as C<$owner>.
193
194 This function is intended to return a dataset reflecting the most recently active shelves for
195 the submitted parameters.
196
197 =cut
198
199 sub GetRecentShelves ($$$) {
200         my ($mincategory, $row_count, $owner) = @_;
201     my (@shelflist);
202         my $total = _shelf_count($owner, $mincategory);
203         my @params = ($owner, $mincategory, 0, $row_count);      #FIXME: offset is hardcoded here, but could be passed in for enhancements
204         shift @params if !$owner;
205         my $query = "SELECT * FROM virtualshelves";
206         $query .= ($owner ? " WHERE owner = ? AND category = ?" : " WHERE category >= ? ");
207         $query .= " ORDER BY lastmodified DESC LIMIT ?, ?";
208         my $sth = $dbh->prepare($query);
209         $sth->execute(@params);
210         @shelflist = $sth->fetchall_arrayref({});
211         return ( \@shelflist, $total );
212 }
213
214 =item GetShelf
215
216   (shelfnumber,shelfname,owner,category,sortfield) = &GetShelf($shelfnumber);
217
218 Looks up information about the contents of virtual virtualshelves number
219 C<$shelfnumber>
220
221 Returns the database's information on 'virtualshelves' table.
222
223 =cut
224
225 sub GetShelf ($) {
226     my ($shelfnumber) = @_;
227     my $query = qq(
228         SELECT shelfnumber, shelfname, owner, category, sortfield
229         FROM   virtualshelves
230         WHERE  shelfnumber=?
231     );
232     my $sth = $dbh->prepare($query);
233     $sth->execute($shelfnumber);
234     return $sth->fetchrow;
235 }
236
237 =item GetShelfContents
238
239   $itemlist = &GetShelfContents($shelfnumber);
240
241 Looks up information about the contents of virtual virtualshelves number
242 C<$shelfnumber>.  Sorted by a field in the biblio table.  copyrightdate 
243 gives a desc sort.
244
245 Returns a reference-to-array, whose elements are references-to-hash,
246 as returned by C<C4::Biblio::GetBiblioFromItemNumber>.
247
248 Note: the notforloan status comes from the itemtype, and where it equals 0
249 it does not ensure that related items.notforloan status is likewise 0. The
250 caller has to check any items on their own, possibly with CanBookBeIssued
251 from C4::Circulation.
252
253 =cut
254
255 sub GetShelfContents ($;$$$) {
256     my ($shelfnumber, $row_count, $offset, $sortfield) = @_;
257     my $dbh=C4::Context->dbh();
258         my $sth1 = $dbh->prepare("SELECT count(*) FROM virtualshelfcontents WHERE shelfnumber = ?");
259         $sth1->execute($shelfnumber);
260         my $total = $sth1->fetchrow;
261         if(!$sortfield) {
262                 my $sth2 = $dbh->prepare('SELECT sortfield FROM virtualshelves WHERE shelfnumber=?');
263                 $sth2->execute($shelfnumber);
264                 ($sortfield) = $sth2->fetchrow_array;
265         }
266     my $query =
267        " SELECT vc.biblionumber, vc.shelfnumber, vc.dateadded,
268                                 biblio.*, biblioitems.itemtype, itemtypes.*
269          FROM   virtualshelfcontents vc
270                  LEFT JOIN biblio      ON      vc.biblionumber =      biblio.biblionumber
271                  LEFT JOIN biblioitems ON  biblio.biblionumber = biblioitems.biblionumber
272                  LEFT JOIN itemtypes   ON biblioitems.itemtype = itemtypes.itemtype
273          WHERE  vc.shelfnumber=? ";
274         my @params = ($shelfnumber);
275         if($sortfield) {
276                 $query .= " ORDER BY ? ";
277                 $query .= " DESC " if ($sortfield eq 'copyrightdate');
278                 push (@params, $sortfield);
279         }
280     if($row_count){
281            $query .= " LIMIT ?, ? ";
282            push (@params, ($offset ? $offset : 0));
283            push (@params, $row_count);
284     }
285     my $sth3 = $dbh->prepare($query);
286         $sth3->execute(@params);
287         return ($sth3->fetchall_arrayref({}), $total);
288         # Like the perldoc says,
289         # returns reference-to-array, where each element is reference-to-hash of the row:
290         #   like [ $sth->fetchrow_hashref(), $sth->fetchrow_hashref() ... ] 
291         # Suitable for use in TMPL_LOOP.
292         # See http://search.cpan.org/~timb/DBI-1.601/DBI.pm#fetchall_arrayref
293         # or newer, for your version of DBI.
294 }
295
296 =item AddShelf
297
298   $shelfnumber = &AddShelf( $shelfname, $owner, $category);
299
300 Creates a new virtual virtualshelves with name C<$shelfname>, owner C<$owner> and category
301 C<$category>.
302
303 Returns a code to know what's happen.
304     * -1 : if this virtualshelves already exist.
305     * $shelfnumber : if success.
306
307 =cut
308
309 sub AddShelf {
310     my ( $shelfname, $owner, $category, $sortfield ) = @_;
311     my $query = qq(
312         SELECT *
313         FROM   virtualshelves
314         WHERE  shelfname=? AND owner=?
315     );
316     my $sth = $dbh->prepare($query);
317     $sth->execute($shelfname,$owner);
318     ( $sth->rows ) and return (-1);
319     $query = qq(
320         INSERT INTO virtualshelves
321             (shelfname,owner,category,sortfield)
322         VALUES (?,?,?,?)
323     );
324     $sth = $dbh->prepare($query);
325     $sth->execute( $shelfname, $owner, $category, $sortfield );
326     my $shelfnumber = $dbh->{'mysql_insertid'};
327     return ($shelfnumber);
328 }
329
330 =item AddToShelf
331
332   &AddToShelf($biblionumber, $shelfnumber);
333
334 Adds item number C<$biblionumber> to virtual virtualshelves number
335 C<$shelfnumber>, unless that item is already on that shelf.
336
337 =cut
338
339 #'
340 sub AddToShelf {
341     my ( $biblionumber, $shelfnumber ) = @_;
342     return unless $biblionumber;
343     my $query = qq(
344         SELECT *
345         FROM   virtualshelfcontents
346         WHERE  shelfnumber=? AND biblionumber=?
347     );
348     my $sth = $dbh->prepare($query);
349
350     $sth->execute( $shelfnumber, $biblionumber );
351     ($sth->rows) and return undef;      # already on shelf
352         $query = qq(
353                 INSERT INTO virtualshelfcontents
354                         (shelfnumber, biblionumber, flags)
355                 VALUES
356                         (?, ?, 0)
357         );
358         $sth = $dbh->prepare($query);
359         $sth->execute( $shelfnumber, $biblionumber );
360         $query = qq(UPDATE virtualshelves
361                                 SET lastmodified = CURRENT_TIMESTAMP
362                                 WHERE shelfnumber = ?);
363         $sth = $dbh->prepare($query);
364         $sth->execute( $shelfnumber );
365 }
366
367 =item AddToShelfFromBiblio
368  
369     &AddToShelfFromBiblio($biblionumber, $shelfnumber)
370
371     this function allow to add a virtual into the shelf number $shelfnumber
372     from biblionumber.
373
374 =cut
375
376 sub AddToShelfFromBiblio {
377     my ( $biblionumber, $shelfnumber ) = @_;
378     return unless $biblionumber;
379     my $query = qq(
380         SELECT *
381         FROM   virtualshelfcontents
382         WHERE  shelfnumber=? AND biblionumber=?
383     );
384     my $sth = $dbh->prepare($query);
385     $sth->execute( $shelfnumber, $biblionumber );
386     unless ( $sth->rows ) {
387         my $query =qq(
388             INSERT INTO virtualshelfcontents
389                 (shelfnumber, biblionumber, flags)
390             VALUES
391                 (?, ?, 0)
392         );
393         $sth = $dbh->prepare($query);
394         $sth->execute( $shelfnumber, $biblionumber );
395                 $query = qq(UPDATE virtualshelves
396                                         SET lastmodified = CURRENT_TIMESTAMP
397                                         WHERE shelfnumber = ?);
398                 $sth = $dbh->prepare($query);
399                 $sth->execute( $shelfnumber );
400     }
401 }
402
403 =item ModShelf
404
405 ModShelf($shelfnumber, $hashref)
406
407 Where $hashref->{column} = param
408
409 Modify the value into virtualshelves table with values given 
410 from hashref, which each key of the hashref should be
411 the name of a column of virtualshelves.
412
413 =cut
414
415 sub ModShelf {
416     my $shelfnumber = shift;
417     my $shelf = shift;
418
419     if (exists $shelf->{shelfnumber}) {
420         carp "Should not use ModShelf to change shelfnumber";
421         return;
422     }
423     unless (defined $shelfnumber and $shelfnumber =~ /^\d+$/) {
424         carp "Invalid shelfnumber passed to ModShelf: $shelfnumber";
425         return;
426     }
427
428         my $query = "UPDATE virtualshelves SET ";
429     my @bind_params = ();
430     my @set_clauses = ();
431
432         foreach my $column (keys %$shelf) {
433         push @set_clauses, "$column = ?";
434         push @bind_params, $shelf->{$column};
435     }
436
437     if ($#set_clauses == -1) {
438         carp "No columns to update passed to ModShelf";
439         return;
440     }
441     $query .= join(", ", @set_clauses);
442
443     $query .= " WHERE shelfnumber = ? ";
444     push @bind_params, $shelfnumber;
445
446     $debug and warn "ModShelf query:\n $query\n",
447                         "ModShelf query args: ", join(',', @bind_params), "\n";
448         my $sth = $dbh->prepare($query);
449         $sth->execute( @bind_params );
450 }
451
452 =item ShelfPossibleAction
453
454 ShelfPossibleAction($loggedinuser, $shelfnumber, $action);
455
456 C<$loggedinuser,$shelfnumber,$action>
457
458 $action can be "view" or "manage".
459
460 Returns 1 if the user can do the $action in the $shelfnumber shelf.
461 Returns 0 otherwise.
462
463 =cut
464
465 sub ShelfPossibleAction {
466     my ( $user, $shelfnumber, $action ) = @_;
467     my $query = qq(
468         SELECT owner,category
469         FROM   virtualshelves
470         WHERE  shelfnumber=?
471     );
472     my $sth = $dbh->prepare($query);
473     $sth->execute($shelfnumber);
474     my ( $owner, $category ) = $sth->fetchrow;
475         my $borrower = GetMemberDetails($user);
476         return 1 if ( $category >= 3);                                                  # open list
477     return 1 if (($category >= 2) and
478                                 defined($action) and $action eq 'view');        # public list, anybody can view
479     return 1 if (($category >= 2) and defined($user) and ($borrower->{authflags}->{superlibrarian} || $user == 0));     # public list, superlibrarian can edit/delete
480     return 1 if (defined($user)  and $owner  eq $user );        # user owns this list.  Check last.
481     return 0;
482 }
483
484 =item DelFromShelf
485
486   &DelFromShelf( $biblionumber, $shelfnumber);
487
488 Removes item number C<$biblionumber> from virtual virtualshelves number
489 C<$shelfnumber>. If the item wasn't on that virtualshelves to begin with,
490 nothing happens.
491
492 =cut
493
494 #'
495 sub DelFromShelf {
496     my ( $biblionumber, $shelfnumber ) = @_;
497     my $query = qq(
498         DELETE FROM virtualshelfcontents
499         WHERE  shelfnumber=? AND biblionumber=?
500     );
501     my $sth = $dbh->prepare($query);
502     $sth->execute( $shelfnumber, $biblionumber );
503 }
504
505 =item DelShelf (old version)
506
507   ($status, $msg) = &DelShelf($shelfnumber);
508
509 Deletes virtual virtualshelves number C<$shelfnumber>. The virtualshelves must
510 be empty.
511
512 Returns a two-element array, where C<$status> is 0 if the operation
513 was successful, or non-zero otherwise. C<$msg> is "Done" in case of
514 success, or an error message giving the reason for failure.
515
516 =item DelShelf (current version)
517
518   $Number = DelShelf($shelfnumber);
519
520 This function deletes the shelf number, and all of it's content.
521
522 =cut
523
524 sub DelShelf {
525         unless (@_) {
526                 carp "DelShelf called without valid argument (shelfnumber)";
527                 return undef;
528         }
529         my $sth = $dbh->prepare("DELETE FROM virtualshelves WHERE shelfnumber=?");
530         return $sth->execute(shift);
531 }
532
533 =item RefreshShelvesSummary
534
535         ($total, $pubshelves, $barshelves) = RefreshShelvesSummary($sessionID, $loggedinuser, $row_count);
536
537 Updates the current session and userenv with the most recent shelves
538
539 Returns the total number of shelves stored in the session/userenv along with two references each to an
540 array of hashes, one containing the C<$loggedinuser>'s private shelves and one containing all public/open shelves.
541
542 This function is used in conjunction with the 'Lists' button in masthead.inc.
543
544 =cut
545
546 sub RefreshShelvesSummary ($$$) {
547         
548         my ($sessionID, $loggedinuser, $row_count) = @_;
549         my $session = C4::Auth::get_session($sessionID);
550         my ($total, $totshelves, $barshelves, $pubshelves);
551
552         ($barshelves, $totshelves) = GetRecentShelves(1, $row_count, $loggedinuser);
553         $total->{'bartotal'} = $totshelves;
554         ($pubshelves, $totshelves) = GetRecentShelves(2, $row_count, undef);
555         $total->{'pubtotal'} = $totshelves;
556
557         # Update the current session with the latest shelves...
558         $session->param('barshelves', $barshelves->[0]);
559         $session->param('pubshelves', $pubshelves->[0]);
560         $session->param('totshelves', $total);
561
562         # likewise the userenv...
563         C4::Context->set_shelves_userenv('bar',$barshelves->[0]);
564         C4::Context->set_shelves_userenv('pub',$pubshelves->[0]);
565         C4::Context::set_shelves_userenv('tot',$total);
566
567         return ($total, $pubshelves, $barshelves);
568 }
569
570 # internal subs
571
572 sub _shelf_count ($$) {
573         my (@params) = @_;
574         # Find out how many shelves total meet the submitted criteria...
575         my $query = "SELECT count(*) FROM virtualshelves";
576         $query .= ($params[1] > 1) ? " WHERE category >= ?" : " WHERE  owner=? AND category=?";
577         shift @params if $params[1] > 1;
578         my $sth = $dbh->prepare($query);
579         $sth->execute(@params);
580         my $total = $sth->fetchrow;
581         return $total;
582 }
583
584 1;
585
586 __END__
587
588 =back
589
590 =head1 AUTHOR
591
592 Koha Developement team <info@koha.org>
593
594 =head1 SEE ALSO
595
596 C4::Circulation::Circ2(3)
597
598 =cut