Browse Source

Rotating Collections

This feature is designed to manage collections of items that move
from library to library periodically. Koha can already track who *has*
and item, and who *owns* and item, but not who *should have* an item.
That is the issue this feature addresses.

It allows a persion to create a collection, and add any number of items
to that collection. The collection can then be transferred from library
to library. If an item shows up at a library that does not currently
'hold' that collection, Koha will ask you to transfer it to the library
that does currently 'hold it. In that way, one can even transfer
collections where some of the items are currently checked out. As soon
as they make it back to a library, they will get transferred to the
current library holding that collection.

The feature consists of 4 main pages.
'Home' Page: The landing page, lists collections and provides access to
the rest of the tools.
  Access is via the Tools page.
Edit Collections: Add/Delete new rotating collections
Add/Remove Items: Add/Remove items from a given collection
Transfer Collection: Set the current 'holder' of a given collection.

Librarian access is controlled by 'CAN_user_tools_rotating_collections'
3.2.x
Frédéric Demians 13 years ago
committed by Henri-Damien LAURENT
parent
commit
f650aad34b
  1. 459
      C4/RotatingCollections.pm
  2. 1
      circ/returns.pl
  3. 1
      installer/data/mysql/en/mandatory/userpermissions.sql
  4. 3
      installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql
  5. 5
      koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tmpl
  6. 83
      rotating_collections/addItems.pl
  7. 103
      rotating_collections/editCollections.pl
  8. 34
      rotating_collections/rotatingCollections.pl
  9. 66
      rotating_collections/transferCollection.pl

459
C4/RotatingCollections.pm

@ -0,0 +1,459 @@
package C4::RotatingCollections;
# $Id: RotatingCollections.pm,v 0.1 2007/04/20 kylemhall
# This package is inteded to keep track of what library
# Items of a certain collection should be at.
# Copyright 2007 Kyle Hall
#
# This file is part of Koha.
#
# Koha is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA
use strict;
require Exporter;
use C4::Context;
use C4::Circulation;
use DBI;
use Data::Dumper;
use vars qw($VERSION @ISA @EXPORT);
# set the version for version checking
$VERSION = 0.01;
=head1 NAME
C4::RotatingCollections - Functions for managing rotating collections
=head1 FUNCTIONS
=over 2
=cut
@ISA = qw( Exporter );
@EXPORT = qw(
CreateCollection
UpdateCollection
DeleteCollection
GetItemsInCollection
GetCollection
GetCollections
AddItemToCollection
RemoveItemFromCollection
TransferCollection
GetCollectionItemBranches
);
=item CreateCollection
( $success, $errorcode, $errormessage ) = CreateCollection( $title, $description );
Creates a new collection
Input:
$title: short description of the club or service
$description: long description of the club or service
Output:
$success: 1 if all database operations were successful, 0 otherwise
$errorCode: Code for reason of failure, good for translating errors in templates
$errorMessage: English description of error
=cut
sub CreateCollection {
my ( $title, $description ) = @_;
## Check for all neccessary parameters
if ( ! $title ) {
return ( 0, 1, "No Title Given" );
}
if ( ! $description ) {
return ( 0, 2, "No Description Given" );
}
my $success = 1;
my $dbh = C4::Context->dbh;
my $sth;
$sth = $dbh->prepare("INSERT INTO collections ( colId, colTitle, colDesc )
VALUES ( NULL, ?, ? )");
$sth->execute( $title, $description ) or return ( 0, 3, $sth->errstr() );
$sth->finish;
return 1;
}
=item UpdateCollection
( $success, $errorcode, $errormessage ) = UpdateCollection( $colId, $title, $description );
Updates a collection
Input:
$colId: id of the collection to be updated
$title: short description of the club or service
$description: long description of the club or service
Output:
$success: 1 if all database operations were successful, 0 otherwise
$errorCode: Code for reason of failure, good for translating errors in templates
$errorMessage: English description of error
=cut
sub UpdateCollection {
my ( $colId, $title, $description ) = @_;
## Check for all neccessary parameters
if ( ! $colId ) {
return ( 0, 1, "No Id Given" );
}
if ( ! $title ) {
return ( 0, 2, "No Title Given" );
}
if ( ! $description ) {
return ( 0, 3, "No Description Given" );
}
my $dbh = C4::Context->dbh;
my $sth;
$sth = $dbh->prepare("UPDATE collections
SET
colTitle = ?, colDesc = ?
WHERE colId = ?");
$sth->execute( $title, $description, $colId ) or return ( 0, 4, $sth->errstr() );
$sth->finish;
return 1;
}
=item DeleteCollection
( $success, $errorcode, $errormessage ) = DeleteCollection( $colId );
Deletes a collection of the given id
Input:
$colId : id of the Archtype to be deleted
Output:
$success: 1 if all database operations were successful, 0 otherwise
$errorCode: Code for reason of failure, good for translating errors in templates
$errorMessage: English description of error
=cut
sub DeleteCollection {
my ( $colId ) = @_;
## Paramter check
if ( ! $colId ) {
return ( 0, 1, "No Collection Id Given" );;
}
my $dbh = C4::Context->dbh;
my $sth;
$sth = $dbh->prepare("DELETE FROM collections WHERE colId = ?");
$sth->execute( $colId ) or return ( 0, 4, $sth->errstr() );
$sth->finish;
return 1;
}
=item GetCollections
$collections = GetCollections();
Returns data about all collections
Output:
On Success:
$results: Reference to an array of associated arrays
On Failure:
$errorCode: Code for reason of failure, good for translating errors in templates
$errorMessage: English description of error
=cut
sub GetCollections {
my $dbh = C4::Context->dbh;
my $sth = $dbh->prepare("SELECT * FROM collections");
$sth->execute() or return ( 1, $sth->errstr() );
my @results;
while ( my $row = $sth->fetchrow_hashref ) {
push( @results , $row );
}
$sth->finish;
return \@results;
}
=item GetItemsInCollection
( $results, $success, $errorcode, $errormessage ) = GetItemsInCollection( $colId );
Returns information about the items in the given collection
Input:
$colId: The id of the collection
Output:
$results: Reference to an array of associated arrays
$success: 1 if all database operations were successful, 0 otherwise
$errorCode: Code for reason of failure, good for translating errors in templates
$errorMessage: English description of error
=cut
sub GetItemsInCollection {
my ( $colId ) = @_;
## Paramter check
if ( ! $colId ) {
return ( 0, 0, 1, "No Collection Id Given" );;
}
my $dbh = C4::Context->dbh;
my $sth = $dbh->prepare("SELECT
biblio.title,
items.itemcallnumber,
items.barcode
FROM collections, collections_tracking, items, biblio
WHERE collections.colId = collections_tracking.colId
AND collections_tracking.itemnumber = items.itemnumber
AND items.biblionumber = biblio.biblionumber
AND collections.colId = ? ORDER BY biblio.title");
$sth->execute( $colId ) or return ( 0, 0, 2, $sth->errstr() );
my @results;
while ( my $row = $sth->fetchrow_hashref ) {
push( @results , $row );
}
$sth->finish;
return \@results;
}
=item GetCollection
( $colId, $colTitle, $colDesc, $colBranchcode ) = GetCollection( $colId );
Returns information about a collection
Input:
$colId: Id of the collection
Output:
$colId, $colTitle, $colDesc, $colBranchcode
=cut
sub GetCollection {
my ( $colId ) = @_;
my $dbh = C4::Context->dbh;
my ( $sth, @results );
$sth = $dbh->prepare("SELECT * FROM collections WHERE colId = ?");
$sth->execute( $colId ) or return 0;
my $row = $sth->fetchrow_hashref;
$sth->finish;
return (
$$row{'colId'},
$$row{'colTitle'},
$$row{'colDesc'},
$$row{'colBranchcode'}
);
}
=item AddItemToCollection
( $success, $errorcode, $errormessage ) = AddItemToCollection( $colId, $itemnumber );
Adds an item to a rotating collection.
Input:
$colId: Collection to add the item to.
$itemnumber: Item to be added to the collection
Output:
$success: 1 if all database operations were successful, 0 otherwise
$errorCode: Code for reason of failure, good for translating errors in templates
$errorMessage: English description of error
=cut
sub AddItemToCollection {
my ( $colId, $itemnumber ) = @_;
## Check for all neccessary parameters
if ( ! $colId ) {
return ( 0, 1, "No Collection Given" );
}
if ( ! $itemnumber ) {
return ( 0, 2, "No Itemnumber Given" );
}
if ( isItemInThisCollection( $itemnumber, $colId ) ) {
return ( 0, 2, "Item is already in the collection!" );
} elsif ( isItemInAnyCollection( $itemnumber ) ) {
return ( 0, 3, "Item is already in a different collection!" );
}
my $dbh = C4::Context->dbh;
my $sth;
$sth = $dbh->prepare("INSERT INTO collections_tracking ( ctId, colId, itemnumber )
VALUES ( NULL, ?, ? )");
$sth->execute( $colId, $itemnumber ) or return ( 0, 3, $sth->errstr() );
$sth->finish;
return 1;
}
=item RemoveItemFromCollection
( $success, $errorcode, $errormessage ) = RemoveItemFromCollection( $colId, $itemnumber );
Removes an item to a collection
Input:
$colId: Collection to add the item to.
$itemnumber: Item to be removed from collection
Output:
$success: 1 if all database operations were successful, 0 otherwise
$errorCode: Code for reason of failure, good for translating errors in templates
$errorMessage: English description of error
=cut
sub RemoveItemFromCollection {
my ( $colId, $itemnumber ) = @_;
## Check for all neccessary parameters
if ( ! $itemnumber ) {
return ( 0, 2, "No Itemnumber Given" );
}
if ( ! isItemInThisCollection( $itemnumber, $colId ) ) {
return ( 0, 2, "Item is not in the collection!" );
}
my $dbh = C4::Context->dbh;
my $sth;
$sth = $dbh->prepare("DELETE FROM collections_tracking
WHERE itemnumber = ?");
$sth->execute( $itemnumber ) or return ( 0, 3, $sth->errstr() );
$sth->finish;
return 1;
}
=item TransferCollection
( $success, $errorcode, $errormessage ) = TransferCollection( $colId, $colBranchcode );
Transfers a collection to another branch
Input:
$colId: id of the collection to be updated
$colBranchcode: branch where collection is moving to
Output:
$success: 1 if all database operations were successful, 0 otherwise
$errorCode: Code for reason of failure, good for translating errors in templates
$errorMessage: English description of error
=cut
sub TransferCollection {
my ( $colId, $colBranchcode ) = @_;
## Check for all neccessary parameters
if ( ! $colId ) {
return ( 0, 1, "No Id Given" );
}
if ( ! $colBranchcode ) {
return ( 0, 2, "No Branchcode Given" );
}
my $dbh = C4::Context->dbh;
my $sth;
$sth = $dbh->prepare("UPDATE collections
SET
colBranchcode = ?
WHERE colId = ?");
$sth->execute( $colBranchcode, $colId ) or return ( 0, 4, $sth->errstr() );
$sth->finish;
$sth = $dbh->prepare("SELECT barcode FROM items, collections_tracking
WHERE items.itemnumber = collections_tracking.itemnumber
AND collections_tracking.colId = ?");
$sth->execute( $colId ) or return ( 0, 4, $sth->errstr );
my @results;
while ( my $item = $sth->fetchrow_hashref ) {
my ( $dotransfer, $messages, $iteminformation ) = transferbook( $colBranchcode, $item->{'barcode'}, my $ignore_reserves = 1);
}
return 1;
}
=item isItemInThisCollection
$inCollection = isItemInThisCollection( $itemnumber, $colId );
=cut
sub isItemInThisCollection {
my ( $itemnumber, $colId ) = @_;
my $dbh = C4::Context->dbh;
my $sth = $dbh->prepare("SELECT COUNT(*) as inCollection FROM collections_tracking WHERE itemnumber = ? AND colId = ?");
$sth->execute( $itemnumber, $colId ) or return( 0 );
my $row = $sth->fetchrow_hashref;
return $$row{'inCollection'};
}
=item isItemInAnyCollection
$inCollection = isItemInAnyCollection( $itemnumber );
=cut
sub isItemInAnyCollection {
my ( $itemnumber ) = @_;
my $dbh = C4::Context->dbh;
my $sth = $dbh->prepare("SELECT itemnumber FROM collections_tracking WHERE itemnumber = ?");
$sth->execute( $itemnumber ) or return( 0 );
my $row = $sth->fetchrow_hashref;
my $itemnumber = $$row{'itemnumber'};
$sth->finish;
if ( $itemnumber ) {
return 1;
} else {
return 0;
}
}
1;
__END__
=back
=head1 AUTHOR
Kyle Hall <kylemhall@gmail.com>
=cut

1
circ/returns.pl

@ -43,6 +43,7 @@ use C4::Items;
use C4::Members;
use C4::Branch; # GetBranches GetBranchName
use C4::Koha; # FIXME : is it still useful ?
use C4::RotatingCollections;
my $query = new CGI;

1
installer/data/mysql/en/mandatory/userpermissions.sql

@ -32,6 +32,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(13, 'batchdel', 'Perform batch deletion of items'),
(13, 'manage_csv_profiles', 'Manage CSV export profiles'),
(13, 'moderate_tags', 'Moderate patron tags'),
(13, 'rotating_collections', 'Manage rotating collections'),
(16, 'execute_reports', 'Execute SQL reports'),
(16, 'create_reports', 'Create SQL Reports')
;

3
installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql

@ -28,7 +28,8 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(11, 'group_manage', 'Gérer les commandes et les bons de commande'),
(11, 'order_receive', 'Gérer les réceptions'),
(11, 'budget_add_del', 'Ajouter et supprimer les budgets (mais pas modifier)'),
(13, 'manage_csv_profiles', 'Manage CSV export profiles'),
(13, 'manage_csv_profiles', 'Gérer les profils d''export CSV'),
(13, 'rotating_collections', 'Gérer les collections tournantes'),
(13, 'batch_mod', 'Modification Par lot des exemplaires'),
(13, 'batch_del', 'Suppression par lot des exemplaires')
;

5
koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tmpl

@ -50,6 +50,11 @@
<dd>Manage CSV export profiles</dd>
<!-- /TMPL_IF -->
<!-- TMPL_IF NAME="CAN_user_tools_rotating_collections" -->
<dt><a href="/cgi-bin/koha/rotating_collections/rotatingCollections.pl">Rotating Collections</a></dt>
<dd>Manage Rotating Collections</dd>
<!-- /TMPL_IF -->
</dl>
</div>
<div class="yui-u">

83
rotating_collections/addItems.pl

@ -0,0 +1,83 @@
#!/usr/bin/perl
use strict;
require Exporter;
use C4::Output;
use C4::Auth;
use C4::Context;
use C4::RotatingCollections;
use C4::Items;
use CGI;
my $query = new CGI;
my ($template, $loggedinuser, $cookie)
= get_template_and_user({template_name => "rotating_collections/addItems.tmpl",
query => $query,
type => "intranet",
authnotrequired => 1,
flagsrequired => {parameters => 1},
debug => 1,
});
if ( $query->param('action') eq 'addItem' ) {
## Add the given item to the collection
my $colId = $query->param('colId');
my $barcode = $query->param('barcode');
my $removeItem = $query->param('removeItem');
my $itemnumber = GetItemnumberFromBarcode( $barcode );
my ( $success, $errorCode, $errorMessage );
if ( ! $removeItem ) {
( $success, $errorCode, $errorMessage ) = AddItemToCollection( $colId, $itemnumber );
$template->param(
previousActionAdd => 1,
addedBarcode => $barcode,
);
if ( $success ) {
$template->param( addSuccess => 1 );
} else {
$template->param( addFailure => 1 );
$template->param( failureMessage => $errorMessage );
}
} else {
## Remove the given item from the collection
( $success, $errorCode, $errorMessage ) = RemoveItemFromCollection( $colId, $itemnumber );
$template->param(
previousActionRemove => 1,
removedBarcode => $barcode,
removeChecked => 1,
);
if ( $success ) {
$template->param( removeSuccess => 1 );
} else {
$template->param( removeFailure => 1 );
$template->param( failureMessage => $errorMessage );
}
}
}
my ( $colId, $colTitle, $colDescription, $colBranchcode ) = GetCollection( $query->param('colId') );
my $collectionItems = GetItemsInCollection( $colId );
if ( $collectionItems ) {
$template->param( collectionItemsLoop => $collectionItems );
}
$template->param(
intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
intranetstylesheet => C4::Context->preference("intranetstylesheet"),
IntranetNav => C4::Context->preference("IntranetNav"),
colId => $colId,
colTitle => $colTitle,
colDescription => $colDescription,
colBranchcode => $colBranchcode,
);
output_html_with_http_headers $query, $cookie, $template->output;

103
rotating_collections/editCollections.pl

@ -0,0 +1,103 @@
#!/usr/bin/perl
use strict;
require Exporter;
use CGI;
use C4::Output;
use C4::Auth;
use C4::Context;
use C4::RotatingCollections;
my $query = new CGI;
my ($template, $loggedinuser, $cookie)
= get_template_and_user({template_name => "rotating_collections/editCollections.tmpl",
query => $query,
type => "intranet",
authnotrequired => 1,
flagsrequired => {parameters => 1},
debug => 1,
});
# Create new Collection
if ( $query->param('action') eq 'create' ) {
my $title = $query->param('title');
my $description = $query->param('description');
my ( $createdSuccessfully, $errorCode, $errorMessage ) = CreateCollection( $title, $description );
$template->param(
previousActionCreate => 1,
createdTitle => $title,
);
if ( $createdSuccessfully ) {
$template->param( createSuccess => 1 );
} else {
$template->param( createFailure => 1 );
$template->param( failureMessage => $errorMessage );
}
}
## Delete a club or service
elsif ( $query->param('action') eq 'delete' ) {
my $colId = $query->param('colId');
my ( $success, $errorCode, $errorMessage ) = DeleteCollection( $colId );
$template->param( previousActionDelete => 1 );
if ( $success ) {
$template->param( deleteSuccess => 1 );
} else {
$template->param( deleteFailure => 1 );
$template->param( failureMessage => $errorMessage );
}
}
## Edit a club or service: grab data, put in form.
elsif ( $query->param('action') eq 'edit' ) {
my $colId = $query->param('colId');
my ( $colId, $colTitle, $colDesc, $colBranchcode ) = GetCollection( $colId );
$template->param(
previousActionEdit => 1,
editColId => $colId,
editColTitle => $colTitle,
editColDescription => $colDesc,
);
}
# Update a Club or Service
elsif ( $query->param('action') eq 'update' ) {
my $colId = $query->param('colId');
my $title = $query->param('title');
my $description = $query->param('description');
my ( $createdSuccessfully, $errorCode, $errorMessage )
= UpdateCollection( $colId, $title, $description );
$template->param(
previousActionUpdate => 1,
updatedTitle => $title,
);
if ( $createdSuccessfully ) {
$template->param( updateSuccess => 1 );
} else {
$template->param( updateFailure => 1 );
$template->param( failureMessage => $errorMessage );
}
}
my $collections = GetCollections();
$template->param(
intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
intranetstylesheet => C4::Context->preference("intranetstylesheet"),
IntranetNav => C4::Context->preference("IntranetNav"),
collectionsLoop => $collections,
);
output_html_with_http_headers $query, $cookie, $template->output;

34
rotating_collections/rotatingCollections.pl

@ -0,0 +1,34 @@
#!/usr/bin/perl
use strict;
require Exporter;
use CGI;
use C4::Output;
use C4::Auth;
use C4::Context;
use C4::RotatingCollections;
my $query = new CGI;
my ($template, $loggedinuser, $cookie)
= get_template_and_user({template_name => "rotating_collections/rotatingCollections.tmpl",
query => $query,
type => "intranet",
authnotrequired => 1,
flagsrequired => {parameters => 1},
debug => 1,
});
my $branchcode = $query->cookie('branch');
my $collections = GetCollections();
$template->param(
intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
intranetstylesheet => C4::Context->preference("intranetstylesheet"),
IntranetNav => C4::Context->preference("IntranetNav"),
collectionsLoop => $collections,
);
output_html_with_http_headers $query, $cookie, $template->output;

66
rotating_collections/transferCollection.pl

@ -0,0 +1,66 @@
#!/usr/bin/perl
use strict;
require Exporter;
use C4::Output;
use C4::Auth;
use C4::Context;
use C4::RotatingCollections;
use C4::Branch;
use CGI;
my $query = new CGI;
my $colId = $query->param('colId');
my $toBranch = $query->param('toBranch');
my ($template, $loggedinuser, $cookie)
= get_template_and_user({template_name => "rotating_collections/transferCollection.tmpl",
query => $query,
type => "intranet",
authnotrequired => 1,
flagsrequired => {parameters => 1},
debug => 1,
});
## Transfer collection
my ( $success, $errorCode, $errorMessage );
if ( $toBranch ) {
( $success, $errorCode, $errorMessage ) = TransferCollection( $colId, $toBranch );
if ( $success ) {
$template->param( transferSuccess => 1 );
} else {
$template->param( transferFailure => 1,
errorCode => $errorCode,
errorMessage => $errorMessage
);
}
}
## Set up the toBranch select options
my $branches = GetBranches();
my @branchoptionloop;
foreach my $br (keys %$branches) {
my %branch;
$branch{code}=$br;
$branch{name}=$branches->{$br}->{'branchname'};
push (@branchoptionloop, \%branch);
}
## Get data about collection
my ( $colId, $colTitle, $colDesc, $colBranchcode ) = GetCollection( $colId );
$template->param(
intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"),
intranetstylesheet => C4::Context->preference("intranetstylesheet"),
IntranetNav => C4::Context->preference("IntranetNav"),
colId => $colId,
colTitle => $colTitle,
colDesc => $colDesc,
colBranchcode => $colBranchcode,
branchoptionloop => \@branchoptionloop
);
output_html_with_http_headers $query, $cookie, $template->output;
Loading…
Cancel
Save