]> git.koha-community.org Git - koha.git/blob - C4/RotatingCollections.pm
Bug 18854: Make sure offset will not be < 0 - protect from DoS
[koha.git] / C4 / RotatingCollections.pm
1 package C4::RotatingCollections;
2
3 # $Id: RotatingCollections.pm,v 0.1 2007/04/20 kylemhall
4
5 # This package is inteded to keep track of what library
6 # Items of a certain collection should be at.
7
8 # Copyright 2007 Kyle Hall
9 #
10 # This file is part of Koha.
11 #
12 # Koha is free software; you can redistribute it and/or modify it
13 # under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 3 of the License, or
15 # (at your option) any later version.
16 #
17 # Koha is distributed in the hope that it will be useful, but
18 # WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
21 #
22 # You should have received a copy of the GNU General Public License
23 # along with Koha; if not, see <http://www.gnu.org/licenses>.
24
25 use Modern::Perl;
26
27 use C4::Context;
28 use C4::Circulation;
29 use C4::Reserves qw(CheckReserves);
30 use Koha::Database;
31
32 use DBI;
33
34 use Data::Dumper;
35
36 use vars qw(@ISA @EXPORT);
37
38
39 =head1 NAME
40
41 C4::RotatingCollections - Functions for managing rotating collections
42
43 =head1 FUNCTIONS
44
45 =cut
46
47 BEGIN {
48     require Exporter;
49     @ISA    = qw( Exporter );
50     @EXPORT = qw(
51       CreateCollection
52       UpdateCollection
53       DeleteCollection
54
55       GetItemsInCollection
56
57       GetCollection
58       GetCollections
59
60       AddItemToCollection
61       RemoveItemFromCollection
62       TransferCollection
63
64       GetCollectionItemBranches
65     );
66 }
67
68 =head2  CreateCollection
69  ( $success, $errorcode, $errormessage ) = CreateCollection( $title, $description );
70  Creates a new collection
71
72  Input:
73    $title: short description of the club or service
74    $description: long description of the club or service
75
76  Output:
77    $success: 1 if all database operations were successful, 0 otherwise
78    $errorCode: Code for reason of failure, good for translating errors in templates
79    $errorMessage: English description of error
80
81 =cut
82
83 sub CreateCollection {
84     my ( $title, $description ) = @_;
85
86     my $schema = Koha::Database->new()->schema();
87     my $duplicate_titles = $schema->resultset('Collection')->count({ colTitle => $title });
88
89     ## Check for all necessary parameters
90     if ( !$title ) {
91         return ( 0, 1, "NO_TITLE" );
92     } elsif ( $duplicate_titles ) {
93         return ( 0, 2, "DUPLICATE_TITLE" );
94     }
95
96     $description ||= q{};
97
98     my $success = 1;
99
100     my $dbh = C4::Context->dbh;
101
102     my $sth;
103     $sth = $dbh->prepare(
104         "INSERT INTO collections ( colId, colTitle, colDesc )
105                         VALUES ( NULL, ?, ? )"
106     );
107     $sth->execute( $title, $description ) or return ( 0, 3, $sth->errstr() );
108
109     return 1;
110
111 }
112
113 =head2 UpdateCollection
114
115  ( $success, $errorcode, $errormessage ) = UpdateCollection( $colId, $title, $description );
116
117 Updates a collection
118
119  Input:
120    $colId: id of the collection to be updated
121    $title: short description of the club or service
122    $description: long description of the club or service
123
124  Output:
125    $success: 1 if all database operations were successful, 0 otherwise
126    $errorCode: Code for reason of failure, good for translating errors in templates
127    $errorMessage: English description of error
128
129 =cut
130
131 sub UpdateCollection {
132     my ( $colId, $title, $description ) = @_;
133
134     my $schema = Koha::Database->new()->schema();
135     my $duplicate_titles = $schema->resultset('Collection')->count({ colTitle => $title,  -not => { colId => $colId } });
136
137     ## Check for all necessary parameters
138     if ( !$colId ) {
139         return ( 0, 1, "NO_ID" );
140     }
141     if ( !$title ) {
142         return ( 0, 2, "NO_TITLE" );
143     }
144     if ( $duplicate_titles ) {
145         return ( 0, 3, "DUPLICATE_TITLE" );
146     }
147
148     my $dbh = C4::Context->dbh;
149
150     $description ||= q{};
151
152     my $sth;
153     $sth = $dbh->prepare(
154         "UPDATE collections
155                         SET 
156                         colTitle = ?, colDesc = ? 
157                         WHERE colId = ?"
158     );
159     $sth->execute( $title, $description, $colId )
160       or return ( 0, 4, $sth->errstr() );
161
162     return 1;
163
164 }
165
166 =head2 DeleteCollection
167
168  ( $success, $errorcode, $errormessage ) = DeleteCollection( $colId );
169  Deletes a collection of the given id
170
171  Input:
172    $colId : id of the Archetype to be deleted
173
174  Output:
175    $success: 1 if all database operations were successful, 0 otherwise
176    $errorCode: Code for reason of failure, good for translating errors in templates
177    $errorMessage: English description of error
178
179 =cut
180
181 sub DeleteCollection {
182     my ($colId) = @_;
183
184     ## Parameter check
185     if ( !$colId ) {
186         return ( 0, 1, "NO_ID" );
187     }
188
189     my $dbh = C4::Context->dbh;
190
191     my $sth;
192
193     $sth = $dbh->prepare("DELETE FROM collections WHERE colId = ?");
194     $sth->execute($colId) or return ( 0, 4, $sth->errstr() );
195
196     return 1;
197 }
198
199 =head2 GetCollections
200
201  $collections = GetCollections();
202  Returns data about all collections
203
204  Output:
205   On Success:
206    $results: Reference to an array of associated arrays
207   On Failure:
208    $errorCode: Code for reason of failure, good for translating errors in templates
209    $errorMessage: English description of error
210
211 =cut
212
213 sub GetCollections {
214
215     my $dbh = C4::Context->dbh;
216
217     my $sth = $dbh->prepare("SELECT * FROM collections");
218     $sth->execute() or return ( 1, $sth->errstr() );
219
220     my @results;
221     while ( my $row = $sth->fetchrow_hashref ) {
222         push( @results, $row );
223     }
224
225     return \@results;
226 }
227
228 =head2 GetItemsInCollection
229
230  ( $results, $success, $errorcode, $errormessage ) = GetItemsInCollection( $colId );
231
232  Returns information about the items in the given collection
233  
234  Input:
235    $colId: The id of the collection
236
237  Output:
238    $results: Reference to an array of associated arrays
239    $success: 1 if all database operations were successful, 0 otherwise
240    $errorCode: Code for reason of failure, good for translating errors in templates
241    $errorMessage: English description of error
242
243 =cut
244
245 sub GetItemsInCollection {
246     my ($colId) = @_;
247
248     ## Parameter check
249     if ( !$colId ) {
250         return ( 0, 0, 1, "NO_ID" );
251     }
252
253     my $dbh = C4::Context->dbh;
254
255     my $sth = $dbh->prepare(
256         "SELECT
257                              biblio.title,
258                              biblio.biblionumber,
259                              items.itemcallnumber,
260                              items.barcode
261                            FROM collections, collections_tracking, items, biblio
262                            WHERE collections.colId = collections_tracking.colId
263                            AND collections_tracking.itemnumber = items.itemnumber
264                            AND items.biblionumber = biblio.biblionumber
265                            AND collections.colId = ? ORDER BY biblio.title"
266     );
267     $sth->execute($colId) or return ( 0, 0, 2, $sth->errstr() );
268
269     my @results;
270     while ( my $row = $sth->fetchrow_hashref ) {
271         push( @results, $row );
272     }
273
274     return \@results;
275 }
276
277 =head2 GetCollection
278
279  ( $colId, $colTitle, $colDesc, $colBranchcode ) = GetCollection( $colId );
280
281 Returns information about a collection
282
283  Input:
284    $colId: Id of the collection
285  Output:
286    $colId, $colTitle, $colDesc, $colBranchcode
287
288 =cut
289
290 sub GetCollection {
291     my ($colId) = @_;
292
293     my $dbh = C4::Context->dbh;
294
295     my ( $sth, @results );
296     $sth = $dbh->prepare("SELECT * FROM collections WHERE colId = ?");
297     $sth->execute($colId) or return 0;
298
299     my $row = $sth->fetchrow_hashref;
300
301     return (
302         $$row{'colId'},   $$row{'colTitle'},
303         $$row{'colDesc'}, $$row{'colBranchcode'}
304     );
305
306 }
307
308 =head2 AddItemToCollection
309
310  ( $success, $errorcode, $errormessage ) = AddItemToCollection( $colId, $itemnumber );
311
312 Adds an item to a rotating collection.
313
314  Input:
315    $colId: Collection to add the item to.
316    $itemnumber: Item to be added to the collection
317  Output:
318    $success: 1 if all database operations were successful, 0 otherwise
319    $errorCode: Code for reason of failure, good for translating errors in templates
320    $errorMessage: English description of error
321
322 =cut
323
324 sub AddItemToCollection {
325     my ( $colId, $itemnumber ) = @_;
326
327     ## Check for all necessary parameters
328     if ( !$colId ) {
329         return ( 0, 1, "NO_ID" );
330     }
331     if ( !$itemnumber ) {
332         return ( 0, 2, "NO_ITEM" );
333     }
334
335     if ( isItemInThisCollection( $itemnumber, $colId ) ) {
336         return ( 0, 2, "IN_COLLECTION" );
337     }
338     elsif ( isItemInAnyCollection($itemnumber) ) {
339         return ( 0, 3, "IN_COLLECTION_OTHER" );
340     }
341
342     my $dbh = C4::Context->dbh;
343
344     my $sth;
345     $sth = $dbh->prepare("
346         INSERT INTO collections_tracking (
347             colId,
348             itemnumber
349         ) VALUES ( ?, ? )
350     ");
351     $sth->execute( $colId, $itemnumber ) or return ( 0, 3, $sth->errstr() );
352
353     return 1;
354
355 }
356
357 =head2  RemoveItemFromCollection
358
359  ( $success, $errorcode, $errormessage ) = RemoveItemFromCollection( $colId, $itemnumber );
360
361 Removes an item to a collection
362
363  Input:
364    $colId: Collection to add the item to.
365    $itemnumber: Item to be removed from collection
366
367  Output:
368    $success: 1 if all database operations were successful, 0 otherwise
369    $errorCode: Code for reason of failure, good for translating errors in templates
370    $errorMessage: English description of error
371
372 =cut
373
374 sub RemoveItemFromCollection {
375     my ( $colId, $itemnumber ) = @_;
376
377     ## Check for all necessary parameters
378     if ( !$itemnumber ) {
379         return ( 0, 2, "NO_ITEM" );
380     }
381
382     if ( !isItemInThisCollection( $itemnumber, $colId ) ) {
383         return ( 0, 2, "NOT_IN_COLLECTION" );
384     }
385
386     my $dbh = C4::Context->dbh;
387
388     my $sth;
389     $sth = $dbh->prepare(
390         "DELETE FROM collections_tracking
391                         WHERE itemnumber = ?"
392     );
393     $sth->execute($itemnumber) or return ( 0, 3, $sth->errstr() );
394
395     return 1;
396 }
397
398 =head2 TransferCollection
399
400  ( $success, $errorcode, $errormessage ) = TransferCollection( $colId, $colBranchcode );
401
402 Transfers a collection to another branch
403
404  Input:
405    $colId: id of the collection to be updated
406    $colBranchcode: branch where collection is moving to
407
408  Output:
409    $success: 1 if all database operations were successful, 0 otherwise
410    $errorCode: Code for reason of failure, good for translating errors in templates
411    $errorMessage: English description of error
412
413 =cut
414
415 sub TransferCollection {
416     my ( $colId, $colBranchcode ) = @_;
417
418     ## Check for all necessary parameters
419     if ( !$colId ) {
420         return ( 0, 1, "NO_ID" );
421     }
422     if ( !$colBranchcode ) {
423         return ( 0, 2, "NO_BRANCHCODE" );
424     }
425
426     my $dbh = C4::Context->dbh;
427
428     my $sth;
429     $sth = $dbh->prepare(
430         "UPDATE collections
431                         SET 
432                         colBranchcode = ? 
433                         WHERE colId = ?"
434     );
435     $sth->execute( $colBranchcode, $colId ) or return ( 0, 4, $sth->errstr() );
436
437     $sth = $dbh->prepare(q{
438         SELECT items.itemnumber, items.barcode FROM collections_tracking
439         LEFT JOIN items ON collections_tracking.itemnumber = items.itemnumber
440         LEFT JOIN issues ON items.itemnumber = issues.itemnumber
441         WHERE issues.borrowernumber IS NULL
442           AND collections_tracking.colId = ?
443     });
444     $sth->execute($colId) or return ( 0, 4, $sth->errstr );
445     my @results;
446     while ( my $item = $sth->fetchrow_hashref ) {
447         my ($status) = CheckReserves( $item->{itemnumber} );
448         my @transfers = C4::Circulation::GetTransfers( $item->{itemnumber} );
449         C4::Circulation::transferbook( $colBranchcode, $item->{barcode}, my $ignore_reserves = 1 ) unless ( $status eq 'Waiting' || @transfers );
450     }
451
452     return 1;
453
454 }
455
456 =head2 GetCollectionItemBranches
457
458   my ( $holdingBranch, $collectionBranch ) = GetCollectionItemBranches( $itemnumber );
459
460 =cut
461
462 sub GetCollectionItemBranches {
463     my ($itemnumber) = @_;
464
465     if ( !$itemnumber ) {
466         return;
467     }
468
469     my $dbh = C4::Context->dbh;
470
471     my ( $sth, @results );
472     $sth = $dbh->prepare(
473 "SELECT holdingbranch, colBranchcode FROM items, collections, collections_tracking
474                         WHERE items.itemnumber = collections_tracking.itemnumber
475                         AND collections.colId = collections_tracking.colId
476                         AND items.itemnumber = ?"
477     );
478     $sth->execute($itemnumber);
479
480     my $row = $sth->fetchrow_hashref;
481
482     return ( $$row{'holdingbranch'}, $$row{'colBranchcode'}, );
483 }
484
485 =head2 isItemInThisCollection
486
487   $inCollection = isItemInThisCollection( $itemnumber, $colId );
488
489 =cut
490
491 sub isItemInThisCollection {
492     my ( $itemnumber, $colId ) = @_;
493
494     my $dbh = C4::Context->dbh;
495
496     my $sth = $dbh->prepare(
497 "SELECT COUNT(*) as inCollection FROM collections_tracking WHERE itemnumber = ? AND colId = ?"
498     );
499     $sth->execute( $itemnumber, $colId ) or return (0);
500
501     my $row = $sth->fetchrow_hashref;
502
503     return $$row{'inCollection'};
504 }
505
506 =head2 isItemInAnyCollection
507
508 $inCollection = isItemInAnyCollection( $itemnumber );
509
510 =cut
511
512 sub isItemInAnyCollection {
513     my ($itemnumber) = @_;
514
515     my $dbh = C4::Context->dbh;
516
517     my $sth = $dbh->prepare(
518         "SELECT itemnumber FROM collections_tracking WHERE itemnumber = ?");
519     $sth->execute($itemnumber) or return (0);
520
521     my $row = $sth->fetchrow_hashref;
522
523     $itemnumber = $row->{itemnumber};
524     if ($itemnumber) {
525         return 1;
526     }
527     else {
528         return 0;
529     }
530 }
531
532 1;
533
534 __END__
535
536 =head1 AUTHOR
537
538 Kyle Hall <kylemhall@gmail.com>
539
540 =cut