From a6b3a980a2c24be783ed794a81a73d7d88194764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Sepp=C3=A4l=C3=A4?= Date: Mon, 18 Aug 2014 11:58:43 +0300 Subject: [PATCH] Bug 8836 - Resurrect Rotating Collections: additions This is patch is an enchancement patch based on our requirements (sending in hopes that it could be useful to someone) and is ment to be applied on top of my squashed rotating collections patch and focuses mainly on the interface, aiming to streamline workflow and and to reduce unnecessary page reloads. Core rotating collection functionality is also changed in that transfers are now handled on the item level instead of on the collection level. This allows individual items in the collection to have their own transfer branches - you can still of course have all items transferred to the same destination by using the collection transfer feature in the main view or in the additems-view. Note: as this is a fairly large change in how collections are handled, this patch cannot be used directly with collections managed by the old system. List of larger changes (of the top of my head): - 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 exists - 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), Items(count), Transferred(how many items in collection are transferred), Transfer collection, Edit and Delete. - 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 collection_tracking). The old collection-level transfer branch in collections is no longer needed but is not touched by this patch. - 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. Sadly, this is *not* a complete list of changes. --- 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(-) diff --git a/C4/Circulation.pm b/C4/Circulation.pm index eb4ffdd..20aff9f 100644 --- a/C4/Circulation.pm +++ b/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; diff --git a/C4/RotatingCollections.pm b/C4/RotatingCollections.pm index 5a63cd8..c4a5eb2 100644 --- a/C4/RotatingCollections.pm +++ b/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__ diff --git a/catalogue/detail.pl b/catalogue/detail.pl index 967d71d..788ef67 100755 --- a/catalogue/detail.pl +++ b/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}; diff --git a/circ/returns.pl b/circ/returns.pl index 8a17a10..8dbd060 100755 --- a/circ/returns.pl +++ b/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), diff --git a/installer/data/mysql/kohastructure.sql b/installer/data/mysql/kohastructure.sql index c21ac83..eff86c3 100644 --- a/installer/data/mysql/kohastructure.sql +++ b/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; -- diff --git a/installer/data/mysql/updatedatabase.pl b/installer/data/mysql/updatedatabase.pl index 078ba46..c614798 100755 --- a/installer/data/mysql/updatedatabase.pl +++ b/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) diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt index e10d95f..3d2a931 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt +++ b/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 %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/addItems.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/addItems.tt index 195b324..110971d 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/addItems.tt +++ b/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' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/editCollections.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/editCollections.tt index e1bb2a8..249c988 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/editCollections.tt +++ b/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' %] - diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/rotatingCollections.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/rotatingCollections.tt index e1780ad..7470178 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/rotatingCollections.tt +++ b/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' %] \ No newline at end of file + + + + + + + + +
Processing...
+[% INCLUDE 'intranet-bottom.inc' %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/transferCollection.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/transferCollection.tt index 25f2cb2..a322803 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/rotating_collections/transferCollection.tt +++ b/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' %] diff --git a/rotating_collections/addItems.pl b/rotating_collections/addItems.pl index 9ef4f39..c570f0e 100755 --- a/rotating_collections/addItems.pl +++ b/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; diff --git a/rotating_collections/editCollections.pl b/rotating_collections/editCollections.pl index aa46f44..8d7f66e 100755 --- a/rotating_collections/editCollections.pl +++ b/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, diff --git a/rotating_collections/rotatingCollections.pl b/rotating_collections/rotatingCollections.pl index 59bbcdb..357461a 100755 --- a/rotating_collections/rotatingCollections.pl +++ b/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; diff --git a/rotating_collections/transferCollection.pl b/rotating_collections/transferCollection.pl index 630c222..301f34a 100755 --- a/rotating_collections/transferCollection.pl +++ b/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'}; -- 1.9.1