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

(-)a/Koha/Biblio.pm (-12 / +12 lines)
Lines 1977-1985 sub recalls { Link Here
1977
1977
1978
=head3 can_be_recalled
1978
=head3 can_be_recalled
1979
1979
1980
    my @items_for_recall = $biblio->can_be_recalled({ patron => $patron_object });
1980
    my $recall_status = $biblio->can_be_recalled({ patron => $patron_object });
1981
1981
1982
Does biblio-level checks and returns the items attached to this biblio that are available for recall
1982
Does biblio-level checks and returns a success or error message.
1983
1983
1984
if hold_convert $param is included, this is to say that this a check to convert a hold to a recall, so we should not check for an existing hold.
1984
if hold_convert $param is included, this is to say that this a check to convert a hold to a recall, so we should not check for an existing hold.
1985
1985
Lines 1988-1994 if hold_convert $param is included, this is to say that this a check to convert Link Here
1988
sub can_be_recalled {
1988
sub can_be_recalled {
1989
    my ( $self, $params ) = @_;
1989
    my ( $self, $params ) = @_;
1990
1990
1991
    return 0 if ( C4::Context->preference('UseRecalls') eq "off" );
1991
    return ( 0, 'recalls_disabled' ) if ( C4::Context->preference('UseRecalls') eq "off" );
1992
1992
1993
    my $patron = $params->{patron};
1993
    my $patron = $params->{patron};
1994
1994
Lines 2000-2006 sub can_be_recalled { Link Here
2000
    my @all_items = Koha::Items->search({ biblionumber => $self->biblionumber })->as_list;
2000
    my @all_items = Koha::Items->search({ biblionumber => $self->biblionumber })->as_list;
2001
2001
2002
    # if there are no available items at all, no recall can be placed
2002
    # if there are no available items at all, no recall can be placed
2003
    return 0 if ( scalar @all_items == 0 );
2003
    return ( 0, 'no_available_items' ) if ( scalar @all_items == 0 );
2004
2004
2005
    my @itemtypes;
2005
    my @itemtypes;
2006
    my @itemnumbers;
2006
    my @itemnumbers;
Lines 2016-2022 sub can_be_recalled { Link Here
2016
    }
2016
    }
2017
2017
2018
    # if there are no recallable items, no recall can be placed
2018
    # if there are no recallable items, no recall can be placed
2019
    return 0 if ( scalar @items == 0 );
2019
    return ( 0, 'no_available_items' ) if ( scalar @items == 0 );
2020
2020
2021
    # Check the circulation rule for each relevant itemtype for this biblio
2021
    # Check the circulation rule for each relevant itemtype for this biblio
2022
    my ( @recalls_allowed, @recalls_per_record, @on_shelf_recalls );
2022
    my ( @recalls_allowed, @recalls_per_record, @on_shelf_recalls );
Lines 2044-2060 sub can_be_recalled { Link Here
2044
    my $on_shelf_recalls = (sort {$on_shelf_recalls_count{$b} <=> $on_shelf_recalls_count{$a}} @on_shelf_recalls)[0]; # take most common
2044
    my $on_shelf_recalls = (sort {$on_shelf_recalls_count{$b} <=> $on_shelf_recalls_count{$a}} @on_shelf_recalls)[0]; # take most common
2045
2045
2046
    # check recalls allowed has been set and is not zero
2046
    # check recalls allowed has been set and is not zero
2047
    return 0 if ( !defined($recalls_allowed) || $recalls_allowed == 0 );
2047
    return ( 0, 'not_allowed' ) if ( !defined($recalls_allowed) || $recalls_allowed == 0 );
2048
2048
2049
    if ( $patron ) {
2049
    if ( $patron ) {
2050
        # check borrower has not reached open recalls allowed limit
2050
        # check borrower has not reached open recalls allowed limit
2051
        return 0 if ( $patron->recalls->filter_by_current->count >= $recalls_allowed );
2051
        return ( 0, 'reached_max_total_recalls' ) if ( $patron->recalls->filter_by_current->count >= $recalls_allowed );
2052
2052
2053
        # check borrower has not reached open recalls allowed per record limit
2053
        # check borrower has not reached open recalls allowed per record limit
2054
        return 0 if ( $patron->recalls->filter_by_current->search({ biblio_id => $self->biblionumber })->count >= $recalls_per_record );
2054
        return ( 0, 'reached_max_record_recalls' ) if ( $patron->recalls->filter_by_current->search({ biblio_id => $self->biblionumber })->count >= $recalls_per_record );
2055
2055
2056
        # check if any of the items under this biblio are already checked out by this borrower
2056
        # check if any of the items under this biblio are already checked out by this borrower
2057
        return 0 if ( Koha::Checkouts->search({ itemnumber => [ @all_itemnumbers ], borrowernumber => $patron->borrowernumber })->count > 0 );
2057
        return ( 0, 'patron_checkouts' ) if ( Koha::Checkouts->search({ itemnumber => [ @all_itemnumbers ], borrowernumber => $patron->borrowernumber })->count > 0 );
2058
    }
2058
    }
2059
2059
2060
    # check item availability
2060
    # check item availability
Lines 2064-2076 sub can_be_recalled { Link Here
2064
    }
2064
    }
2065
2065
2066
    # can't recall if on shelf recalls only allowed when all unavailable, but items are still available for checkout
2066
    # can't recall if on shelf recalls only allowed when all unavailable, but items are still available for checkout
2067
    return 0 if ( $on_shelf_recalls eq 'all' && $checked_out_count < scalar @items );
2067
    return ( 0, 'on_shelf_not_allowed' ) if ( $on_shelf_recalls eq 'all' && $checked_out_count < scalar @items );
2068
2068
2069
    # can't recall if no items have been checked out
2069
    # can't recall if no items have been checked out
2070
    return 0 if ( $checked_out_count == 0 );
2070
    return ( 0, 'no_checkouts' ) if ( $checked_out_count == 0 );
2071
2071
2072
    # can recall
2072
    # can recall
2073
    return @items;
2073
    return ( 1, 'OK' );
2074
}
2074
}
2075
2075
2076
=head3 ratings
2076
=head3 ratings
(-)a/Koha/Item.pm (-24 / +24 lines)
Lines 2265-2273 sub recall { Link Here
2265
2265
2266
=head3 can_be_recalled
2266
=head3 can_be_recalled
2267
2267
2268
    if ( $item->can_be_recalled({ patron => $patron_object }) ) # do recall
2268
    if ( $item->can_be_recalled({ patron => $patron_object }) eq 'OK' ) # do recall
2269
2269
2270
Does item-level checks and returns if items can be recalled by this borrower
2270
Does item-level checks and returns an 'OK' message if item can be recalled by this borrower, otherwise returns an error reason.
2271
2271
2272
if hold_convert $param is included, this is to say that this a check to convert a hold to a recall, so we should not check for an existing hold.
2272
if hold_convert $param is included, this is to say that this a check to convert a hold to a recall, so we should not check for an existing hold.
2273
2273
Lines 2276-2290 if hold_convert $param is included, this is to say that this a check to convert Link Here
2276
sub can_be_recalled {
2276
sub can_be_recalled {
2277
    my ( $self, $params ) = @_;
2277
    my ( $self, $params ) = @_;
2278
2278
2279
    return 0 if ( C4::Context->preference('UseRecalls') eq "off" );
2279
    return ( 0, 'recalls_disabled' ) if ( C4::Context->preference('UseRecalls') eq "off" );
2280
2280
2281
    # check if this item is not for loan, withdrawn or lost
2281
    # check if this item is not for loan, withdrawn or lost
2282
    return 0 if ( $self->notforloan != 0 );
2282
    return ( 0, 'item_unavailable' ) if ( $self->notforloan != 0 );
2283
    return 0 if ( $self->itemlost != 0 );
2283
    return ( 0, 'item_unavailable' ) if ( $self->itemlost != 0 );
2284
    return 0 if ( $self->withdrawn != 0 );
2284
    return ( 0, 'item_unavailable' ) if ( $self->withdrawn != 0 );
2285
2285
2286
    # check if this item is not checked out - if not checked out, can't be recalled
2286
    # check if this item is not checked out - if not checked out, can't be recalled
2287
    return 0 if ( !defined( $self->checkout ) );
2287
    return ( 0, 'no_checkouts' ) if ( !defined( $self->checkout ) );
2288
2288
2289
    my $patron = $params->{patron};
2289
    my $patron = $params->{patron};
2290
2290
Lines 2306-2329 sub can_be_recalled { Link Here
2306
    });
2306
    });
2307
2307
2308
    # check recalls allowed has been set and is not zero
2308
    # check recalls allowed has been set and is not zero
2309
    return 0 if ( !defined($rule->{recalls_allowed}) || $rule->{recalls_allowed} == 0 );
2309
    return ( 0, 'not_allowed' ) if ( !defined($rule->{recalls_allowed}) || $rule->{recalls_allowed} == 0 );
2310
2310
2311
    if ( $patron ) {
2311
    if ( $patron ) {
2312
        # check borrower has not reached open recalls allowed limit
2312
        # check borrower has not reached open recalls allowed limit
2313
        return 0 if ( $patron->recalls->filter_by_current->count >= $rule->{recalls_allowed} );
2313
        return ( 0, 'reached_max_total_recalls' ) if ( $patron->recalls->filter_by_current->count >= $rule->{recalls_allowed} );
2314
2314
2315
        # check borrower has not reach open recalls allowed per record limit
2315
        # check borrower has not reach open recalls allowed per record limit
2316
        return 0 if ( $patron->recalls->filter_by_current->search({ biblio_id => $self->biblionumber })->count >= $rule->{recalls_per_record} );
2316
        return ( 0, 'reached_max_record_recalls' ) if ( $patron->recalls->filter_by_current->search({ biblio_id => $self->biblionumber })->count >= $rule->{recalls_per_record} );
2317
2317
2318
        # check if this patron has already recalled this item
2318
        # check if this patron has already recalled this item
2319
        return 0 if ( Koha::Recalls->search({ item_id => $self->itemnumber, patron_id => $patron->borrowernumber })->filter_by_current->count > 0 );
2319
        return ( 0, 'patron_recalled' ) if ( Koha::Recalls->search({ item_id => $self->itemnumber, patron_id => $patron->borrowernumber })->filter_by_current->count > 0 );
2320
2320
2321
        # check if this patron has already checked out this item
2321
        # check if this patron has already checked out this item
2322
        return 0 if ( Koha::Checkouts->search({ itemnumber => $self->itemnumber, borrowernumber => $patron->borrowernumber })->count > 0 );
2322
        return ( 0, 'patron_checkouts' ) if ( Koha::Checkouts->search({ itemnumber => $self->itemnumber, borrowernumber => $patron->borrowernumber })->count > 0 );
2323
2323
2324
        # check if this patron has already reserved this item
2324
        # check if this patron has already reserved this item
2325
        unless ( $params->{hold_convert} ) {
2325
        unless ( $params->{hold_convert} ) {
2326
            return 0 if ( Koha::Holds->search({ itemnumber => $self->itemnumber, borrowernumber => $patron->borrowernumber })->count > 0 );
2326
            return ( 0, 'patron_host' ) if ( Koha::Holds->search({ itemnumber => $self->itemnumber, borrowernumber => $patron->borrowernumber })->count > 0 );
2327
        }
2327
        }
2328
    }
2328
    }
2329
2329
Lines 2332-2338 sub can_be_recalled { Link Here
2332
    my @items = Koha::Items->search({ biblionumber => $self->biblionumber, itemlost => 0, withdrawn => 0, notforloan => 0 })->as_list;
2332
    my @items = Koha::Items->search({ biblionumber => $self->biblionumber, itemlost => 0, withdrawn => 0, notforloan => 0 })->as_list;
2333
2333
2334
    # if there are no available items at all, no recall can be placed
2334
    # if there are no available items at all, no recall can be placed
2335
    return 0 if ( scalar @items == 0 );
2335
    return ( 0, 'no_available_items' ) if ( scalar @items == 0 );
2336
2336
2337
    my $checked_out_count = 0;
2337
    my $checked_out_count = 0;
2338
    foreach (@items) {
2338
    foreach (@items) {
Lines 2340-2357 sub can_be_recalled { Link Here
2340
    }
2340
    }
2341
2341
2342
    # can't recall if on shelf recalls only allowed when all unavailable, but items are still available for checkout
2342
    # can't recall if on shelf recalls only allowed when all unavailable, but items are still available for checkout
2343
    return 0 if ( $rule->{on_shelf_recalls} eq 'all' && $checked_out_count < scalar @items );
2343
    return ( 0, 'on_shelf_not_allowed' ) if ( $rule->{on_shelf_recalls} eq 'all' && $checked_out_count < scalar @items );
2344
2344
2345
    # can't recall if no items have been checked out
2345
    # can't recall if no items have been checked out
2346
    return 0 if ( $checked_out_count == 0 );
2346
    return ( 0, 'no_checkouts' ) if ( $checked_out_count == 0 );
2347
2347
2348
    # can recall
2348
    # can recall
2349
    return 1;
2349
    return ( 1, 'OK' );
2350
}
2350
}
2351
2351
2352
=head3 can_be_waiting_recall
2352
=head3 can_be_waiting_recall
2353
2353
2354
    if ( $item->can_be_waiting_recall ) { # allocate item as waiting for recall
2354
    if ( $item->can_be_waiting_recall eq 'OK' ) { # allocate item as waiting for recall
2355
2355
2356
Checks item type and branch of circ rules to return whether this item can be used to fill a recall.
2356
Checks item type and branch of circ rules to return whether this item can be used to fill a recall.
2357
At this point the item has already been recalled. We are now at the checkin and set waiting stage.
2357
At this point the item has already been recalled. We are now at the checkin and set waiting stage.
Lines 2361-2372 At this point the item has already been recalled. We are now at the checkin and Link Here
2361
sub can_be_waiting_recall {
2361
sub can_be_waiting_recall {
2362
    my ( $self ) = @_;
2362
    my ( $self ) = @_;
2363
2363
2364
    return 0 if ( C4::Context->preference('UseRecalls') eq "off" );
2364
    return ( 0, 'recalls_disabled' ) if ( C4::Context->preference('UseRecalls') eq "off" );
2365
2365
2366
    # check if this item is not for loan, withdrawn or lost
2366
    # check if this item is not for loan, withdrawn or lost
2367
    return 0 if ( $self->notforloan != 0 );
2367
    return ( 0, 'item_unavailable' ) if ( $self->notforloan != 0 );
2368
    return 0 if ( $self->itemlost != 0 );
2368
    return ( 0, 'item_unavailable' ) if ( $self->itemlost != 0 );
2369
    return 0 if ( $self->withdrawn != 0 );
2369
    return ( 0, 'item_unavailable' ) if ( $self->withdrawn != 0 );
2370
2370
2371
    my $branchcode = $self->holdingbranch;
2371
    my $branchcode = $self->holdingbranch;
2372
    if ( C4::Context->preference('CircControl') eq 'PickupLibrary' and C4::Context->userenv and C4::Context->userenv->{'branch'} ) {
2372
    if ( C4::Context->preference('CircControl') eq 'PickupLibrary' and C4::Context->userenv and C4::Context->userenv->{'branch'} ) {
Lines 2387-2396 sub can_be_waiting_recall { Link Here
2387
    );
2387
    );
2388
2388
2389
    # check recalls allowed has been set and is not zero
2389
    # check recalls allowed has been set and is not zero
2390
    return 0 if ( !defined($rule->{recalls_allowed}) || $rule->{recalls_allowed} == 0 );
2390
    return ( 0, 'not_allowed' ) if ( !defined($rule->{recalls_allowed}) || $rule->{recalls_allowed} == 0 );
2391
2391
2392
    # can recall
2392
    # can recall
2393
    return 1;
2393
    return ( 1, 'OK' );
2394
}
2394
}
2395
2395
2396
=head3 check_recalls
2396
=head3 check_recalls
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/recalls/request.tt (-4 / +3 lines)
Lines 53-65 Link Here
53
    [% IF patron %]
53
    [% IF patron %]
54
54
55
        [% IF error %]
55
        [% IF error %]
56
            <div class="dialog alert">
56
            <div class="alert alert-warning">
57
                Unable to place a recall. Check your circulation rules.
57
                <strong>Cannot place recall:</strong> check your circulation rules.
58
            </div>
58
            </div>
59
        [% END %]
59
        [% END %]
60
60
61
        [% IF patron_holds_count %]
61
        [% IF patron_holds_count %]
62
            <div class="dialog alert alert-info">
62
            <div class="alert alert-info">
63
                Patron has placed one or more record-level holds. <a href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% biblio.biblionumber | uri %]">Convert a hold to a recall</a>.
63
                Patron has placed one or more record-level holds. <a href="/cgi-bin/koha/reserve/request.pl?biblionumber=[% biblio.biblionumber | uri %]">Convert a hold to a recall</a>.
64
            </div>
64
            </div>
65
        [% END %]
65
        [% END %]
66
- 

Return to bug 31391