From 85c4b1771ae154a494c751fe81fc328452d1343a Mon Sep 17 00:00:00 2001 From: Alex Buckley Date: Sat, 25 Aug 2018 13:52:37 +1200 Subject: [PATCH] Bug 20844: Revert hold when setting an item to lost If an item is marked as 'Lost' then this patch introduces the following new functionality: 1. Check if there is a bib-level or item-level hold on the item with the status of 'W' (waiting). This is an allocated hold which is not yet checked out to the requesting patron. 1.a. If the hold was originally a bib-level reserve (reserves.originalholdtype='B') then do the following: * Revert the waiting status of the reserve * Set the reserves.itemnumber=NULL so the hold is reset to a bib-level hold 1.b. If the hold was originally (and still is) a item-level hold (reserves.originalholdtype='I') then display a alert dialog box on the additem.pl interface asking the librarian to select one of two options: * Cancel the hold - This deletes the hold altogether * Retain the hold - This does not change the hold. Therefore the requester will still have a hold on a lost item NOTE: Previously an allocated bib-level hold was identical to a item-level hold in the database. As the first available item on the bib record had been allocated to the requester and so an itemnumber had been set in the record in the reserves table. However this patch introduces a atomicupdate which adds the new column 'originalholdtype' to the reserves table. This allows us to track if the reserve was originally a bib level hold and treat it differently when the allocated item is being marked as 'Lost' Test plan: 1. Place a bib-level hold on a biblio 2. Check out an item from the biblio to a different patron 3. Query the reserves db table for biblio you placed the bib-level hold and notice it has no 'itemnumber' or 'status' value 4. Return the item and confirm the hold in the modal box that is loaded 5. Query the reserves db table and notice the itemnumber field is now filled with the returned item's itemnumber and the status is 'W' 6. Set the item to 'Lost' either by clicking on Edit->Edit items from the detail.pl page OR clicking on the Items tab on the left side of the detail.pl page 7. Notice the waiting item-level hold still exists after the item is marked as 'lost' 8. Repeat steps 1-7 but this time place an item-level hold on an item in step 1 and then check that same item out in step 2. Notice in the repeated step 7 that the hold remains after marking the item as 'Lost' 9. Apply patch and run ./updatedatabase.pl from the koha-shell in the installer/data/mysql/ directory 9. Repeat steps 1-6 placing an bib-level hold and then query the database and notice the bib-level hold which was changed to an allocated waiting item-level hold when the item was returned and the hold confirmed is now reverted to a bib-level hold again. This is controlled by the LostBibLevelHoldsRevert syspref. If this syspref is not enabled then the allocated item-level (originally bib-level hold) will remain after the item is marked as lost. 10. Repeat 1-6 but this time place an item-level hold on the item. Notice when you mark the item as 'Lost' a yellow warning box is displayed asking if you want to 'Retain hold' or 'Cancel hold'. Select 'Retain hold' and notice the item-level hold remains now the item is marked as lost. 11. Repeat step 10 but choose 'Cancel hold' option and notice the hold is deleted now. 12. Now enable the new 'LostItemCancelOutstandingTransfers' syspref. This will now cancel any outstanding transfers on the item when it is marked as lost. 13. Find a item which is in transfer, i.e. find an item with the text in the 'Status' field of the table in detail.pl that indicates it is in transfer 14. Now mark that item as 'Lost' and now notice the transfer is cancelled 15. Go into koha-shell from the Koha home dir: sudo koha-shell 16. Run the RevertWaitingStatus.t test file: prove t/db_dependent/Holds/RevertWaitingStatus.t Sponsored-By: Brimbank Library, Australia Signed-off-by: Owen Leonard --- C4/Circulation.pm | 17 +++ C4/Reserves.pm | 109 ++++++++++++++---- Koha/Schema/Result/OldReserve.pm | 12 +- Koha/Schema/Result/Reserve.pm | 12 +- catalogue/moredetail.pl | 7 ++ catalogue/updateitem.pl | 23 +++- cataloguing/additem.pl | 34 +++++- ...20844-added-holdtype-field-to-reserves.sql | 3 + .../admin/preferences/circulation.pref | 6 + .../prog/en/modules/catalogue/moredetail.tt | 19 ++- .../prog/en/modules/cataloguing/additem.tt | 14 +++ t/db_dependent/Holds/RevertWaitingStatus.t | 64 +++++++++- 12 files changed, 286 insertions(+), 34 deletions(-) create mode 100644 installer/data/mysql/atomicupdate/bug_20844-added-holdtype-field-to-reserves.sql diff --git a/C4/Circulation.pm b/C4/Circulation.pm index 221ed31a9f..027203c1dc 100644 --- a/C4/Circulation.pm +++ b/C4/Circulation.pm @@ -3684,6 +3684,23 @@ sub LostItem{ DeleteTransfer($itemnumber); } + my ( $restype, $res ) = C4::Reserves::CheckReserves( $itemnumber ); + my $LostItemLevelHold; + if ( $restype eq "Waiting" || $restype eq "Reserved" ) { + if ( $res->{originalholdtype} eq "B" ) { + #originalholdtype equalling "B" means this is a bib level hold + C4::Reserves::RevertWaitingStatus({itemnumber => $itemnumber}); + + #If the LostBibLevelHoldsRevert syspref is enabled then revert the allocated reserve back to an unallocated bib-level hold + if ( C4::Context->preference('LostBibLevelHoldsRevert')) { + C4::Reserves::RevertItemLevelHoldToBibLevelHold({ reserveid => $res->{reserve_id} }); + } + } else { + #Otherwise originalholdtype equals "I" and is an item level hold + $LostItemLevelHold = 1; + } + } + return $LostItemLevelHold; } sub GetOfflineOperations { diff --git a/C4/Reserves.pm b/C4/Reserves.pm index 78e8f6a360..d5cbd7d1d9 100644 --- a/C4/Reserves.pm +++ b/C4/Reserves.pm @@ -130,6 +130,8 @@ BEGIN { &AlterPriority &ToggleLowestPriority + &RevertWaitingStatus + &RevertItemLevelHoldToBibLevelHold &ReserveSlip &ToggleSuspend &SuspendAll @@ -198,23 +200,47 @@ sub AddReserve { # Don't add itemtype limit if specific item is selected $itemtype = undef if $checkitem; - # updates take place here - my $hold = Koha::Hold->new( - { - borrowernumber => $borrowernumber, - biblionumber => $biblionumber, - reservedate => $resdate, - branchcode => $branch, - priority => $priority, - reservenotes => $notes, - itemnumber => $checkitem, - found => $found, - waitingdate => $waitingdate, - expirationdate => $expdate, - itemtype => $itemtype, - } - )->store(); - $hold->set_waiting() if $found eq 'W'; + # Create reserves with with originalholdtype="B" if biblio level hold and "I" if item level hold + my $hold; + if (!($checkitem)) { + # updates take place here + $hold = Koha::Hold->new( + { + borrowernumber => $borrowernumber, + biblionumber => $biblionumber, + reservedate => $resdate, + branchcode => $branch, + priority => $priority, + reservenotes => $notes, + itemnumber => $checkitem, + found => $found, + waitingdate => $waitingdate, + expirationdate => $expdate, + itemtype => $itemtype, + originalholdtype => 'B', + } + )->store(); + $hold->set_waiting() if $found eq 'W'; + } else { + # updates take place here + $hold = Koha::Hold->new( + { + borrowernumber => $borrowernumber, + biblionumber => $biblionumber, + reservedate => $resdate, + branchcode => $branch, + priority => $priority, + reservenotes => $notes, + itemnumber => $checkitem, + found => $found, + waitingdate => $waitingdate, + expirationdate => $expdate, + itemtype => $itemtype, + originalholdtype => 'I', + } + )->store(); + $hold->set_waiting() if $found eq 'W'; + } logaction( 'HOLDS', 'CREATE', $hold->id, Dumper($hold->unblessed) ) if C4::Context->preference('HoldsLog'); @@ -1405,11 +1431,9 @@ sub _FixPriority { $hold = Koha::Holds->find( $reserve_id ); return unless $hold; } - unless ( $biblionumber ) { # FIXME This is a very weird API $biblionumber = $hold->biblionumber; } - if ( $rank eq "del" ) { # FIXME will crash if called without $hold $hold->cancel; } @@ -1521,7 +1545,8 @@ sub _Findgroupreserve { biblioitems.biblioitemnumber AS biblioitemnumber, reserves.itemnumber AS itemnumber, reserves.reserve_id AS reserve_id, - reserves.itemtype AS itemtype + reserves.itemtype AS itemtype, + reserves.originalholdtype AS originalholdtype FROM reserves JOIN biblioitems USING (biblionumber) JOIN hold_fill_targets USING (biblionumber, borrowernumber, itemnumber) @@ -1556,7 +1581,8 @@ sub _Findgroupreserve { biblioitems.biblioitemnumber AS biblioitemnumber, reserves.itemnumber AS itemnumber, reserves.reserve_id AS reserve_id, - reserves.itemtype AS itemtype + reserves.itemtype AS itemtype, + reserves.originalholdtype AS originalholdtype FROM reserves JOIN biblioitems USING (biblionumber) JOIN hold_fill_targets USING (biblionumber, borrowernumber) @@ -1590,7 +1616,8 @@ sub _Findgroupreserve { reserves.timestamp AS timestamp, reserves.itemnumber AS itemnumber, reserves.reserve_id AS reserve_id, - reserves.itemtype AS itemtype + reserves.itemtype AS itemtype, + reserves.originalholdtype AS originalholdtype FROM reserves WHERE reserves.biblionumber = ? AND (reserves.itemnumber IS NULL OR reserves.itemnumber = ?) @@ -1910,6 +1937,44 @@ sub RevertWaitingStatus { _FixPriority( { biblionumber => $reserve->{biblionumber} } ); } + +=head2 RevertItemLevelHoldToBibLevelHold + + RevertItemLevelHoldToBibLevelHold({ reserveid => $reserveid }); + + Reverts a item level hold (which was originally a bib-level hold, which is determined by the value of reserves.originalholdtype) back to a bib-level hold. + +=cut + +sub RevertItemLevelHoldToBibLevelHold { + my ( $params ) = @_; + my $reserve_id = $params->{'reserveid'}; + + return unless ( $reserve_id ); + my $dbh = C4::Context->dbh; + + #Get the waiting reserve we want to revert + my $query = " + SELECT * FROM reserves + WHERE reserve_id = ? + AND itemnumber IS NOT NULL + "; + my $sth = $dbh->prepare( $query ); + $sth->execute( $reserve_id ); + my $reserve = $sth->fetchrow_hashref(); + + ## Set the itemnumber to 'NULL' + $query = " + UPDATE reserves + SET + itemnumber = NULL + WHERE + reserve_id = ? + "; + $sth = $dbh->prepare( $query ); + $sth->execute( $reserve_id ); +} + =head2 ReserveSlip ReserveSlip( diff --git a/Koha/Schema/Result/OldReserve.pm b/Koha/Schema/Result/OldReserve.pm index 851f00c90d..5e085cf385 100644 --- a/Koha/Schema/Result/OldReserve.pm +++ b/Koha/Schema/Result/OldReserve.pm @@ -137,6 +137,12 @@ __PACKAGE__->table("old_reserves"); is_nullable: 1 size: 10 +=head2 originalholdtype + + data_type: 'varchar' + is_nullable: 1 + size: 1 + =cut __PACKAGE__->add_columns( @@ -192,6 +198,8 @@ __PACKAGE__->add_columns( }, "itemtype", { data_type => "varchar", is_foreign_key => 1, is_nullable => 1, size => 10 }, + "originalholdtype", + { data_type => "varchar", is_nullable => 1, size => 1 }, ); =head1 PRIMARY KEY @@ -289,8 +297,8 @@ __PACKAGE__->belongs_to( ); -# Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-02-16 17:54:54 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ynb6NtiTN8ZZur2YCvxlNg +# Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-09-02 09:48:38 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:cc4o9r7wLXapCJJ3WfDy4g # You can replace this text with custom content, and it will be preserved on regeneration diff --git a/Koha/Schema/Result/Reserve.pm b/Koha/Schema/Result/Reserve.pm index 1ba1c974f6..3866861194 100644 --- a/Koha/Schema/Result/Reserve.pm +++ b/Koha/Schema/Result/Reserve.pm @@ -141,6 +141,12 @@ __PACKAGE__->table("reserves"); is_nullable: 1 size: 10 +=head2 originalholdtype + + data_type: 'varchar' + is_nullable: 1 + size: 1 + =cut __PACKAGE__->add_columns( @@ -206,6 +212,8 @@ __PACKAGE__->add_columns( }, "itemtype", { data_type => "varchar", is_foreign_key => 1, is_nullable => 1, size => 10 }, + "originalholdtype", + { data_type => "varchar", is_nullable => 1, size => 1 }, ); =head1 PRIMARY KEY @@ -313,8 +321,8 @@ __PACKAGE__->belongs_to( ); -# Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-02-16 17:54:54 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:2GCET9quFpUvzuN7MUWZNw +# Created by DBIx::Class::Schema::Loader v0.07042 @ 2018-08-25 12:05:26 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:YIZXhPQwRJXrzYkdmVQH7Q __PACKAGE__->belongs_to( "item", diff --git a/catalogue/moredetail.pl b/catalogue/moredetail.pl index ba599370e3..7395993047 100755 --- a/catalogue/moredetail.pl +++ b/catalogue/moredetail.pl @@ -71,6 +71,13 @@ my $itemnumber = $query->param('itemnumber'); my $data = &GetBiblioData($biblionumber); my $dewey = $data->{'dewey'}; my $showallitems = $query->param('showallitems'); +my $lostitemlevelhold = $query->param('LostItemLevelHold'); +my $lostitemnumber = $query->param('lostitemnumber'); +my $itemlost = $query->param('itemlost'); + +if ($lostitemlevelhold && $itemlost) { + $template->param(LostItemLevelHold => $lostitemlevelhold, itemlost => $itemlost, lostitemnumber => $lostitemnumber, biblionumber => $biblionumber); +} #coping with subscriptions my $subscriptionsnumber = CountSubscriptionFromBiblionumber($biblionumber); diff --git a/catalogue/updateitem.pl b/catalogue/updateitem.pl index f06dfedfb1..3f0f001969 100755 --- a/catalogue/updateitem.pl +++ b/catalogue/updateitem.pl @@ -26,6 +26,7 @@ use C4::Items; use C4::Output; use C4::Circulation; use C4::Reserves; +use Data::Dumper; my $cgi= new CGI; @@ -39,6 +40,8 @@ my $itemnotes=$cgi->param('itemnotes'); my $itemnotes_nonpublic=$cgi->param('itemnotes_nonpublic'); my $withdrawn=$cgi->param('withdrawn'); my $damaged=$cgi->param('damaged'); +my $cancelhold = $cgi->param('CancelHold'); +my $retainhold = $cgi->param('RetainHold'); my $confirm=$cgi->param('confirm'); my $dbh = C4::Context->dbh; @@ -53,8 +56,19 @@ for ($damaged,$itemlost,$withdrawn) { } } +if ($cancelhold) { + my ($restype, $res ) = C4::Reserves::CheckReserves( $itemnumber ); + my $hold = Koha::Holds->find($res->{reserve_id}); + $hold->cancel; +} + +#Assigning variables for use in cancelling item level holds when item marked as 'Lost' +my $LostItemLevelHold; +my $originalitemnumber = $itemnumber; + # modify MARC item if input differs from items table. my $item_changes = {}; + if (defined $itemnotes_nonpublic) { # i.e., itemnotes_nonpublic parameter passed from form checkauth($cgi, 0, {editcatalogue => 'edit_items'}, 'intranet'); if ((not defined $item_data_hashref->{'itemnotes_nonpublic'}) or $itemnotes_nonpublic ne $item_data_hashref->{'itemnotes_nonpublic'}) { @@ -79,7 +93,12 @@ elsif (defined $itemnotes) { # i.e., itemnotes parameter passed from form } ModItem($item_changes, $biblionumber, $itemnumber); +$LostItemLevelHold = LostItem($itemnumber, 'moredetail') if $itemlost; + +if ( $LostItemLevelHold) { + print $cgi->redirect("moredetail.pl?biblionumber=$biblionumber&LostItemLevelHold=$LostItemLevelHold&itemlost=$itemlost&lostitemnumber=$itemnumber#item$itemnumber"); +} else { + print $cgi->redirect("moredetail.pl?biblionumber=$biblionumber&itemnumber=$itemnumber#item$itemnumber"); +} -LostItem($itemnumber, 'moredetail') if $itemlost; -print $cgi->redirect("moredetail.pl?biblionumber=$biblionumber&itemnumber=$itemnumber#item$itemnumber"); diff --git a/cataloguing/additem.pl b/cataloguing/additem.pl index 6af351d375..9d32e54f73 100755 --- a/cataloguing/additem.pl +++ b/cataloguing/additem.pl @@ -40,7 +40,7 @@ use C4::Search; use Storable qw(thaw freeze); use URI::Escape; use C4::Members; - +use Data::Dumper; use MARC::File::XML; use URI::Escape; @@ -385,9 +385,18 @@ my $fa_barcode = $input->param('barcode'); my $fa_branch = $input->param('branch'); my $fa_stickyduedate = $input->param('stickyduedate'); my $fa_duedatespec = $input->param('duedatespec'); - +my $cancelhold = $input->param('CancelHold'); +my $retainhold = $input->param('RetainHold'); my $frameworkcode = &GetFrameworkCode($biblionumber); +if ($cancelhold || $retainhold) { + $op =''; +} + +#Assigning variables for use in cancelling item level holds when item marked as 'Lost' +my $LostItemLevelHold; +my $originalitemnumber = $itemnumber; + # Defining which userflag is needing according to the framework currently used my $userflags; if (defined $input->param('frameworkcode')) { @@ -692,6 +701,7 @@ if ($op eq "additem") { # check that the barcode don't exist already my $addedolditem = TransformMarcToKoha($itemtosave); my $exist_itemnumber = get_item_from_barcode($addedolditem->{'barcode'}); + my $lostitemnumber; if ($exist_itemnumber && $exist_itemnumber != $itemnumber) { push @errors,"barcode_not_unique"; } else { @@ -700,9 +710,14 @@ if ($op eq "additem") { $itemnumber = q{}; my $olditemlost = $item->{itemlost}; my $newitemlost = $newitem->{itemlost}; - LostItem( $item->{itemnumber}, 'additem' ) + $LostItemLevelHold = LostItem( $item->{itemnumber}, 'additem' ) if $newitemlost && $newitemlost ge '1' && !$olditemlost; } + + if ($LostItemLevelHold) { + $lostitemnumber = $originalitemnumber; + } + $template->param( LostItemLevelHold => $LostItemLevelHold, lostitemnumber => $lostitemnumber ); $nextop="additem"; } elsif ($op eq "delinkitem"){ my $analyticfield = '773'; @@ -720,6 +735,12 @@ if ($op eq "additem") { my $modbibresult = ModBiblio($record, $biblionumber,''); } +if ($cancelhold) { + my ( $restype, $res ) = C4::Reserves::CheckReserves( $originalitemnumber ); + my $hold = Koha::Holds->find($res->{reserve_id}); + $hold->cancel; +} + # #------------------------------------------------------------------------------- # build screen with existing items. and "new" one @@ -905,6 +926,13 @@ foreach my $tag ( keys %{$tagslib}){ my $item = Koha::Items->find($itemnumber); # We certainly want to fetch it earlier +#If you are trying to mark an item as lost which has an item level hold on it return $originalitemnumber +if ($LostItemLevelHold) { + $template->param( itemnumber => $originalitemnumber); +} else { + $template->param( itemnumber => $itemnumber ); +} + # what's the next op ? it's what we are not in : an add if we're editing, otherwise, and edit. $template->param( biblionumber => $biblionumber, diff --git a/installer/data/mysql/atomicupdate/bug_20844-added-holdtype-field-to-reserves.sql b/installer/data/mysql/atomicupdate/bug_20844-added-holdtype-field-to-reserves.sql new file mode 100644 index 0000000000..ef27ecc04b --- /dev/null +++ b/installer/data/mysql/atomicupdate/bug_20844-added-holdtype-field-to-reserves.sql @@ -0,0 +1,3 @@ +ALTER TABLE reserves ADD originalholdtype VARCHAR(1); +ALTER TABLE old_reserves ADD originalholdtype VARCHAR(1); +INSERT INTO systempreferences (variable, value, options, explanation, type) VALUES ('LostBibLevelHoldsRevert', 1, 'Enable|Disable', 'If the item which has an allocated hold on it which was originally a bib-level hold then when the item is marked as lost revert the hold to a bib-level hold', 'YesNo'); diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref index c5cdca0f2d..32b98aab40 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref @@ -595,6 +595,12 @@ Circulation: - pref: ReservesMaxPickUpDelay class: integer - days. + - + - If the item which has an allocated hold on it which was originally a bib-level hold is marked as lost then revert the hold to a bib-level hold + - pref: LostBibLevelHoldsRevert + choices: + yes: "Enable" + no: "Disable" - - pref: LostItemCancelOutstandingTransfers choices: diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt index 4474432d93..95af665733 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt @@ -42,14 +42,29 @@ Show all items[% END %] +
[% IF ( ONLY_ONE ) %]
You are only viewing one item. View All
[% END %] + [% FOREACH ITEM_DAT IN ITEM_DATA %]
-

Barcode [% ITEM_DAT.barcode | html %] [% IF ( ITEM_DAT.notforloantext ) %][% ITEM_DAT.notforloantext | html %] [% END %]

-

Item information [% IF ( CAN_user_editcatalogue_edit_catalogue ) %][% UNLESS ( ITEM_DAT.nomod ) %] +

Barcode [% ITEM_DAT.barcode | html %] [% IF ( ITEM_DAT.notforloantext ) %][% ITEM_DAT.notforloantext | html %] [% END %]

+ [% IF ((ITEM_DAT.itemnumber == lostitemnumber) && (LostItemLevelHold)) %] +
+
+ + + + This item has an item-level hold on it: + + +
+
+ [% END %] + +

Item information [% IF ( CAN_user_editcatalogue_edit_catalogue ) %][% UNLESS ( ITEM_DAT.nomod ) %] [% IF ( CAN_user_editcatalogue_edit_items ) %] [Edit Item] [% END %] diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/additem.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/additem.tt index 7d88b902d0..0d79293017 100644 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/additem.tt +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/additem.tt @@ -258,6 +258,20 @@ function confirm_deletion() { [% ELSE %]

Edit Item #[% itemnumber | html %][% IF ( barcode ) %] / Barcode [% barcode | html %][% END %]

[% END %] + + + [% IF (LostItemLevelHold) %] +
+
+ + This item has an item-level hold on it: + + +
+
+ [% END %] + +
    [% FOREACH ite IN item %] diff --git a/t/db_dependent/Holds/RevertWaitingStatus.t b/t/db_dependent/Holds/RevertWaitingStatus.t index 9877e68b2c..a1a0c20040 100755 --- a/t/db_dependent/Holds/RevertWaitingStatus.t +++ b/t/db_dependent/Holds/RevertWaitingStatus.t @@ -16,7 +16,7 @@ # along with Koha; if not, see . use Modern::Perl; -use Test::More tests => 3; +use Test::More tests => 12; use MARC::Record; use Koha::Libraries; @@ -109,6 +109,68 @@ ok( scalar @$priorities == 2, 'Only 2 holds remain in the reserves table' ); ok( $priorities->[0]->[0] == 1, 'First hold has a priority of 1' ); ok( $priorities->[1]->[0] == 2, 'Second hold has a priority of 2' ); +#Bug 20844 +#Test reverting the waiting status of holds when the reserved items are set to lost + +#Create bib-level hold and test what happens when the item an allocated bib-level hold is allocated on is lost when the LostBibLevelHoldsRevert syspref is enabled +my $hold_id = C4::Reserves::AddReserve( + $branchcode, + 4, + $biblionumber, + my $bibitems = q{}, + my $priority, + my $resdate, + my $expdate, + my $notes = q{}, + $title, + my $checkitem, + my $found, +); + +my $hold = Koha::Holds->find($hold_id); +is( $hold->originalholdtype, 'B', 'Holds originalholdtype is "B" which is correct' ); +ModReserveAffect($itemnumber, 4, 0); #Confirm the hold - now it's an allocated bib-level hold on $itemnumber and has status is 'W' +$hold = Koha::Holds->find($hold_id); +is( $hold->found, 'W', 'Hold status is "W" (waiting) which is correct' ); +is( $hold->itemnumber, $itemnumber, 'Bib-level hold is allocated and has an itemnumber' ); +t::lib::Mocks::mock_preference( 'LostBibLevelHoldsRevert', 1 ); + +if (C4::Context->preference('LostBibLevelHoldsRevert') ) { + #When item is set to lost revert hold to bib-level (i.e. remove the itemnumber in hold record) and change reserves.found to '' + RevertWaitingStatus({ itemnumber => $itemnumber }); + RevertItemLevelHoldToBibLevelHold({ reserveid => $hold_id }); +} +$hold = Koha::Holds->find($hold_id); +is( $hold->found, undef, 'reserve.found reverted to undef now item is lost' ); +is( $hold->itemnumber, undef, 'Hold reverted back to unallocated bib level hold' ); + +#Create item-level hold and test what happens when the reserved item is set to lost +$hold_id = C4::Reserves::AddReserve( + $branchcode, + 4, + $biblionumber, + $bibitems = q{}, + $priority, + $resdate, + $expdate, + $notes = q{}, + $title, + $itemnumber, + $found, +); + +$hold = Koha::Holds->find($hold_id); +is( $hold->itemnumber, $itemnumber, 'This is an item-level hold' ); + +is( $hold->originalholdtype, 'I', 'Holds originalholdtype is correct' ); +ModReserveAffect($itemnumber, 4, 0); #Confirm the hold - now it's a waiting item-level hold with a reserves.found value of 'W' +$hold = Koha::Holds->find($hold_id); +is( $hold->found, 'W', 'Hold status is waiting' ); + +RevertWaitingStatus({ itemnumber => $itemnumber }); +$hold = Koha::Holds->find($hold_id); +is( $hold->found, undef, 'Reserves found value is reverted to undef as the reserved item has been lost' ); + $schema->storage->txn_rollback; # Helper method to set up a Biblio. -- 2.19.1