View | Details | Raw Unified | Return to bug 20844
Collapse All | Expand All

(-)a/C4/Circulation.pm (-2 / +20 lines)
Lines 3762-3770 sub ReturnLostItem{ Link Here
3762
    MarkIssueReturned( $borrowernumber, $itemnum );
3762
    MarkIssueReturned( $borrowernumber, $itemnum );
3763
}
3763
}
3764
3764
3765
3766
sub LostItem{
3765
sub LostItem{
3767
    my ($itemnumber, $mark_lost_from, $force_mark_returned) = @_;
3766
    my ($itemnumber, $mark_lost_from, $force_mark_returned, $cancel_reserve) = @_;
3768
3767
3769
    unless ( $mark_lost_from ) {
3768
    unless ( $mark_lost_from ) {
3770
        # Temporary check to avoid regressions
3769
        # Temporary check to avoid regressions
Lines 3818-3823 sub LostItem{ Link Here
3818
        Koha::Items->find($itemnumber)->holdingbranch($frombranch)->store;
3817
        Koha::Items->find($itemnumber)->holdingbranch($frombranch)->store;
3819
    }
3818
    }
3820
    my $transferdeleted = DeleteTransfer($itemnumber);
3819
    my $transferdeleted = DeleteTransfer($itemnumber);
3820
3821
    # RevertLostBibLevelHolds
3822
    my $hold = Koha::Holds->find({ itemnumber => $itemnumber, found => { '!=' =>  undef } });
3823
    if ( C4::Context->preference('RevertLostBibLevelHolds') && defined $hold ){
3824
        # syspref is enabled and there is a waiting hold for this item
3825
        if ( $hold->item_level_hold && defined $cancel_reserve ){
3826
            if ( $cancel_reserve ){
3827
                # cancel item-level hold
3828
                $hold->cancel;
3829
            } else { # eq 'revert'
3830
                # revert item-level hold's waiting status
3831
                $hold = C4::Reserves::RevertWaitingStatus({ itemnumber => $itemnumber });
3832
            }
3833
        }
3834
        if ( !$hold->item_level_hold ){
3835
            # revert biblio-level hold's waiting status
3836
            $hold = C4::Reserves::RevertWaitingStatus({ itemnumber => $itemnumber });
3837
        }
3838
    }
3821
}
3839
}
3822
3840
3823
sub GetOfflineOperations {
3841
sub GetOfflineOperations {
(-)a/catalogue/moredetail.pl (+2 lines)
Lines 237-242 foreach my $item (@items){ Link Here
237
        my $curr_borrower = Koha::Patrons->find( $item->{borrowernumber} );
237
        my $curr_borrower = Koha::Patrons->find( $item->{borrowernumber} );
238
        $item->{patron} = $curr_borrower;
238
        $item->{patron} = $curr_borrower;
239
    }
239
    }
240
241
    $item->{waiting_holds} = $item->{object}->holds({ found => 'W', item_level_hold => { '!=' => 0 } })->count;
240
}
242
}
241
243
242
my $mss = Koha::MarcSubfieldStructures->search({ frameworkcode => $fw, kohafield => 'items.itemlost', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
244
my $mss = Koha::MarcSubfieldStructures->search({ frameworkcode => $fw, kohafield => 'items.itemlost', authorised_value => [ -and => {'!=' => undef }, {'!=' => ''}] });
(-)a/catalogue/updateitem.pl (+12 lines)
Lines 40-45 my $itemnotes=$cgi->param('itemnotes'); Link Here
40
my $itemnotes_nonpublic=$cgi->param('itemnotes_nonpublic');
40
my $itemnotes_nonpublic=$cgi->param('itemnotes_nonpublic');
41
my $withdrawn=$cgi->param('withdrawn');
41
my $withdrawn=$cgi->param('withdrawn');
42
my $damaged=$cgi->param('damaged');
42
my $damaged=$cgi->param('damaged');
43
my $cancelhold=$cgi->param('cancelhold');
44
my $reverthold=$cgi->param('reverthold');
45
my $redirecturl=$cgi->param('redirecturl');
46
if ( defined $cancelhold ){
47
    LostItem($itemnumber, 'moredetail', 0, $cancelhold);
48
} elsif ( defined $reverthold ){
49
    $cancelhold = 0;
50
    LostItem($itemnumber, 'moredetail', 0, $cancelhold);
51
}
52
if ( defined $redirecturl ){
53
    print $cgi->redirect( $redirecturl . $biblionumber );
54
}
43
55
44
my $confirm=$cgi->param('confirm');
56
my $confirm=$cgi->param('confirm');
45
my $dbh = C4::Context->dbh;
57
my $dbh = C4::Context->dbh;
(-)a/cataloguing/additem.pl (+12 lines)
Lines 949-954 foreach my $tag ( keys %{$tagslib}){ Link Here
949
}
949
}
950
@loop_data = sort {$a->{subfield} cmp $b->{subfield} } @loop_data;
950
@loop_data = sort {$a->{subfield} cmp $b->{subfield} } @loop_data;
951
951
952
if ( C4::Context->preference('RevertLostBibLevelHolds') ){
953
    my @lostitems = Koha::Items->search({ biblionumber => $biblionumber, itemlost => { '!=' => 0 } });
954
    # find if any of these lost items have waiting holds
955
    my @waitinglostitems;
956
    foreach my $lostitem ( @lostitems ){
957
        if ( $lostitem->holds({ found => 'W', item_level_hold => 1 })->count > 0 ){
958
            push( @waitinglostitems, $lostitem );
959
        }
960
    }
961
    $template->param( waitinglostitems => \@waitinglostitems );
962
}
963
952
my $item = Koha::Items->find($itemnumber); # We certainly want to fetch it earlier
964
my $item = Koha::Items->find($itemnumber); # We certainly want to fetch it earlier
953
965
954
# what's the next op ? it's what we are not in : an add if we're editing, otherwise, and edit.
966
# what's the next op ? it's what we are not in : an add if we're editing, otherwise, and edit.
(-)a/installer/data/mysql/atomicupdate/bug_20844-add_RevertLostBibLevelHolds_syspref.perl (+6 lines)
Line 0 Link Here
1
$DBversion = 'XXX';
2
if( CheckVersion( $DBversion ) ) {
3
    $dbh->do(q{INSERT IGNORE INTO systempreferences (variable,value,options,explanation,type) VALUES ('RevertLostBibLevelHolds', '0', NULL, 'If an item is marked as lost after being allocated for a biblio-level hold, revert the hold from its waiting status', 'YesNo') });
4
5
    NewVersion( $DBversion, 20844, "Add RevertLostBibLevelHolds system preference");
6
}
(-)a/installer/data/mysql/sysprefs.sql (+2 lines)
Lines 542-547 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
542
('ReturnBeforeExpiry','0',NULL,'If ON, checkout will be prevented if returndate is after patron card expiry','YesNo'),
542
('ReturnBeforeExpiry','0',NULL,'If ON, checkout will be prevented if returndate is after patron card expiry','YesNo'),
543
('ReturnLog','1',NULL,'If ON, enables the circulation (returns) log','YesNo'),
543
('ReturnLog','1',NULL,'If ON, enables the circulation (returns) log','YesNo'),
544
('ReturnpathDefault','',NULL,'Use this email address as return path or bounce address for undeliverable emails','Free'),
544
('ReturnpathDefault','',NULL,'Use this email address as return path or bounce address for undeliverable emails','Free'),
545
('RevertLostBibLevelHolds', '0', NULL, 'If an item is marked as lost after being allocated for a biblio-level hold, revert the hold from its waiting status', 'YesNo'),
545
('reviewson','1','','If ON, enables patron reviews of bibliographic records in the OPAC','YesNo'),
546
('reviewson','1','','If ON, enables patron reviews of bibliographic records in the OPAC','YesNo'),
546
('RisExportAdditionalFields',  '', NULL ,  'Define additional RIS tags to export from MARC records in YAML format as an associative array with either a marc tag/subfield combination as the value, or a list of tag/subfield combinations.',  'textarea'),
547
('RisExportAdditionalFields',  '', NULL ,  'Define additional RIS tags to export from MARC records in YAML format as an associative array with either a marc tag/subfield combination as the value, or a list of tag/subfield combinations.',  'textarea'),
547
('RoundFinesAtPayment','0', NULL,'If enabled any fines with fractions of a cent will be rounded to the nearest cent when payments are coll    ected. e.g. 1.004 will be paid off by a 1.00 payment','YesNo'),
548
('RoundFinesAtPayment','0', NULL,'If enabled any fines with fractions of a cent will be rounded to the nearest cent when payments are coll    ected. e.g. 1.004 will be paid off by a 1.00 payment','YesNo'),
Lines 565-570 INSERT INTO systempreferences ( `variable`, `value`, `options`, `explanation`, ` Link Here
565
('SelfCheckReceiptPrompt','1','NULL','If ON, print receipt dialog pops up when self checkout is finished','YesNo'),
566
('SelfCheckReceiptPrompt','1','NULL','If ON, print receipt dialog pops up when self checkout is finished','YesNo'),
566
('SelfCheckTimeout','120','','Define the number of seconds before the Web-based Self Checkout times out a patron','Integer'),
567
('SelfCheckTimeout','120','','Define the number of seconds before the Web-based Self Checkout times out a patron','Integer'),
567
('SendAllEmailsTo','',NULL,'All emails will be redirected to this email if it is not empty','free'),
568
('SendAllEmailsTo','',NULL,'All emails will be redirected to this email if it is not empty','free'),
569
('SendLostHoldNotices', '0', NULL, 'Send a notice to a borrower if their reserved and waiting item is marked as lost', 'YesNo'),
568
('SeparateHoldings','0',NULL,'Separate current branch holdings from other holdings','YesNo'),
570
('SeparateHoldings','0',NULL,'Separate current branch holdings from other holdings','YesNo'),
569
('SeparateHoldingsBranch','homebranch','homebranch|holdingbranch','Branch used to separate holdings','Choice'),
571
('SeparateHoldingsBranch','homebranch','homebranch|holdingbranch','Branch used to separate holdings','Choice'),
570
('SessionRestrictionByIP','1','Check for change in remote IP address for session security. Disable only when remote IP address changes frequently.','','YesNo'),
572
('SessionRestrictionByIP','1','Check for change in remote IP address for session security. Disable only when remote IP address changes frequently.','','YesNo'),
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/circulation.pref (+6 lines)
Lines 597-602 Circulation: Link Here
597
            - the last patron to return an item. This setting is independent of opacreadinghistory/AnonymousPatron.
597
            - the last patron to return an item. This setting is independent of opacreadinghistory/AnonymousPatron.
598
    Holds Policy:
598
    Holds Policy:
599
        -
599
        -
600
            - pref: RevertLostBibLevelHolds
601
              choices:
602
                  yes: Revert
603
                  no: "Don't revert"
604
            - waiting status of a hold if the allocated item is marked as Lost.
605
        -
600
            - In the staff client, split the holds queue into separate tables by
606
            - In the staff client, split the holds queue into separate tables by
601
            - pref: HoldsSplitQueue
607
            - pref: HoldsSplitQueue
602
              choices:
608
              choices:
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/moredetail.tt (+13 lines)
Lines 55-60 Link Here
55
55
56
    [% FOREACH ITEM_DAT IN ITEM_DATA %]
56
    [% FOREACH ITEM_DAT IN ITEM_DATA %]
57
        <h3 id="item[% ITEM_DAT.itemnumber | html %]">Barcode [% ITEM_DAT.barcode | html %]  [% IF ( ITEM_DAT.notforloantext ) %][% ITEM_DAT.notforloantext | html %] [% END %]</h3>
57
        <h3 id="item[% ITEM_DAT.itemnumber | html %]">Barcode [% ITEM_DAT.barcode | html %]  [% IF ( ITEM_DAT.notforloantext ) %][% ITEM_DAT.notforloantext | html %] [% END %]</h3>
58
59
        [% IF ITEM_DAT.itemlost and ITEM_DAT.waiting_holds > 0  %]
60
            <div class="dialog alert">
61
                This item has a waiting item-level hold on it, and has been marked as lost.<br>
62
                <form action="updateitem.pl" method="post" class="inline">
63
                    <input type="hidden" name="itemnumber" value="[% ITEM_DAT.itemnumber %]">
64
                    <input type="hidden" name="biblionumber" value="[% ITEM_DAT.biblionumber %]">
65
                    <button type="submit" name="reverthold" value="1" class="btn btn-default"><i class="fa fa-undo"></i> Revert waiting status</button>
66
                    <button type="submit" name="cancelhold" value="1" class="btn btn-default"><i class="fa fa-times"></i> Cancel hold</button>
67
                </form>
68
            </div>
69
        [% END %]
70
58
        <div class="listgroup"><h4>Item information [% IF ( CAN_user_editcatalogue_edit_catalogue ) %][% UNLESS ( ITEM_DAT.nomod ) %]
71
        <div class="listgroup"><h4>Item information [% IF ( CAN_user_editcatalogue_edit_catalogue ) %][% UNLESS ( ITEM_DAT.nomod ) %]
59
         [% IF ( CAN_user_editcatalogue_edit_items ) %]
72
         [% IF ( CAN_user_editcatalogue_edit_items ) %]
60
            <a href="/cgi-bin/koha/cataloguing/additem.pl?op=edititem&amp;biblionumber=[% ITEM_DAT.biblionumber | uri %]&amp;itemnumber=[% ITEM_DAT.itemnumber | uri %]"><i class="fa fa-pencil"></i> Edit item</a>
73
            <a href="/cgi-bin/koha/cataloguing/additem.pl?op=edititem&amp;biblionumber=[% ITEM_DAT.biblionumber | uri %]&amp;itemnumber=[% ITEM_DAT.itemnumber | uri %]"><i class="fa fa-pencil"></i> Edit item</a>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/cataloguing/additem.tt (+19 lines)
Lines 42-47 Link Here
42
[% IF ( not_same_branch ) %]<div class="dialog alert"><strong>Cannot delete</strong>: The items do not belong to your library.</div>[% END %]
42
[% IF ( not_same_branch ) %]<div class="dialog alert"><strong>Cannot delete</strong>: The items do not belong to your library.</div>[% END %]
43
[% IF ( linked_analytics ) %]<div class="dialog alert"><strong>Cannot delete</strong>: item has linked <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblionumber | uri %]&amp;analyze=1">analytics.</a>.</div>[% END %]
43
[% IF ( linked_analytics ) %]<div class="dialog alert"><strong>Cannot delete</strong>: item has linked <a href="/cgi-bin/koha/catalogue/detail.pl?biblionumber=[% biblionumber | uri %]&amp;analyze=1">analytics.</a>.</div>[% END %]
44
44
45
[% IF waitinglostitems %]
46
    <div class="alert">
47
        The following item(s) have a waiting item-level hold and have been marked as lost.
48
        <ul>
49
        [% FOREACH i IN waitinglostitems %]
50
            <br>
51
            <li>Item (<i>[% i.barcode %]</i>)
52
            <form action="../catalogue/updateitem.pl" method="post" class="inline">
53
                <input type="hidden" name="itemnumber" value="[% i.itemnumber %]">
54
                <input type="hidden" name="biblionumber" value="[% i.biblionumber %]">
55
                <input type="hidden" name="redirecturl" value="../cataloguing/additem.pl?biblionumber=">
56
                <button type="submit" name="reverthold" value="1" class="btn btn-default"><i class="fa fa-undo"></i> Revert waiting status</button>
57
                <button type="submit" name="cancelhold" value="1" class="btn btn-default"><i class="fa fa-times"></i> Cancel hold</button></li>
58
            </form>
59
        [% END %]
60
        </ul>
61
    </div>
62
[% END %]
63
45
<div id="cataloguing_additem_itemlist">
64
<div id="cataloguing_additem_itemlist">
46
    [% IF ( item_loop ) %]
65
    [% IF ( item_loop ) %]
47
        <div>
66
        <div>
(-)a/t/db_dependent/Reserves.t (-2 / +123 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 62;
20
use Test::More tests => 63;
21
use Test::MockModule;
21
use Test::MockModule;
22
use Test::Warn;
22
use Test::Warn;
23
23
Lines 1035-1040 subtest 'MoveReserve additional test' => sub { Link Here
1035
1035
1036
};
1036
};
1037
1037
1038
subtest 'Waiting item is marked as lost' => sub {
1039
1040
    plan tests => 15;
1041
1042
    # Set up data
1043
    my $biblio = $builder->build_sample_biblio();
1044
    my $item = $builder->build_sample_item({ biblionumber => $biblio->biblionumber });
1045
    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
1046
1047
    ## TEST 1: BIBLIO-LEVEL HOLD
1048
1049
    # place biblio-level hold
1050
    my $reserve_id = AddReserve({
1051
        branchcode => $item->homebranch,
1052
        borrowernumber => $patron->borrowernumber,
1053
        biblionumber => $biblio->biblionumber,
1054
    });
1055
    my $hold = Koha::Holds->find( $reserve_id );
1056
1057
    is( $hold->item_level_hold, 0, 'Biblio-level hold placed' );
1058
1059
    # set hold as waiting and assign item
1060
    $hold->set_waiting;
1061
    $hold->set({ itemnumber => $item->itemnumber, priority => 0 })->store;
1062
1063
    # mark item in biblio as lost
1064
    $item->itemlost( 1 )->store;
1065
    is( $item->itemlost, 1, 'Item assigned to waiting hold has been marked lost');
1066
1067
    # do test
1068
    t::lib::Mocks::mock_preference( 'RevertLostBibLevelHolds', 0 );
1069
    C4::Circulation::LostItem( $item->itemnumber, 'test', 0, 0 );
1070
    is( $hold->found, 'W', 'Hold is still waiting even though the item is lost because RevertLostBibLevelHolds is disabled' );
1071
1072
    # enable preference
1073
    t::lib::Mocks::mock_preference( 'RevertLostBibLevelHolds', 1 );
1074
1075
    # try again
1076
    is( $item->itemlost, 1, 'Item assigned to waiting hold has been marked lost');
1077
    C4::Circulation::LostItem( $item->itemnumber, 'test', 0, 0 );
1078
    $hold = Koha::Holds->find( $reserve_id );
1079
    is( $hold->found, undef, 'Hold waiting status has been reverted because RevertLostBibLevelHolds is enabled' );
1080
1081
    # clean up
1082
    $hold->cancel;
1083
    $item->itemlost( 0 );
1084
1085
    ## TEST 2: ITEM-LEVEL HOLD, REVERT
1086
1087
    # place item-level hold
1088
    $reserve_id = AddReserve({
1089
        branchcode => $item->homebranch,
1090
        borrowernumber => $patron->borrowernumber,
1091
        biblionumber => $biblio->biblionumber,
1092
        itemnumber => $item->itemnumber
1093
    });
1094
    $hold = Koha::Holds->find( $reserve_id );
1095
1096
    is( $hold->item_level_hold, 1, 'Item-level hold placed' );
1097
1098
    # set hold as waiting and assign item
1099
    $hold->set_waiting;
1100
    $hold->set({ itemnumber => $item->itemnumber, priority => 0 })->store;
1101
1102
    # mark item in biblio as lost
1103
    $item->itemlost( 1 );
1104
    is( $item->itemlost, 1, 'Item assigned to waiting hold has been marked lost');
1105
1106
    # do test
1107
    t::lib::Mocks::mock_preference( 'RevertLostBibLevelHolds', 0 );
1108
    C4::Circulation::LostItem( $item->itemnumber, 'test', 0, 0 );
1109
    is( $hold->found, 'W', 'Hold is still waiting even though the item is lost because RevertLostBibLevelHolds is disabled' );
1110
1111
    # enable preference
1112
    t::lib::Mocks::mock_preference( 'RevertLostBibLevelHolds', 1 );
1113
1114
    # try again
1115
    is( $item->itemlost, 1, 'Item assigned to waiting hold has been marked lost');
1116
    C4::Circulation::LostItem( $item->itemnumber, 'test', 0, 0 );
1117
    $hold = Koha::Holds->find( $reserve_id );
1118
    is( $hold->found, undef, 'Hold waiting status has been reverted because RevertLostBibLevelHolds is enabled, and we chose not to cancel' );
1119
1120
    # clean up
1121
    $hold->cancel;
1122
    $item->itemlost( 0 );
1123
1124
    # TEST 3: ITEM-LEVEL HOLD, CANCEL
1125
1126
    # place item-level hold
1127
    $reserve_id = AddReserve({
1128
        branchcode => $item->homebranch,
1129
        borrowernumber => $patron->borrowernumber,
1130
        biblionumber => $biblio->biblionumber,
1131
        itemnumber => $item->itemnumber
1132
    });
1133
    $hold = Koha::Holds->find( $reserve_id );
1134
1135
    is( $hold->item_level_hold, 1, 'Item-level hold placed' );
1136
1137
    # set hold as waiting and assign item
1138
    $hold->set_waiting;
1139
    $hold->set({ itemnumber => $item->itemnumber, priority => 0 })->store;
1140
1141
    # mark item in biblio as lost
1142
    $item->itemlost( 1 );
1143
    is( $item->itemlost, 1, 'Item assigned to waiting hold has been marked lost');
1144
1145
    # do test
1146
    t::lib::Mocks::mock_preference( 'RevertLostBibLevelHolds', 0 );
1147
    C4::Circulation::LostItem( $item->itemnumber, 'test', 0, 1 );
1148
    is( $hold->found, 'W', 'Hold is still waiting even though the item is lost because RevertLostBibLevelHolds is disabled' );
1149
1150
    # enable preference
1151
    t::lib::Mocks::mock_preference( 'RevertLostBibLevelHolds', 1 );
1152
1153
    # try again
1154
    is( $item->itemlost, 1, 'Item assigned to waiting hold has been marked lost');
1155
    C4::Circulation::LostItem( $item->itemnumber, 'test', 0, 1 );
1156
    $hold = Koha::Holds->find( $reserve_id );
1157
    is( Koha::Holds->find( $reserve_id ), undef, 'Hold has been cancelled with RevertLostBibLevelHolds enabled' );
1158
};
1159
1038
sub count_hold_print_messages {
1160
sub count_hold_print_messages {
1039
    my $message_count = $dbh->selectall_arrayref(q{
1161
    my $message_count = $dbh->selectall_arrayref(q{
1040
        SELECT COUNT(*)
1162
        SELECT COUNT(*)
1041
- 

Return to bug 20844