@@ -, +, @@ - transferCollection-view has been made redundant with the addition of a transfer button and branch select input in the main view. - editCollections-view has been made redundant with addition of the "edit" button in the main view. Note that "Edit collection" still - datatables used in all the views. - The main view table has been revamped and some columns have been moved around or removed. New columns: Owner(branch of the signed in user on creation), - New collections can be created directly from the main view using the "New collection"-button. - Item's original home branch (before a transfer) is now recorded on transfer (a new database column 'origin_branchcode' in - Item's transfer location is now recored on item-level basis (a new database column: 'transfer_branch). - Item's tranfer status is now recorded (a new database column in collection_tracking: 'transferred'). - When removing a collection, all items (if any) in that collection get removed from collection_tracking and returned to their origin branch. - addItems-view: - Table now shows the item's origin branch, home branch and current loc. In addition to these, new columns: "Transferred", "Transfer", "Return" and "Remove". - Item's title and barcode are now links to the relevant page in catalogue. - Buttons for individual item transfer, return and removal. The transfer button can be used to transfer an individual item to a branch (branch selection happens in a bootsrap modal-view). The return button can be used to return an item to its origin branch. The remove button allows removing an item from the collection without the need for reading a barcode. - A button for whole collection transfer. --- C4/Circulation.pm | 2 +- C4/RotatingCollections.pm | 565 +++++++++++++++++++-- catalogue/detail.pl | 4 + circ/returns.pl | 8 +- installer/data/mysql/kohastructure.sql | 13 +- installer/data/mysql/updatedatabase.pl | 21 + .../prog/en/modules/catalogue/detail.tt | 7 +- .../en/modules/rotating_collections/addItems.tt | 340 ++++++++++++- .../rotating_collections/editCollections.tt | 176 +++++-- .../rotating_collections/rotatingCollections.tt | 367 ++++++++++++- .../rotating_collections/transferCollection.tt | 68 ++- rotating_collections/addItems.pl | 17 +- rotating_collections/editCollections.pl | 7 +- rotating_collections/rotatingCollections.pl | 6 +- rotating_collections/transferCollection.pl | 108 +++- 15 files changed, 1536 insertions(+), 173 deletions(-) --- a/C4/Circulation.pm +++ a/C4/Circulation.pm @@ -42,7 +42,7 @@ use C4::Koha qw( GetKohaAuthorisedValueLib ); use C4::Overdues qw(CalcFine UpdateFine); -use C4::RotatingCollections qw(GetCollectionItemBranches); +use C4::RotatingCollections; use Algorithm::CheckDigits; use Data::Dumper; --- a/C4/RotatingCollections.pm +++ a/C4/RotatingCollections.pm @@ -27,6 +27,10 @@ use Modern::Perl; use C4::Context; use C4::Circulation; use C4::Reserves qw(GetReserveStatus); +use C4::Biblio; +use C4::Branch; +use C4::Items; +use C4::Reserves; use DBI; @@ -56,13 +60,22 @@ BEGIN { GetItemsInCollection GetCollection + GetCollectionByTitle GetCollections AddItemToCollection RemoveItemFromCollection TransferCollection + TransferCollectionItem + ReturnCollectionItemToOrigin + ReturnCollectionToOrigin GetCollectionItemBranches + + GetItemOriginBranch + GetItemsCollection + + isItemInAnyCollection ); } @@ -82,14 +95,26 @@ BEGIN { =cut sub CreateCollection { - my ( $title, $description ) = @_; + my ( $title, $description, $owningbranch ) = @_; ## Check for all neccessary parameters if ( !$title ) { - return ( 0, 1, "No Title Given" ); + return ( 0, 1, "No title given" ); } if ( !$description ) { - return ( 0, 2, "No Description Given" ); + return ( 0, 2, "No description given" ); + } + + if ( !$owningbranch ) { + return ( 0, 3, "No owning branch given" ); + } + + # Check whether a collection with the given title already exists + my $collections = GetCollections(); + for my $col (@$collections) { + if ($col->{'colTitle'} eq $title) { + return (0, 4, "A collection with the title '" . $title . "' already exists"); + } } my $success = 1; @@ -98,10 +123,10 @@ sub CreateCollection { my $sth; $sth = $dbh->prepare( - "INSERT INTO collections ( colId, colTitle, colDesc ) - VALUES ( NULL, ?, ? )" + "INSERT INTO collections ( colId, colTitle, colDesc, owningBranchcode ) + VALUES ( NULL, ?, ?, ? )" ); - $sth->execute( $title, $description ) or return ( 0, 3, $sth->errstr() ); + $sth->execute( $title, $description, $owningbranch ) or return ( 0, 5, $sth->errstr() ); return 1; @@ -139,6 +164,14 @@ sub UpdateCollection { return ( 0, 3, "No Description Given" ); } + # Check whether a collection with the given title already exists + my $collections = GetCollections(); + for my $col (@$collections) { + if ($col->{'colTitle'} eq $title) { + return (0, 4, "A collection with the title '" . $title . "' already exists"); + } + } + my $dbh = C4::Context->dbh; my $sth; @@ -178,6 +211,14 @@ sub DeleteCollection { return ( 0, 1, "No Collection Id Given" ); } + my $collectionItems = GetItemsInCollection($colId); + # KD-139: Actually remove all items from the collection before removing the collection itself. + for my $item (@$collectionItems) { + my $itembiblio = GetBiblioFromItemNumber(undef, $item->{'barcode'}); + my $itemnumber = $itembiblio->{'itemnumber'}; + RemoveItemFromCollection($colId, $itemnumber); + } + my $dbh = C4::Context->dbh; my $sth; @@ -205,12 +246,21 @@ sub DeleteCollection { sub GetCollections { my $dbh = C4::Context->dbh; + my $query = ' + SELECT * + FROM collections + LEFT JOIN branches ON owningBranchcode = branches.branchcode + '; - my $sth = $dbh->prepare("SELECT * FROM collections"); + my $sth = $dbh->prepare($query); $sth->execute() or return ( 1, $sth->errstr() ); my @results; while ( my $row = $sth->fetchrow_hashref ) { + my $colItemCount = GetCollectionItemCount($row->{'colId'}); + my $itemsTransferred = GetTransferredItemCount($row->{'colId'}); + $row->{'colItemsCount'} = $colItemCount; + $row->{'itemsTransferred'} = $itemsTransferred; push( @results, $row ); } @@ -246,19 +296,32 @@ sub GetItemsInCollection { my $sth = $dbh->prepare( "SELECT - biblio.title, - items.itemcallnumber, - items.barcode - FROM collections, collections_tracking, items, biblio - WHERE collections.colId = collections_tracking.colId + biblio.title, + biblio.biblionumber, + items.itemcallnumber, + items.barcode, + items.itemnumber, + items.holdingbranch, + items.homebranch, + branches.branchname, + collections_tracking.* + FROM collections, collections_tracking, items, biblio, branches + WHERE items.homebranch = branches.branchcode + AND collections.colId = collections_tracking.colId AND collections_tracking.itemnumber = items.itemnumber AND items.biblionumber = biblio.biblionumber - AND collections.colId = ? ORDER BY biblio.title" + 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 ) { + my $originbranchname = GetBranchName($row->{'origin_branchcode'}); + my $holdingbranchname = GetBranchName($row->{'holdingbranch'}); + $row->{'holdingbranchname'} = $holdingbranchname; + $row->{'origin_branchname'} = $originbranchname; + $row->{'intransit'} = GetTransfers($row->{'itemnumber'}); push( @results, $row ); } @@ -296,6 +359,68 @@ sub GetCollection { } +=head2 GetCollectionByTitle + + ($colId, $colTitle, $colDesc, $colBranchcode) = GetCollectionByTitle($colTitle); + +Returns information about a collection + + Input: + $colTitle: Title of the collection + Output: + $colId, $colTitle, $colDesc, $colBranchcode + +=cut + +sub GetCollectionByTitle { + my ($colId) = @_; + + my $dbh = C4::Context->dbh; + + my ( $sth, @results ); + $sth = $dbh->prepare("SELECT * FROM collections WHERE colTitle = ?"); + $sth->execute($colId) or return 0; + + my $row = $sth->fetchrow_hashref; + + return ( + $$row{'colId'}, $$row{'colTitle'}, + $$row{'colDesc'}, $$row{'colBranchcode'} + ); + +} + +=head2 GetItemsCollection + +$itemsCollection = GetItemsCollection($itemnumber) + +Returns an item's collection if it exists + + Input: + $itemnumber: itemnumber of the item + Output: + $colId of the item's collection or 0 if the item is not in a collection + +=cut + +sub GetItemsCollection { + my $itemnumber = shift; + + if (!isItemInAnyCollection($itemnumber)) { + return 0; + } + + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare("SELECT * FROM collections_tracking WHERE itemnumber = ?"); + $sth->execute($itemnumber) or return 0; + + my $colItem = $sth->fetchrow_hashref; + if ($colItem) { + return $colItem->{'colId'}; + } + return 0; +} + =head2 AddItemToCollection ( $success, $errorcode, $errormessage ) = AddItemToCollection( $colId, $itemnumber ); @@ -322,13 +447,19 @@ sub AddItemToCollection { 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!" ); } + # Check item's reserve status + my ($reservedate, $borrowernumber, $branchcode, $reserve_id, $waitingdate) = GetReservesFromItemnumber($itemnumber); + return (0, 4, "The item is waiting for pickup and cannot be added to a collection!") if ($waitingdate); + + my $itembiblio = GetBiblioFromItemNumber($itemnumber, undef); + my $originbranchcode = $itembiblio->{'homebranch'}; + my $transferred = 0; my $dbh = C4::Context->dbh; @@ -336,10 +467,11 @@ sub AddItemToCollection { $sth = $dbh->prepare(" INSERT INTO collections_tracking ( colId, - itemnumber - ) VALUES ( ?, ? ) + itemnumber, + origin_branchcode + ) VALUES (?, ?, ?) "); - $sth->execute( $colId, $itemnumber ) or return ( 0, 3, $sth->errstr() ); + $sth->execute($colId, $itemnumber, $originbranchcode) or return ( 0, 3, $sth->errstr() ); return 1; @@ -374,8 +506,22 @@ sub RemoveItemFromCollection { return ( 0, 2, "Item is not in the collection!" ); } - my $dbh = C4::Context->dbh; + # KD-139: Attempt to transfer the item being removed if it has its origin branch + # set up. + my $itembiblio = GetBiblioFromItemNumber($itemnumber, undef); + my $currenthomebranchcode = $itembiblio->{'homebranch'}; + my $originbranchcode = GetItemOriginBranch($itemnumber); + my $barcode = $itembiblio->{'barcode'}; + my ($dotransfer, $messages, $iteminformation); + + if ($originbranchcode && $barcode) { + if (GetTransfers($itemnumber)) { + DeleteTransfer($itemnumber) + } + ($dotransfer, $messages, $iteminformation) = transferbook($originbranchcode, $barcode, 1); + } + my $dbh = C4::Context->dbh; my $sth; $sth = $dbh->prepare( "DELETE FROM collections_tracking @@ -383,6 +529,140 @@ sub RemoveItemFromCollection { ); $sth->execute($itemnumber) or return ( 0, 3, $sth->errstr() ); + # Transfer was not done - not considered an error here + if (!$dotransfer) { + return (1, 4, $messages); + } + + # Change the item's homebranch back to its pre-transfer status + ModItem({ homebranch => $originbranchcode }, undef, $itemnumber); + + return 1; +} + +=head2 ReturnCollectionToOrigin + + ($success, $errorcode, $errormessage) = ReturnCollectionToOrigin($colId); + +Marks a collection to be returned to their origin branch, e.g. the branch that was +the item's home branch when it was first added to the collection + + Input: + $colId: Collection the returned item belongs to + + Output: + $success: 1 if all database operations were successful, 0 otherwise + $errorcode: Code for reason of failure, good for translating errors in templates + $errormessages: English description of any errors with return operations +=cut + +sub ReturnCollectionToOrigin { + my $colId = shift; + + if (!$colId) { + return (0, 1, "No collection id given"); + } + + my $collectionItems = GetItemsInCollection($colId); + my $collectionItemsCount = scalar(@$collectionItems); + my ($colSuccess, $errorcode, @errormessages); + + for my $item (@$collectionItems) { + my $itemOriginBranch = GetItemOriginBranch($item->{'itemnumber'}); + my ($success, $errocode, $errormessage); + if ($itemOriginBranch) { + ($success, $errorcode, $errormessage) = + ReturnCollectionItemToOrigin($colId, $item->{'itemnumber'}); + if (!$success) { + push(@errormessages, $errormessage); + } + } + } + my $errorCount = scalar(@errormessages); + if ($errorCount == $collectionItemsCount) { + return (0, 2, "No items in collection transferred"); + } + else { + # Some items were succesfully returned - return info about failed transfers for template usage + return (1, 0, \@errormessages); + } +} + + + +=head2 ReturnCollectionItemToOrigin + + ($success, $errorcode, $errormessage) = ReturnCollectionItemToOrigin($colId, $itemnumber); + +Marks a collection item to be returned to their origin branch, e.g. the branch that was +the item's home branch when it was first added to the collection + + Input: + $colId: Collection the returned item belongs to + $itemnumber: Item in the collection to be returned to their origin branch + + 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 ReturnCollectionItemToOrigin { + my ($colId, $itemnumber) = @_; + my $originBranch = GetItemOriginBranch($itemnumber); + + ## Check for all neccessary parameters + if (!$colId) { + return (0, 1, "No collection id given"); + } + if (!$itemnumber) { + return (0, 2, "No itemnumber given"); + } + + if (!$originBranch) { + return (0, 3, "Item has no origin branch set"); + } + + if (!isItemTransferred($itemnumber)) { + return (0, 4, "Cannot return an item that is not transferred"); + } + + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare(q{ + SELECT items.itemnumber, items.barcode, items.homebranch, items.holdingbranch FROM collections_tracking + LEFT JOIN items ON collections_tracking.itemnumber = items.itemnumber + LEFT JOIN issues ON items.itemnumber = issues.itemnumber + WHERE issues.borrowernumber IS NULL + AND collections_tracking.colId = ? AND collections_tracking.itemnumber = ? + }); + + $sth->execute($colId, $itemnumber) or return (0, 5, $sth->errstr); + my ($dotransfer, $messages, $iteminformation); + if (my $item = $sth->fetchrow_hashref) { + unless (GetReserveStatus($item->{itemnumber}) eq "Waiting") { + ($dotransfer, $messages, $iteminformation) + = transferbook($originBranch, $item->{barcode}, 1); + } + } + # Push all issues with the transfer into a list for template usage. + if (!$dotransfer) { + my @errorlist; + for my $message (keys %$messages) { + push(@errorlist, $message); + } + return (0, 6, \@errorlist); + } + + $sth = $dbh->prepare(q{ + UPDATE collections_tracking + SET + transfer_branch = NULL + WHERE itemnumber = ? + }); + $sth->execute($itemnumber) or return (0, 7, $sth->errstr); + ModItem({ homebranch => $originBranch }, undef, $itemnumber); + return 1; } @@ -404,46 +684,129 @@ Transfers a collection to another branch =cut sub TransferCollection { - my ( $colId, $colBranchcode ) = @_; + my ($colId, $colBranchcode) = @_; ## Check for all neccessary parameters - if ( !$colId ) { - return ( 0, 1, "No Id Given" ); + if (!$colId) { + return (0, 1, "No id given"); } - if ( !$colBranchcode ) { - return ( 0, 2, "No Branchcode Given" ); + if (!$colBranchcode) { + return (0, 2, "No branchcode given"); } - my $dbh = C4::Context->dbh; + my $colItems = GetItemsInCollection($colId); + my $colItemsCount = scalar(@$colItems); + my ($transfersuccess, $error, @errorlist); + my $problemItemCount = 0; + + for my $item (@$colItems) { + my $itemOriginBranch = GetItemOriginBranch($item->{'itemnumber'}); + my $itemCurHomeBranch = $item->{'homebranch'}; + my ($dotransfer, $errorcode, $errormessage) = TransferCollectionItem($colId, $item->{'itemnumber'}, $colBranchcode); + if (!$dotransfer) { + $problemItemCount++; + push(@errorlist, $item->{'title'} . ":"); + if (ref $errormessage eq "ARRAY") { + for my $message (@$errormessage) { + push(@errorlist, $message); + } + } + else { + push (@errorlist, $errormessage); + } + } + } - my $sth; - $sth = $dbh->prepare( - "UPDATE collections - SET - colBranchcode = ? - WHERE colId = ?" - ); - $sth->execute( $colBranchcode, $colId ) or return ( 0, 4, $sth->errstr() ); + if ($problemItemCount == $colItemsCount) { + return (0, 3, \@errorlist); + } + elsif ($problemItemCount < $colItemsCount) { + return (1, 0, \@errorlist); + } + else { + return 1; + } +} - $sth = $dbh->prepare(q{ - SELECT items.itemnumber, items.barcode FROM collections_tracking +=head2 TransferItem + + ($success, $errorcode, $errormessage) = TransferCollection($colId, $itemnumber, $transferBranch); + +Transfers an item to another branch + + Input: + $colId: id of the collection to be updated + $itemnumber: the itemnumber of the item in the collection being transferred + $transferBranch: branch where item 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 TransferCollectionItem { + my ($colId, $itemnumber, $transferBranch) = @_; + + if (!$colId) { + return (0, 1, "No collection id given"); + } + + if (!$itemnumber) { + return (0, 2, "No itemnumber given"); + } + + if (!$transferBranch) { + return (0, 3, "No transfer branch given"); + } + + if (isItemTransferred($itemnumber)) { + return (0, 4, "Item is already transferred"); + } + + my $dbh = C4::Context->dbh; + my $sth = $dbh->prepare(q{ + SELECT items.itemnumber, items.barcode, items.homebranch FROM collections_tracking LEFT JOIN items ON collections_tracking.itemnumber = items.itemnumber LEFT JOIN issues ON items.itemnumber = issues.itemnumber WHERE issues.borrowernumber IS NULL - AND collections_tracking.colId = ? + AND collections_tracking.colId = ? AND collections_tracking.itemnumber = ? }); - $sth->execute($colId) or return ( 0, 4, $sth->errstr ); - my @results; - while ( my $item = $sth->fetchrow_hashref ) { - transferbook( $colBranchcode, $item->{barcode}, - my $ignore_reserves = 1 ) - unless ( GetReserveStatus( $item->{itemnumber} ) eq "Waiting" ); + + $sth->execute($colId, $itemnumber) or return ( 0, 5, $sth->errstr ); + my ($dotransfer, $messages, $iteminformation); + if (my $item = $sth->fetchrow_hashref) { + unless (GetReserveStatus($item->{itemnumber}) eq "Waiting") { + ($dotransfer, $messages, $iteminformation) + = transferbook($transferBranch, $item->{barcode}, 1); + } } - return 1; + # Push all issues with the transfer into a list for template usage. + if (!$dotransfer) { + my @errorlist; + for my $message (keys %$messages) { + push(@errorlist, $message); + } + return (0, 6, \@errorlist); + } + my $transferred = 1; + $sth = $dbh->prepare(q{ + UPDATE collections_tracking + SET + transfer_branch = ?, + transferred = ? + WHERE itemnumber = ? + }); + $sth->execute($transferBranch, $transferred, $itemnumber) or return (0, 7, $sth->errstr); + ModItem({ homebranch => $transferBranch }, undef, $itemnumber); + + return 1; } + =head2 GetCollectionItemBranches my ( $holdingBranch, $collectionBranch ) = GetCollectionItemBranches( $itemnumber ); @@ -461,7 +824,7 @@ sub GetCollectionItemBranches { my ( $sth, @results ); $sth = $dbh->prepare( -"SELECT holdingbranch, colBranchcode FROM items, collections, collections_tracking +"SELECT holdingbranch, transfer_branch FROM items, collections, collections_tracking WHERE items.itemnumber = collections_tracking.itemnumber AND collections.colId = collections_tracking.colId AND items.itemnumber = ?" @@ -470,7 +833,49 @@ sub GetCollectionItemBranches { my $row = $sth->fetchrow_hashref; - return ( $$row{'holdingbranch'}, $$row{'colBranchcode'}, ); + return ( $$row{'holdingbranch'}, $$row{'transfer_branch'}, ); +} + +=head2 GetTransferredItemCount + + $transferredCount = GetTransferredItemCount($colId); + +=cut + +sub GetTransferredItemCount { + my $colId = shift; + + my $dbh = C4::Context->dbh; + my $query = "SELECT COUNT(*) + FROM collections_tracking + WHERE colId = ? AND transferred = 1 + "; + my $sth = $dbh->prepare($query); + $sth->execute($colId) or die $sth->errstr(); + + my $result = $sth->fetchrow(); + return $result; +} + +=head2 GetCollectionItemCount + + $colItemCount = GetCollectionItemCount($colId); + +=cut + +sub GetCollectionItemCount { + my $colId = shift; + + my $dbh = C4::Context->dbh; + my $query = "SELECT COUNT(colId) + FROM collections_tracking + WHERE colId = ? + "; + my $sth = $dbh->prepare($query); + $sth->execute($colId) or die $sth->errstr(); + + my $result = $sth->fetchrow(); + return $result; } =head2 isItemInThisCollection @@ -520,6 +925,78 @@ sub isItemInAnyCollection { } } +=head2 isItemTramsferred + +($transferred, $errorcode, $errormessage) = isItemTransferred($itemnumber); + +=cut + +sub isItemTransferred { + my $itemnumber = shift; + + my $dbh = C4::Context->dbh; + my $sth; + + my $query = ' + Select * FROM collections_tracking + WHERE itemnumber = ? + '; + + $sth = $dbh->prepare($query); + $sth->execute($itemnumber) or return (0, 1, $sth->errstr); + my $resultrow = $sth->fetchrow_hashref; + if (!$resultrow) { + return (0, 2, "Item is not in a collection"); + } + + if ($resultrow->{'transferred'}) { + return 1; + } + else { + return 0; + } + +} + + + +=head2 GetItemOriginBranch + +$originBranch = GetItemOriginBranch($itemnumber); + +Kd-139: Returns the given item's origin branch, e.g. the home branch at the time it was +being added to a collection or 0 the item has no origin + +=cut + +sub GetItemOriginBranch { + my $itemnumber = shift; + + my $dbh = C4::Context->dbh; + my $sth; + + my $query = ' + SELECT * + FROM collections_tracking + WHERE itemnumber = ? + '; + $sth = $dbh->prepare($query); + $sth->execute($itemnumber); + my $resultrow = $sth->fetchrow_hashref; + + if (!$resultrow) { + return 0; + } + + my $originBranchCode = $resultrow->{'origin_branchcode'}; + if ($originBranchCode) { + return $originBranchCode; + } + else { + return 0; + } +} + 1; __END__ --- a/catalogue/detail.pl +++ a/catalogue/detail.pl @@ -44,6 +44,7 @@ use Koha::DateUtils; use C4::HTML5Media; use C4::CourseReserves qw(GetItemCourseReservesInfo); use C4::Acquisition qw(GetOrdersByBiblionumber); +use C4::RotatingCollections qw(GetItemsCollection); my $query = CGI->new(); @@ -258,6 +259,9 @@ foreach my $item (@items) { $item->{nocancel} = 1; } + # Check the item's rotating collection status + $item->{itemsCollection} = GetItemsCollection($item->{itemnumber}); + # item has a host number if its biblio number does not match the current bib if ($item->{biblionumber} ne $biblionumber){ $item->{hostbiblionumber} = $item->{biblionumber}; --- a/circ/returns.pl +++ a/circ/returns.pl @@ -600,10 +600,10 @@ $template->param( BlockReturnOfWithdrawnItems => C4::Context->preference("BlockReturnOfWithdrawnItems"), ); -my $itemnumber = GetItemnumberFromBarcode( $query->param('barcode') ); -if ( $itemnumber ) { - my ( $holdingBranch, $collectionBranch ) = GetCollectionItemBranches( $itemnumber ); - if ( ! ( $holdingBranch eq $collectionBranch ) ) { +my $itemnumber = GetItemnumberFromBarcode($query->param('barcode')); +if ($itemnumber) { + my ($holdingBranch, $collectionBranch) = GetCollectionItemBranches($itemnumber); + if ($holdingBranch ne $collectionBranch) { $template->param( collectionItemNeedsTransferred => 1, collectionBranch => GetBranchName($collectionBranch), --- a/installer/data/mysql/kohastructure.sql +++ a/installer/data/mysql/kohastructure.sql @@ -481,14 +481,16 @@ CREATE TABLE collections ( colTitle varchar(100) NOT NULL DEFAULT '', colDesc text NOT NULL, colBranchcode varchar(10) DEFAULT NULL, -- 'branchcode for branch where item should be held.' + owningBranchcode varchar(10) DEFAULT NULL, PRIMARY KEY (colId) ) ENGINE=InnoDB DEFAULT CHARACTER SET utf8; -- -- Constraints for table `collections` -- -ALTER TABLE `collections` - ADD CONSTRAINT `collections_ibfk_1` FOREIGN KEY (`colBranchcode`) REFERENCES `branches` (`branchcode`) ON DELETE CASCADE ON UPDATE CASCADE; +ALTER TABLE collections + ADD CONSTRAINT collections_ibfk_1 FOREIGN KEY (colBranchcode) REFERENCES branches (branchcode) ON DELETE CASCADE ON UPDATE CASCADE, + ADD CONSTRAINT collections_owning_1 FOREIGN KEY (owningBranchcode) REFERENCES branches (branchcode) ON DELETE CASCADE ON UPDATE CASCADE; -- -- Table: collections_tracking @@ -498,7 +500,12 @@ CREATE TABLE collections_tracking ( collections_tracking_id integer(11) NOT NULL auto_increment, colId integer(11) NOT NULL DEFAULT 0 comment 'collections.colId', itemnumber integer(11) NOT NULL DEFAULT 0 comment 'items.itemnumber', - PRIMARY KEY (collections_tracking_id) + origin_branchcode varchar(10) DEFAULT NULL, + transfer_branch varchar(10) DEFAULT NULL, + transferred tinyint(1) DEFAULT '0', + PRIMARY KEY (collections_tracking_id), + CONSTRAINT collections_origin_1 FOREIGN KEY (origin_branchcode) REFERENCES branches (branchcode) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT collections_transfer_1 FOREIGN KEY (transfer_branch) REFERENCES branches (branchcode) ON DELETE CASCADE ON UPDATE CASCADE ) ENGINE=InnoDB DEFAULT CHARACTER SET utf8; -- --- a/installer/data/mysql/updatedatabase.pl +++ a/installer/data/mysql/updatedatabase.pl @@ -8629,6 +8629,27 @@ if ( CheckVersion($DBversion) ) { SetVersion($DBversion); } +$DBversion = "3.17.00.XXX"; +if ( CheckVersion($DBversion) ) { + $dbh->do(q{ + ALTER TABLE collections_tracking + ADD origin_branchcode VARCHAR(10) NULL DEFAULT NULL, + ADD transfer_branch VARCHAR(10) NULL DEFAULT NULL, + ADD CONSTRAINT collections_origin_1 FOREIGN KEY (origin_branchcode) REFERENCES branches (branchcode) ON DELETE CASCADE ON UPDATE CASCADE, + ADD CONSTRAINT collections_transfer_1 FOREIGN KEY (transfer_branch) REFERENCES branches (branchcode) ON DELETE CASCADE ON UPDATE CASCADE, + ADD transferred TINYINT(1) DEFAULT 0 + }); + + $dbh->do(q{ + ALTER TABLE collections + ADD owningBranchcode VARCHAR(10) NULL DEFAULT NULL, + ADD CONSTRAINT collections_owning_1 FOREIGN KEY (owningBranchcode) REFERENCES branches (branchcode) ON DELETE CASCADE ON UPDATE CASCADE + }); + + print "Upgrade to $DBversion done (Bug 8836 - Resurrect Rotating Collections additions)\n"; + SetVersion($DBversion); +} + =head1 FUNCTIONS =head2 TableExists($table) --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt @@ -580,7 +580,12 @@ function verify_images() { [% END %] [% UNLESS ( singlebranchmode ) %][% item.branchname %] [% END %] - [% item.homebranch %][% item.location %] + [% item.homebranch %][% item.location %] + [% IF item.itemsCollection %] + (Col.: [% item.itemsCollection%]) + + [% END %] + [% IF ( itemdata_ccode ) %][% item.ccode %][% END %] [% IF ( item.itemcallnumber ) %] [% item.itemcallnumber %][% END %] --- a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/addItems.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/addItems.tt @@ -1,11 +1,189 @@ [% INCLUDE 'doc-head-open.inc' %] -Koha › Tools › Rotating collections › Add/Remove items +Koha › Tools › Rotating collections › Manage collection [% INCLUDE 'doc-head-close.inc' %] +[% INCLUDE 'datatables.inc' %] + @@ -19,30 +197,38 @@
-

Rotating collections: Add/Remove items

+

Rotating collections: Manage collection

-
+

[% IF ( previousActionAdd ) %] [% IF ( addSuccess ) %] -
Item with barcode '[% addedBarcode %]' Added successfully!
+
Item with barcode '[% addedBarcode %]' Added successfully!
[% ELSE %] -
Failed to add item with barcode '[% addedBarcode %]'!
-
Reason: [% failureMessage %]
+
Failed to add item with barcode '[% addedBarcode %]'!
+
Reason: [% failureMessage %]
[% END %] [% END %] [% IF ( previousActionRemove ) %] [% IF ( removeSuccess ) %] -
Item with barcode '[% addedBarcode %]' Removed successfully!
+
Item with barcode '[% removedBarcode %]' Removed successfully! + [% IF messages %] + Transfer messages: +
    + [% FOREACH message in messages %] +
  • [% message %]
  • + [% END %] +
+ [% END %] +
[% ELSE %] -
Failed to remove item with barcode '[% removedBarcode %]'!
-
Reason: [% failureMessage %]
+
Failed to remove item with barcode '[% removedBarcode %]'!
+
Reason: [% failureMessage %]
[% END %] [% END %] - -

Add item to [% colTitle %]

+

Add items to [% colTitle %]

@@ -64,20 +250,36 @@
+

Items in this collection

-

Items in this collection

[% IF ( collectionItemsLoop ) %] - - - - - - +
TitleCall numberBarcode
+ + + + + + + + + + + + + + [% FOREACH collectionItemsLoo IN collectionItemsLoop %] - + - + + + + + + + + [% END %]
TitleCall numberBarcodeOrigin libraryHome libraryCurrent locationTransferredTransferReturnRemove
[% collectionItemsLoo.title |html %][% collectionItemsLoo.title |html %] [% collectionItemsLoo.itemcallnumber %][% collectionItemsLoo.barcode %][% collectionItemsLoo.barcode %][% collectionItemsLoo.origin_branchname %][% collectionItemsLoo.branchname %][% collectionItemsLoo.holdingbranchname %][% IF collectionItemsLoo.transferred %]Yes[% ELSE %]No[% END %] Transfer Return Remove
@@ -88,10 +290,102 @@

- + Return to rotating collections home + Transfer this collection +
-
+ + + + + + + + + + +
Processing...
[% INCLUDE 'intranet-bottom.inc' %] --- a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/editCollections.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/editCollections.tt @@ -1,6 +1,79 @@ [% INCLUDE 'doc-head-open.inc' %] Koha › Tools › Rotating collections › Edit collections [% INCLUDE 'doc-head-close.inc' %] +[% INCLUDE 'datatables.inc' %] + + [% INCLUDE 'header.inc' %] @@ -10,67 +83,40 @@
-
+

Rotating collections: Edit collections

- + [% IF ( previousActionUpdate ) %] [% IF ( updateSuccess ) %] -
Collection '[% updatedTitle %]' Updated successfully!
+
Collection '[% updatedTitle %]' Updated successfully!
[% ELSE %] -
Collection '[% updatedTitle %]' Failed to be updated!
-
Reason: [% failureMessage %]
+
Collection '[% updatedTitle %]' Failed to be updated!
+
Reason: [% failureMessage %]
[% END %] [% END %] - +

- [% IF ( collectionsLoop ) %] - - - - - - - - - - - - [% FOREACH collectionsLoo IN collectionsLoop %] - - - - - - - - [% END %] - -
TitleDescriptionHolding library  
[% collectionsLoo.colTitle %][% collectionsLoo.colDesc %][% collectionsLoo.colBranchcode %]EditDelete
- [% ELSE %] - There are no collections currently defined. - [% END %] -
-
+

[% IF ( previousActionEdit ) %] @@ -120,13 +166,57 @@
+
+ + [% IF ( collectionsLoop ) %] + + + + + + + + + + + + [% FOREACH collectionsLoo IN collectionsLoop %] + + + + + + + + [% END %] + +
TitleDescriptionTransferred toEditDelete
[% collectionsLoo.colTitle %][% collectionsLoo.colDesc %][% IF collectionsLoo.branchname %][% collectionsLoo.branchname %][% ELSE %]Not yet transferred[% END %] Edit Delete
+ [% ELSE %] + There are no collections currently defined. + [% END %] +
+ + +
Processing...
[% INCLUDE 'intranet-bottom.inc' %] - --- a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/rotatingCollections.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/rotatingCollections.tt @@ -1,35 +1,257 @@ [% INCLUDE 'doc-head-open.inc' %] Koha › Tools › Rotating collections [% INCLUDE 'doc-head-close.inc' %] +[% INCLUDE 'datatables.inc' %] + + [% INCLUDE 'header.inc' %] [% INCLUDE 'cat-search.inc' %] - +
+
+
-

Rotating collections

+

Rotating collections

[% IF ( collectionsLoop ) %] - - - - - - - - +
TitleDescriptionCurrent locationAdd/Remove itemsTransfer collection
+ + + + + + + + + + + + + [% FOREACH collectionsLoo IN collectionsLoop %] - - - - - + + + + + + + + + + [% END %]
TitleDescriptionOwnerItemsTransferredTransfer collectionEditDelete
[% collectionsLoo.colTitle %][% collectionsLoo.colDesc %][% collectionsLoo.colBranchcode %]Add/Remove ItemsTransfer Collection[% collectionsLoo.colTitle %][% collectionsLoo.colDesc %][% collectionsLoo.branchname %][% collectionsLoo.colItemsCount %][% IF collectionsLoo.itemsTransferred > 0 %] + [% IF collectionsLoo.itemsTransferred == collectionsLoo.colItemsCount %] + All items transferred + [% ELSE %] + [% collectionsLoo.itemsTransferred %] items transferred + [% END %] + [% ELSE %] + None transferred yet + [% END %] + Transfer collection + Edit Delete
@@ -39,9 +261,118 @@
-[% INCLUDE 'intranet-bottom.inc' %] + + + + + + + + +
Processing...
+[% INCLUDE 'intranet-bottom.inc' %] --- a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/transferCollection.tt +++ a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/transferCollection.tt @@ -9,23 +9,69 @@
-
+

Rotating collections: Transfer collection


- [% IF ( transferSuccess ) %] -
Collection transferred successfully
- [% END %] - - [% IF ( transferFailure ) %] -
Failed to transfer collection!
-
Reason: [% errorMessage %]
+
+ + [% IF transferSuccess && previousAction == "collectionTransfer" %] +
Collection transferred successfully
+ [% ELSIF transferSuccess && previousAction == "itemTransfer" %] +
Item transferred successfully
+ [% ELSIF transferSuccess && previousAction == "itemReturn" %] +
Item returned successfully
+ [% ELSIF transferSuccess && previousAction == "collectionReturn" && problemItems %] +
Some items returned succesfully, problematic items:
+ [% FOREACH item IN problemItems %] + [% item %]
+ [% END %] +
+ [% ELSIF transferSuccess && previousAction == "collectionReturn" && !problemItems %] +
Collection returned succesfully
+ + [% ELSIF transferSuccess && previousAction == "collectionTransfer" && problemItems %] +
Some items transferred succesfully, problematic items:
+ [% FOREACH item IN problemItems %] + [% item %]
+ [% END %] +
+ + [% ELSIF transferFailure && previousAction == "collectionTransfer" %] +
Failed to transfer any items in collection!
+
Problems:
+ [% FOREACH item IN problemItems %] + [% item %]
+ [% END %] +
+ [% ELSIF transferFailure && previousAction == "itemTransfer" %] +
Failed to transfer item!
+
Problems:
+ [% FOREACH error IN errorMessage %] + [% error %]
+ [% END %] +
+ [% ELSIF transferFailure && previousAction == "itemReturn" %] +
Failed to return item!
+
Problems:
+ [% FOREACH error IN errorMessage %] + [% error %]
+ [% END %] +
+ [% ELSIF transferFailure && previousAction == "collectionReturn" %] +
Failed to return any item in collection!
+
Problematic items:
+ [% FOREACH item IN errorMessages %] + [% item %]
+ [% END %] +
[% END %] - +
[% IF ( transferSuccess ) %] [% ELSE %]
+ + Return to rotating collections home
- +
[% INCLUDE 'intranet-bottom.inc' %] --- a/rotating_collections/addItems.pl +++ a/rotating_collections/addItems.pl @@ -23,14 +23,14 @@ use C4::Auth; use C4::Context; use C4::RotatingCollections; use C4::Items; +use C4::Branch; use CGI; my $query = new CGI; - my ( $template, $loggedinuser, $cookie ) = get_template_and_user( { - template_name => "rotating_collections/addItems.tmpl", + template_name => "rotating_collections/addItems.tt", query => $query, type => "intranet", authnotrequired => 0, @@ -77,11 +77,13 @@ if ( $query->param('action') eq 'addItem' ) { ); if ($success) { - $template->param( removeSuccess => 1 ); + $template->param(removeSuccess => 1); + # Item's transfer can fail even if the removal itself was succesful + $template->param(messages => $errorMessage) if ($errorMessage); } else { - $template->param( removeFailure => 1 ); - $template->param( failureMessage => $errorMessage ); + $template->param(removeFailure => 1); + $template->param(failureMessage => $errorMessage); } } @@ -90,10 +92,14 @@ if ( $query->param('action') eq 'addItem' ) { my ( $colId, $colTitle, $colDescription, $colBranchcode ) = GetCollection( $query->param('colId') ); my $collectionItems = GetItemsInCollection($colId); + if ($collectionItems) { + $template->param( collectionItemsLoop => $collectionItems ); } +my $branchesLoop = GetBranchesLoop(); + $template->param( intranetcolorstylesheet => C4::Context->preference("intranetcolorstylesheet"), @@ -104,6 +110,7 @@ $template->param( colTitle => $colTitle, colDescription => $colDescription, colBranchcode => $colBranchcode, + branchesLoop => $branchesLoop ); output_html_with_http_headers $query, $cookie, $template->output; --- a/rotating_collections/editCollections.pl +++ a/rotating_collections/editCollections.pl @@ -27,10 +27,9 @@ use C4::Context; use C4::RotatingCollections; my $query = new CGI; - my ( $template, $loggedinuser, $cookie ) = get_template_and_user( { - template_name => "rotating_collections/editCollections.tmpl", + template_name => "rotating_collections/editCollections.tt", query => $query, type => "intranet", authnotrequired => 0, @@ -43,9 +42,11 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( if ( $query->param('action') eq 'create' ) { my $title = $query->param('title'); my $description = $query->param('description'); + my $userenv = C4::Context->userenv; + my $owningbranch = $userenv->{'branch'}; my ( $createdSuccessfully, $errorCode, $errorMessage ) = - CreateCollection( $title, $description ); + CreateCollection( $title, $description, $owningbranch ); $template->param( previousActionCreate => 1, --- a/rotating_collections/rotatingCollections.pl +++ a/rotating_collections/rotatingCollections.pl @@ -23,13 +23,13 @@ use CGI; use C4::Output; use C4::Auth; use C4::Context; +use C4::Branch; use C4::RotatingCollections; my $query = new CGI; - my ( $template, $loggedinuser, $cookie ) = get_template_and_user( { - template_name => "rotating_collections/rotatingCollections.tmpl", + template_name => "rotating_collections/rotatingCollections.tt", query => $query, type => "intranet", authnotrequired => 0, @@ -39,6 +39,7 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( ); my $branchcode = $query->cookie('branch'); +my $branchesLoop = GetBranchesLoop(); my $collections = GetCollections(); @@ -49,6 +50,7 @@ $template->param( IntranetNav => C4::Context->preference("IntranetNav"), collectionsLoop => $collections, + branchesLoop => $branchesLoop ); output_html_with_http_headers $query, $cookie, $template->output; --- a/rotating_collections/transferCollection.pl +++ a/rotating_collections/transferCollection.pl @@ -28,12 +28,14 @@ use CGI; my $query = new CGI; -my $colId = $query->param('colId'); +my $colId = $query->param('colId'); +my $itemNumber = $query->param('itemNumber'); my $toBranch = $query->param('toBranch'); +my $transferAction = $query->param('transferAction'); my ( $template, $loggedinuser, $cookie ) = get_template_and_user( { - template_name => "rotating_collections/transferCollection.tmpl", + template_name => "rotating_collections/transferCollection.tt", query => $query, type => "intranet", authnotrequired => 0, @@ -43,27 +45,103 @@ my ( $template, $loggedinuser, $cookie ) = get_template_and_user( ); ## Transfer collection -my ( $success, $errorCode, $errorMessage ); -if ($toBranch) { - ( $success, $errorCode, $errorMessage ) = - TransferCollection( $colId, $toBranch ); +if ($transferAction eq 'collectionTransfer') { + my ($success, $errorCode, $problemItems); + if ($toBranch) { + ($success, $errorCode, $problemItems) = + TransferCollection($colId, $toBranch); - if ($success) { - $template->param( transferSuccess => 1 ); + if ($success) { + $template->param( + transferSuccess => 1, + previousAction => 'collectionTransfer' + ); + } + else { + $template->param( + transferFailure => 1, + errorCode => $errorCode, + problemItems => $problemItems, + previousAction => 'collectionTransfer' + ); + } } - else { - $template->param( - transferFailure => 1, - errorCode => $errorCode, - errorMessage => $errorMessage - ); +} + +## Transfer an item +if ($transferAction eq 'itemTransfer') { + my ($success, $errorCode, $errorMessage); + if ($toBranch && $itemNumber) { + ($success, $errorCode, $errorMessage) = + TransferCollectionItem($colId, $itemNumber, $toBranch); + if ($success) { + $template->param( + transferSuccess => 1, + previousAction => 'itemTransfer' + ); + } + else { + $template->param( + transferFailure => 1, + errorCode => $errorCode, + errorMessage => $errorMessage, + previousAction => 'itemTransfer' + ); + } + } +} + +## Return an item +if ($transferAction eq 'itemReturn') { + my ($success, $errorCode, $errorMessage); + if ($colId && $itemNumber) { + ($success, $errorCode, $errorMessage) = + ReturnCollectionItemToOrigin($colId, $itemNumber); + if ($success) { + $template->param( + transferSuccess => 1, + previousAction => 'itemReturn' + ); + } + else { + $template->param( + transferFailure => 1, + errorCode => $errorCode, + errorMessage => $errorMessage, + previousAction => 'itemReturn' + ); + } + } +} + +## Return a collection +if ($transferAction eq 'collectionReturn') { + my ($success, $errorCode, $errorMessages); + if ($colId) { + ($success, $errorCode, $errorMessages) = + ReturnCollectionToOrigin($colId); + if ($success) { + $template->param( + transferSuccess => 1, + problemItems => $errorMessages, + previousAction => 'collectionReturn' + ); + } + else { + $template->param( + transferFailure => 1, + errorCode => $errorCode, + errorMessages => $errorMessages, + previousAction => 'collectionReturn' + ); + } } } ## Set up the toBranch select options my $branches = GetBranches(); my @branchoptionloop; -foreach my $br ( keys %$branches ) { +foreach my $br ( sort(keys %$branches) ) { my %branch; $branch{code} = $br; $branch{name} = $branches->{$br}->{'branchname'}; --