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

(-)a/C4/Circulation.pm (-73 / +76 lines)
Lines 65-71 use Koha::Plugins; Link Here
65
use Koha::Recalls;
65
use Koha::Recalls;
66
use Carp qw( carp );
66
use Carp qw( carp );
67
use List::MoreUtils qw( any );
67
use List::MoreUtils qw( any );
68
use Scalar::Util qw( looks_like_number );
68
use Scalar::Util qw( looks_like_number blessed );
69
use Date::Calc qw( Date_to_Days );
69
use Date::Calc qw( Date_to_Days );
70
our (@ISA, @EXPORT_OK);
70
our (@ISA, @EXPORT_OK);
71
BEGIN {
71
BEGIN {
Lines 369-375 sub transferbook { Link Here
369
    }
369
    }
370
370
371
    # check if it is still issued to someone, return it...
371
    # check if it is still issued to someone, return it...
372
    my $issue = Koha::Checkouts->find({ itemnumber => $itemnumber });
372
    my $issue = $item->checkout;
373
    if ( $issue ) {
373
    if ( $issue ) {
374
        AddReturn( $barcode, $fbr );
374
        AddReturn( $barcode, $fbr );
375
        $messages->{'WasReturned'} = $issue->borrowernumber;
375
        $messages->{'WasReturned'} = $issue->borrowernumber;
Lines 378-384 sub transferbook { Link Here
378
    # find reserves.....
378
    # find reserves.....
379
    # That'll save a database query.
379
    # That'll save a database query.
380
    my ( $resfound, $resrec, undef ) =
380
    my ( $resfound, $resrec, undef ) =
381
      CheckReserves( $itemnumber );
381
      CheckReserves( $item );
382
    if ( $resfound ) {
382
    if ( $resfound ) {
383
        $resrec->{'ResFound'} = $resfound;
383
        $resrec->{'ResFound'} = $resfound;
384
        $messages->{'ResFound'} = $resrec;
384
        $messages->{'ResFound'} = $resrec;
Lines 958-967 sub CanBookBeIssued { Link Here
958
                and C4::Context->preference('SwitchOnSiteCheckouts') ) {
958
                and C4::Context->preference('SwitchOnSiteCheckouts') ) {
959
            $messages{ONSITE_CHECKOUT_WILL_BE_SWITCHED} = 1;
959
            $messages{ONSITE_CHECKOUT_WILL_BE_SWITCHED} = 1;
960
        } else {
960
        } else {
961
            my ($CanBookBeRenewed,$renewerror) = CanBookBeRenewed(
961
            my ($CanBookBeRenewed,$renewerror) = CanBookBeRenewed($patron, $issue);
962
                $patron->borrowernumber,
963
                $item_object->itemnumber,
964
            );
965
            if ( $CanBookBeRenewed == 0 ) {    # no more renewals allowed
962
            if ( $CanBookBeRenewed == 0 ) {    # no more renewals allowed
966
                if ( $renewerror eq 'onsite_checkout' ) {
963
                if ( $renewerror eq 'onsite_checkout' ) {
967
                    $issuingimpossible{NO_RENEWAL_FOR_ONSITE_CHECKOUTS} = 1;
964
                    $issuingimpossible{NO_RENEWAL_FOR_ONSITE_CHECKOUTS} = 1;
Lines 983-1000 sub CanBookBeIssued { Link Here
983
980
984
        my ( $can_be_returned, $message ) = CanBookBeReturned( $item_unblessed, C4::Context->userenv->{branch} );
981
        my ( $can_be_returned, $message ) = CanBookBeReturned( $item_unblessed, C4::Context->userenv->{branch} );
985
982
986
        unless ( $can_be_returned ) {
983
        if ( !$can_be_returned ) {
987
            $issuingimpossible{RETURN_IMPOSSIBLE} = 1;
984
            $issuingimpossible{RETURN_IMPOSSIBLE} = 1;
988
            $issuingimpossible{branch_to_return} = $message;
985
            $issuingimpossible{branch_to_return} = $message;
989
        } else {
986
        } else {
990
            if ( C4::Context->preference('AutoReturnCheckedOutItems') ) {
987
            if ( C4::Context->preference('AutoReturnCheckedOutItems') ) {
991
                $alerts{RETURNED_FROM_ANOTHER} = { patron => $patron };
988
                $alerts{RETURNED_FROM_ANOTHER} = { patron => $patron };
992
            } else {
989
            }
993
            $needsconfirmation{ISSUED_TO_ANOTHER} = 1;
990
            else {
994
            $needsconfirmation{issued_firstname} = $patron->firstname;
991
                $needsconfirmation{ISSUED_TO_ANOTHER} = 1;
995
            $needsconfirmation{issued_surname} = $patron->surname;
992
                $needsconfirmation{issued_firstname} = $patron->firstname;
996
            $needsconfirmation{issued_cardnumber} = $patron->cardnumber;
993
                $needsconfirmation{issued_surname} = $patron->surname;
997
            $needsconfirmation{issued_borrowernumber} = $patron->borrowernumber;
994
                $needsconfirmation{issued_cardnumber} = $patron->cardnumber;
995
                $needsconfirmation{issued_borrowernumber} = $patron->borrowernumber;
998
            }
996
            }
999
        }
997
        }
1000
    }
998
    }
Lines 1027-1035 sub CanBookBeIssued { Link Here
1027
    # CHECKPREVCHECKOUT: CHECK IF ITEM HAS EVER BEEN LENT TO PATRON
1025
    # CHECKPREVCHECKOUT: CHECK IF ITEM HAS EVER BEEN LENT TO PATRON
1028
    #
1026
    #
1029
    $patron = Koha::Patrons->find( $patron->borrowernumber ); # FIXME Refetch just in case, to avoid regressions. But must not be needed
1027
    $patron = Koha::Patrons->find( $patron->borrowernumber ); # FIXME Refetch just in case, to avoid regressions. But must not be needed
1030
    my $wants_check = $patron->wants_check_for_previous_checkout;
1028
    if ( $patron->wants_check_for_previous_checkout && $patron->do_check_for_previous_checkout($item_unblessed) ) {
1031
    $needsconfirmation{PREVISSUE} = 1
1029
        $needsconfirmation{PREVISSUE} = 1;
1032
        if ($wants_check and $patron->do_check_for_previous_checkout($item_unblessed));
1030
    }
1033
1031
1034
    #
1032
    #
1035
    # ITEM CHECKING
1033
    # ITEM CHECKING
Lines 1167-1173 sub CanBookBeIssued { Link Here
1167
1165
1168
    unless ( $ignore_reserves and defined $recall ) {
1166
    unless ( $ignore_reserves and defined $recall ) {
1169
        # See if the item is on reserve.
1167
        # See if the item is on reserve.
1170
        my ( $restype, $res ) = C4::Reserves::CheckReserves( $item_object->itemnumber );
1168
        my ( $restype, $res ) = CheckReserves( $item_object );
1171
        if ($restype) {
1169
        if ($restype) {
1172
            my $resbor = $res->{'borrowernumber'};
1170
            my $resbor = $res->{'borrowernumber'};
1173
            if ( $resbor ne $patron->borrowernumber ) {
1171
            if ( $resbor ne $patron->borrowernumber ) {
Lines 2384-2390 sub AddReturn { Link Here
2384
    # launch the Checkreserves routine to find any holds
2382
    # launch the Checkreserves routine to find any holds
2385
    my ($resfound, $resrec);
2383
    my ($resfound, $resrec);
2386
    my $lookahead= C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2384
    my $lookahead= C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2387
    ($resfound, $resrec, undef) = C4::Reserves::CheckReserves( $item->itemnumber, undef, $lookahead ) unless ( $item->withdrawn );
2385
    ($resfound, $resrec, undef) = CheckReserves( $item, $lookahead ) unless ( $item->withdrawn );
2388
    # if a hold is found and is waiting at another branch, change the priority back to 1 and trigger the hold (this will trigger a transfer and update the hold status properly)
2386
    # if a hold is found and is waiting at another branch, change the priority back to 1 and trigger the hold (this will trigger a transfer and update the hold status properly)
2389
    if ( $resfound and $resfound eq "Waiting" and $branch ne $resrec->{branchcode} ) {
2387
    if ( $resfound and $resfound eq "Waiting" and $branch ne $resrec->{branchcode} ) {
2390
        my $hold = C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
2388
        my $hold = C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
Lines 2880-2893 sub GetUpcomingDueIssues { Link Here
2880
2878
2881
=head2 CanBookBeRenewed
2879
=head2 CanBookBeRenewed
2882
2880
2883
  ($ok,$error,$info) = &CanBookBeRenewed($borrowernumber, $itemnumber[, $override_limit]);
2881
  ($ok,$error,$info) = &CanBookBeRenewed($patron, $issue, $override_limit);
2884
2882
2885
Find out whether a borrowed item may be renewed.
2883
Find out whether a borrowed item may be renewed.
2886
2884
2887
C<$borrowernumber> is the borrower number of the patron who currently
2885
C<$patron> is the patron who currently has the issue.
2888
has the item on loan.
2889
2886
2890
C<$itemnumber> is the number of the item to renew.
2887
C<$issue> is the checkout to renew.
2891
2888
2892
C<$override_limit>, if supplied with a true value, causes
2889
C<$override_limit>, if supplied with a true value, causes
2893
the limit on the number of times that the loan can be renewed
2890
the limit on the number of times that the loan can be renewed
Lines 2906-2924 already renewed the loan. Link Here
2906
=cut
2903
=cut
2907
2904
2908
sub CanBookBeRenewed {
2905
sub CanBookBeRenewed {
2909
    my ( $borrowernumber, $itemnumber, $override_limit, $cron ) = @_;
2906
    my ( $patron, $issue, $override_limit, $cron ) = @_;
2910
2907
2911
    my $auto_renew = "no";
2908
    my $auto_renew = "no";
2912
    my $soonest;
2909
    my $soonest;
2910
    my $item = $issue->item;
2913
2911
2914
    my $item      = Koha::Items->find($itemnumber)      or return ( 0, 'no_item' );
2912
    return ( 0, 'no_item' ) unless $item;
2915
    my $issue = $item->checkout or return ( 0, 'no_checkout' );
2913
    return ( 0, 'no_checkout' ) unless $issue;
2916
    return ( 0, 'onsite_checkout' ) if $issue->onsite_checkout;
2914
    return ( 0, 'onsite_checkout' ) if $issue->onsite_checkout;
2915
    return ( 0, 'item_issued_to_other_patron') if $issue->borrowernumber != $patron->borrowernumber;
2917
    return ( 0, 'item_denied_renewal') if $item->is_denied_renewal;
2916
    return ( 0, 'item_denied_renewal') if $item->is_denied_renewal;
2918
2917
2919
    my $patron = $issue->patron or return;
2918
       # override_limit will override anything else except on_reserve
2920
2921
    # override_limit will override anything else except on_reserve
2922
    unless ( $override_limit ){
2919
    unless ( $override_limit ){
2923
        my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
2920
        my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
2924
        my $issuing_rule = Koha::CirculationRules->get_effective_rules(
2921
        my $issuing_rule = Koha::CirculationRules->get_effective_rules(
Lines 2944-2950 sub CanBookBeRenewed { Link Here
2944
2941
2945
        my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing');
2942
        my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing');
2946
        my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
2943
        my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
2947
        $patron         = Koha::Patrons->find($borrowernumber); # FIXME Is this really useful?
2948
        my $restricted  = $patron->is_debarred;
2944
        my $restricted  = $patron->is_debarred;
2949
        my $hasoverdues = $patron->has_overdues;
2945
        my $hasoverdues = $patron->has_overdues;
2950
2946
Lines 2992-3000 sub CanBookBeRenewed { Link Here
2992
            non_priority => 0,
2988
            non_priority => 0,
2993
            found        => undef,
2989
            found        => undef,
2994
            reservedate  => { '<=' => \'NOW()' },
2990
            reservedate  => { '<=' => \'NOW()' },
2995
            suspend      => 0,
2991
            suspend      => 0
2996
        },
2992
        }
2997
        { prefetch => 'patron' }
2998
    );
2993
    );
2999
    if ( $fillable_holds->count ) {
2994
    if ( $fillable_holds->count ) {
3000
        if ( C4::Context->preference('AllowRenewalIfOtherItemsAvailable') ) {
2995
        if ( C4::Context->preference('AllowRenewalIfOtherItemsAvailable') ) {
Lines 3006-3012 sub CanBookBeRenewed { Link Here
3006
                biblionumber => $item->biblionumber,
3001
                biblionumber => $item->biblionumber,
3007
                onloan       => undef,
3002
                onloan       => undef,
3008
                notforloan   => 0,
3003
                notforloan   => 0,
3009
                -not         => { itemnumber => $itemnumber } })->as_list;
3004
                -not         => { itemnumber => $item->itemnumber } })->as_list;
3010
3005
3011
            return ( 0, "on_reserve" ) if @possible_holds && (scalar @other_items < scalar @possible_holds);
3006
            return ( 0, "on_reserve" ) if @possible_holds && (scalar @other_items < scalar @possible_holds);
3012
3007
Lines 3014-3020 sub CanBookBeRenewed { Link Here
3014
            foreach my $possible_hold (@possible_holds) {
3009
            foreach my $possible_hold (@possible_holds) {
3015
                my $fillable = 0;
3010
                my $fillable = 0;
3016
                my $patron_with_reserve = Koha::Patrons->find($possible_hold->borrowernumber);
3011
                my $patron_with_reserve = Koha::Patrons->find($possible_hold->borrowernumber);
3017
                my $items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $item->biblionumber, patron => $patron_with_reserve });
3012
                my $items_any_available = ItemsAnyAvailableAndNotRestricted({
3013
                    biblionumber => $item->biblionumber,
3014
                    patron => $patron_with_reserve
3015
                });
3018
3016
3019
                # FIXME: We are not checking whether the item we are renewing can fill the hold
3017
                # FIXME: We are not checking whether the item we are renewing can fill the hold
3020
3018
Lines 3032-3046 sub CanBookBeRenewed { Link Here
3032
                }
3030
                }
3033
                return ( 0, "on_reserve" ) unless $fillable;
3031
                return ( 0, "on_reserve" ) unless $fillable;
3034
            }
3032
            }
3035
3033
        }
3036
        } else {
3034
        else {
3037
            my ($status, $matched_reserve, $possible_reserves) = CheckReserves($itemnumber);
3035
            my ($status, $matched_reserve, $possible_reserves) = CheckReserves($item);
3038
            return ( 0, "on_reserve" ) if $status;
3036
            return ( 0, "on_reserve" ) if $status;
3039
        }
3037
        }
3040
    }
3038
    }
3041
3039
3042
    return ( 0, $auto_renew, { soonest_renew_date => $soonest } ) if $auto_renew =~ 'too_soon';#$auto_renew ne "no" && $auto_renew ne "ok";
3040
    return ( 0, $auto_renew, { soonest_renew_date => $soonest } ) if $auto_renew =~ 'too_soon';#$auto_renew ne "no" && $auto_renew ne "ok";
3043
    $soonest = GetSoonestRenewDate($issue);
3041
    $soonest = GetSoonestRenewDate($patron, $issue);
3044
    if ( $soonest > dt_from_string() ){
3042
    if ( $soonest > dt_from_string() ){
3045
        return (0, "too_soon", { soonest_renew_date => $soonest } ) unless $override_limit;
3043
        return (0, "too_soon", { soonest_renew_date => $soonest } ) unless $override_limit;
3046
    }
3044
    }
Lines 3290-3296 sub AddRenewal { Link Here
3290
3288
3291
sub GetRenewCount {
3289
sub GetRenewCount {
3292
    # check renewal status
3290
    # check renewal status
3293
    my ( $bornum, $itemno ) = @_;
3291
    my ( $borrowernumber_or_patron, $itemnumber_or_item ) = @_;
3292
3294
    my $dbh           = C4::Context->dbh;
3293
    my $dbh           = C4::Context->dbh;
3295
    my $renewcount    = 0;
3294
    my $renewcount    = 0;
3296
    my $unseencount    = 0;
3295
    my $unseencount    = 0;
Lines 3298-3306 sub GetRenewCount { Link Here
3298
    my $unseenallowed = 0;
3297
    my $unseenallowed = 0;
3299
    my $renewsleft    = 0;
3298
    my $renewsleft    = 0;
3300
    my $unseenleft    = 0;
3299
    my $unseenleft    = 0;
3301
3300
    my $patron = blessed $borrowernumber_or_patron ?
3302
    my $patron = Koha::Patrons->find( $bornum );
3301
        $borrowernumber_or_patron : Koha::Patrons->find($borrowernumber_or_patron);
3303
    my $item   = Koha::Items->find($itemno);
3302
    my $item = blessed $itemnumber_or_item ?
3303
        $itemnumber_or_item : Koha::Items->find($itemnumber_or_item);
3304
3304
3305
    return (0, 0, 0, 0, 0, 0) unless $patron or $item; # Wrong call, no renewal allowed
3305
    return (0, 0, 0, 0, 0, 0) unless $patron or $item; # Wrong call, no renewal allowed
3306
3306
Lines 3308-3319 sub GetRenewCount { Link Here
3308
    # and not yet returned.
3308
    # and not yet returned.
3309
3309
3310
    # FIXME - I think this function could be redone to use only one SQL call.
3310
    # FIXME - I think this function could be redone to use only one SQL call.
3311
    my $sth = $dbh->prepare(
3311
    my $sth = $dbh->prepare(q{
3312
        "select * from issues
3312
        SELECT * FROM issues
3313
                                where (borrowernumber = ?)
3313
        WHERE  (borrowernumber = ?) AND (itemnumber = ?)
3314
                                and (itemnumber = ?)"
3314
    });
3315
    );
3315
    $sth->execute( $patron->borrowernumber, $item->itemnumber );
3316
    $sth->execute( $bornum, $itemno );
3317
    my $data = $sth->fetchrow_hashref;
3316
    my $data = $sth->fetchrow_hashref;
3318
    $renewcount = $data->{'renewals_count'} if $data->{'renewals_count'};
3317
    $renewcount = $data->{'renewals_count'} if $data->{'renewals_count'};
3319
    $unseencount = $data->{'unseen_renewals'} if $data->{'unseen_renewals'};
3318
    $unseencount = $data->{'unseen_renewals'} if $data->{'unseen_renewals'};
Lines 3348-3358 sub GetRenewCount { Link Here
3348
3347
3349
=head2 GetSoonestRenewDate
3348
=head2 GetSoonestRenewDate
3350
3349
3351
  $NoRenewalBeforeThisDate = &GetSoonestRenewDate($checkout);
3350
  $NoRenewalBeforeThisDate = &GetSoonestRenewDate($patron, $issue);
3352
3351
3353
Find out the soonest possible renew date of a borrowed item.
3352
Find out the soonest possible renew date of a borrowed item.
3354
3353
3355
C<$checkout> is the checkout object to renew.
3354
C<$patron> is the patron who currently has the item on loan.
3355
3356
C<$issue> is the the item issue.
3356
3357
3357
C<$GetSoonestRenewDate> returns the DateTime of the soonest possible
3358
C<$GetSoonestRenewDate> returns the DateTime of the soonest possible
3358
renew date, based on the value "No renewal before" of the applicable
3359
renew date, based on the value "No renewal before" of the applicable
Lines 3363-3372 cannot be found. Link Here
3363
=cut
3364
=cut
3364
3365
3365
sub GetSoonestRenewDate {
3366
sub GetSoonestRenewDate {
3366
    my ( $checkout ) = @_;
3367
    my ( $patron, $issue ) = @_;
3368
    return unless $issue;
3369
    return unless $patron;
3367
3370
3368
    my $item   = $checkout->item or return;
3371
    my $item = $issue->item;
3369
    my $patron = $checkout->patron or return;
3372
    return unless $item;
3373
3374
    my $dbh = C4::Context->dbh;
3370
3375
3371
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3376
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3372
    my $issuing_rule = Koha::CirculationRules->get_effective_rules(
3377
    my $issuing_rule = Koha::CirculationRules->get_effective_rules(
Lines 3386-3392 sub GetSoonestRenewDate { Link Here
3386
        and $issuing_rule->{norenewalbefore} ne "" )
3391
        and $issuing_rule->{norenewalbefore} ne "" )
3387
    {
3392
    {
3388
        my $soonestrenewal =
3393
        my $soonestrenewal =
3389
          dt_from_string( $checkout->date_due )->subtract(
3394
          dt_from_string( $issue->date_due )->subtract(
3390
            $issuing_rule->{lengthunit} => $issuing_rule->{norenewalbefore} );
3395
            $issuing_rule->{lengthunit} => $issuing_rule->{norenewalbefore} );
3391
3396
3392
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
3397
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
Lines 3395-3403 sub GetSoonestRenewDate { Link Here
3395
            $soonestrenewal->truncate( to => 'day' );
3400
            $soonestrenewal->truncate( to => 'day' );
3396
        }
3401
        }
3397
        return $soonestrenewal if $now < $soonestrenewal;
3402
        return $soonestrenewal if $now < $soonestrenewal;
3398
    } elsif ( $checkout->auto_renew && $patron->autorenew_checkouts ) {
3403
    } elsif ( $issue->auto_renew && $patron->autorenew_checkouts ) {
3399
        # Checkouts with auto-renewing fall back to due date
3404
        # Checkouts with auto-renewing fall back to due date
3400
        my $soonestrenewal = dt_from_string( $checkout->date_due );
3405
        my $soonestrenewal = dt_from_string( $issue->date_due );
3401
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
3406
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
3402
            and $issuing_rule->{lengthunit} eq 'days' )
3407
            and $issuing_rule->{lengthunit} eq 'days' )
3403
        {
3408
        {
Lines 3410-3423 sub GetSoonestRenewDate { Link Here
3410
3415
3411
=head2 GetLatestAutoRenewDate
3416
=head2 GetLatestAutoRenewDate
3412
3417
3413
  $NoAutoRenewalAfterThisDate = &GetLatestAutoRenewDate($borrowernumber, $itemnumber);
3418
  $NoAutoRenewalAfterThisDate = &GetLatestAutoRenewDate($patron, $issue);
3414
3419
3415
Find out the latest possible auto renew date of a borrowed item.
3420
Find out the latest possible auto renew date of a borrowed item.
3416
3421
3417
C<$borrowernumber> is the borrower number of the patron who currently
3422
C<$patron> is the patron who currently has the item on loan.
3418
has the item on loan.
3419
3423
3420
C<$itemnumber> is the number of the item to renew.
3424
C<$issue> is the item issue.
3421
3425
3422
C<$GetLatestAutoRenewDate> returns the DateTime of the latest possible
3426
C<$GetLatestAutoRenewDate> returns the DateTime of the latest possible
3423
auto renew date, based on the value "No auto renewal after" and the "No auto
3427
auto renew date, based on the value "No auto renewal after" and the "No auto
Lines 3428-3443 or item cannot be found. Link Here
3428
=cut
3432
=cut
3429
3433
3430
sub GetLatestAutoRenewDate {
3434
sub GetLatestAutoRenewDate {
3431
    my ( $borrowernumber, $itemnumber ) = @_;
3435
    my ( $patron, $issue ) = @_;
3432
3436
    return unless $issue;
3433
    my $dbh = C4::Context->dbh;
3437
    return unless $patron;
3434
3438
3435
    my $item      = Koha::Items->find($itemnumber)  or return;
3439
    my $item = $issue->item;
3436
    my $itemissue = $item->checkout                 or return;
3440
    return unless $item;
3437
3441
3438
    $borrowernumber ||= $itemissue->borrowernumber;
3442
    my $dbh = C4::Context->dbh;
3439
    my $patron = Koha::Patrons->find( $borrowernumber )
3440
      or return;
3441
3443
3442
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3444
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3443
    my $circulation_rules = Koha::CirculationRules->get_effective_rules(
3445
    my $circulation_rules = Koha::CirculationRules->get_effective_rules(
Lines 3462-3468 sub GetLatestAutoRenewDate { Link Here
3462
3464
3463
    my $maximum_renewal_date;
3465
    my $maximum_renewal_date;
3464
    if ( $circulation_rules->{no_auto_renewal_after} ) {
3466
    if ( $circulation_rules->{no_auto_renewal_after} ) {
3465
        $maximum_renewal_date = dt_from_string($itemissue->issuedate);
3467
        $maximum_renewal_date = dt_from_string($issue->issuedate);
3466
        $maximum_renewal_date->add(
3468
        $maximum_renewal_date->add(
3467
            $circulation_rules->{lengthunit} => $circulation_rules->{no_auto_renewal_after}
3469
            $circulation_rules->{lengthunit} => $circulation_rules->{no_auto_renewal_after}
3468
        );
3470
        );
Lines 3512-3524 sub GetIssuingCharges { Link Here
3512
3514
3513
    my $sth = $dbh->prepare($charge_query);
3515
    my $sth = $dbh->prepare($charge_query);
3514
    $sth->execute($itemnumber);
3516
    $sth->execute($itemnumber);
3517
    my $patron;
3515
    if ( my $item_data = $sth->fetchrow_hashref ) {
3518
    if ( my $item_data = $sth->fetchrow_hashref ) {
3516
        $item_type = $item_data->{itemtype};
3519
        $item_type = $item_data->{itemtype};
3517
        $charge    = $item_data->{rentalcharge};
3520
        $charge    = $item_data->{rentalcharge};
3518
        if ($charge) {
3521
        if ($charge) {
3519
            # FIXME This should follow CircControl
3522
            # FIXME This should follow CircControl
3520
            my $branch = C4::Context::mybranch();
3523
            my $branch = C4::Context::mybranch();
3521
            my $patron = Koha::Patrons->find( $borrowernumber );
3524
            $patron //= Koha::Patrons->find( $borrowernumber );
3522
            my $discount = Koha::CirculationRules->get_effective_rule({
3525
            my $discount = Koha::CirculationRules->get_effective_rule({
3523
                categorycode => $patron->categorycode,
3526
                categorycode => $patron->categorycode,
3524
                branchcode   => $branch,
3527
                branchcode   => $branch,
Lines 4456-4462 sub _CanBookBeAutoRenewed { Link Here
4456
        }
4459
        }
4457
    );
4460
    );
4458
4461
4459
    if ( $patron->category->effective_BlockExpiredPatronOpacActions and $patron->is_expired ) {
4462
    if ( $patron->is_expired && $patron->category->effective_BlockExpiredPatronOpacActions ) {
4460
        return 'auto_account_expired';
4463
        return 'auto_account_expired';
4461
    }
4464
    }
4462
4465
Lines 4492-4498 sub _CanBookBeAutoRenewed { Link Here
4492
        }
4495
        }
4493
    }
4496
    }
4494
4497
4495
    my $soonest = GetSoonestRenewDate($issue);
4498
    my $soonest = GetSoonestRenewDate($patron, $issue);
4496
    if ( $soonest > dt_from_string() )
4499
    if ( $soonest > dt_from_string() )
4497
    {
4500
    {
4498
        return ( "auto_too_soon", $soonest );
4501
        return ( "auto_too_soon", $soonest );
(-)a/C4/ILSDI/Services.pm (-5 / +7 lines)
Lines 637-643 sub GetServices { Link Here
637
    }
637
    }
638
638
639
    # Renewal management
639
    # Renewal management
640
    my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
640
    my @renewal = CanBookBeRenewed( $patron, $item->checkout ); # TODO: Error if issue not found?
641
    if ( $renewal[0] ) {
641
    if ( $renewal[0] ) {
642
        push @availablefor, 'loan renewal';
642
        push @availablefor, 'loan renewal';
643
    }
643
    }
Lines 681-696 sub RenewLoan { Link Here
681
    return { code => 'PatronNotFound' } unless $patron;
681
    return { code => 'PatronNotFound' } unless $patron;
682
682
683
    # Get the item, or return an error code
683
    # Get the item, or return an error code
684
    my $itemnumber = $cgi->param('item_id');
684
    my $itemnumber = $cgi->param('item_id'); # TODO: Refactor and send issue_id instead?
685
    my $item = Koha::Items->find($itemnumber);
685
    my $item = Koha::Items->find($itemnumber);
686
686
    return { code => 'RecordNotFound' } unless $item;
687
    return { code => 'RecordNotFound' } unless $item;
687
688
689
    my $issue = $item->checkout;
690
    return unless $issue; # FIXME should be handled
691
688
    # Add renewal if possible
692
    # Add renewal if possible
689
    my @renewal = CanBookBeRenewed( $borrowernumber, $itemnumber );
693
    my @renewal = CanBookBeRenewed( $patron, $issue );
690
    if ( $renewal[0] ) { AddRenewal( $borrowernumber, $itemnumber, undef, undef, undef, undef, 0 ); }
694
    if ( $renewal[0] ) { AddRenewal( $borrowernumber, $itemnumber, undef, undef, undef, undef, 0 ); }
691
695
692
    my $issue = $item->checkout;
693
    return unless $issue; # FIXME should be handled
694
696
695
    # Hashref building
697
    # Hashref building
696
    my $out;
698
    my $out;
(-)a/C4/Reserves.pm (-66 / +30 lines)
Lines 676-684 sub GetOtherReserves { Link Here
676
    my ($itemnumber) = @_;
676
    my ($itemnumber) = @_;
677
    my $messages;
677
    my $messages;
678
    my $nextreservinfo;
678
    my $nextreservinfo;
679
    my ( undef, $checkreserves, undef ) = CheckReserves($itemnumber);
679
    my $item = Koha::Items->find($itemnumber);
680
    my ( undef, $checkreserves, undef ) = CheckReserves($item);
680
    if ($checkreserves) {
681
    if ($checkreserves) {
681
        my $item = Koha::Items->find($itemnumber);
682
        if ( $item->holdingbranch ne $checkreserves->{'branchcode'} ) {
682
        if ( $item->holdingbranch ne $checkreserves->{'branchcode'} ) {
683
            $messages->{'transfert'} = $checkreserves->{'branchcode'};
683
            $messages->{'transfert'} = $checkreserves->{'branchcode'};
684
            #minus priorities of others reservs
684
            #minus priorities of others reservs
Lines 823-835 sub GetReserveStatus { Link Here
823
823
824
=head2 CheckReserves
824
=head2 CheckReserves
825
825
826
  ($status, $matched_reserve, $possible_reserves) = &CheckReserves($itemnumber);
826
  ($status, $matched_reserve, $possible_reserves) = &CheckReserves($item);
827
  ($status, $matched_reserve, $possible_reserves) = &CheckReserves(undef, $barcode);
827
  ($status, $matched_reserve, $possible_reserves) = &CheckReserves($item, $lookahead);
828
  ($status, $matched_reserve, $possible_reserves) = &CheckReserves($itemnumber,undef,$lookahead);
829
828
830
Find a book in the reserves.
829
Find a book in the reserves.
831
830
832
C<$itemnumber> is the book's item number.
831
C<$item> is the book's item.
833
C<$lookahead> is the number of days to look in advance for future reserves.
832
C<$lookahead> is the number of days to look in advance for future reserves.
834
833
835
As I understand it, C<&CheckReserves> looks for the given item in the
834
As I understand it, C<&CheckReserves> looks for the given item in the
Lines 851-915 table in the Koha database. Link Here
851
=cut
850
=cut
852
851
853
sub CheckReserves {
852
sub CheckReserves {
854
    my ( $item, $barcode, $lookahead_days, $ignore_borrowers) = @_;
853
    my ( $item, $lookahead_days, $ignore_borrowers ) = @_;
855
    my $dbh = C4::Context->dbh;
856
    my $sth;
857
    my $select;
858
    if (C4::Context->preference('item-level_itypes')){
859
	$select = "
860
           SELECT items.biblionumber,
861
           items.biblioitemnumber,
862
           itemtypes.notforloan,
863
           items.notforloan AS itemnotforloan,
864
           items.itemnumber,
865
           items.damaged,
866
           items.homebranch,
867
           items.holdingbranch
868
           FROM   items
869
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
870
           LEFT JOIN itemtypes   ON items.itype   = itemtypes.itemtype
871
        ";
872
    }
873
    else {
874
	$select = "
875
           SELECT items.biblionumber,
876
           items.biblioitemnumber,
877
           itemtypes.notforloan,
878
           items.notforloan AS itemnotforloan,
879
           items.itemnumber,
880
           items.damaged,
881
           items.homebranch,
882
           items.holdingbranch
883
           FROM   items
884
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
885
           LEFT JOIN itemtypes   ON biblioitems.itemtype   = itemtypes.itemtype
886
        ";
887
    }
888
889
    if ($item) {
890
        $sth = $dbh->prepare("$select WHERE itemnumber = ?");
891
        $sth->execute($item);
892
    }
893
    else {
894
        $sth = $dbh->prepare("$select WHERE barcode = ?");
895
        $sth->execute($barcode);
896
    }
897
    # note: we get the itemnumber because we might have started w/ just the barcode.  Now we know for sure we have it.
854
    # note: we get the itemnumber because we might have started w/ just the barcode.  Now we know for sure we have it.
898
    my ( $biblio, $bibitem, $notforloan_per_itemtype, $notforloan_per_item, $itemnumber, $damaged, $item_homebranch, $item_holdingbranch ) = $sth->fetchrow_array;
899
    return if ( $damaged && !C4::Context->preference('AllowHoldsOnDamagedItems') );
900
855
901
    return unless $itemnumber; # bail if we got nothing.
856
    return unless $item; # bail if we got nothing.
857
858
    return if ( $item->damaged && !C4::Context->preference('AllowHoldsOnDamagedItems') );
859
902
    # if item is not for loan it cannot be reserved either.....
860
    # if item is not for loan it cannot be reserved either.....
903
    # except where items.notforloan < 0 :  This indicates the item is holdable.
861
    # except where items.notforloan < 0 :  This indicates the item is holdable.
904
862
905
    my @SkipHoldTrapOnNotForLoanValue = split( '\|', C4::Context->preference('SkipHoldTrapOnNotForLoanValue') );
863
    my @SkipHoldTrapOnNotForLoanValue = split( '\|', C4::Context->preference('SkipHoldTrapOnNotForLoanValue') );
906
    return if grep { $_ eq $notforloan_per_item } @SkipHoldTrapOnNotForLoanValue;
864
    return if grep { $_ eq $item->notforloan } @SkipHoldTrapOnNotForLoanValue;
907
865
908
    my $dont_trap = C4::Context->preference('TrapHoldsOnOrder') ? ($notforloan_per_item > 0) : ($notforloan_per_item && 1 );
866
    my $dont_trap = C4::Context->preference('TrapHoldsOnOrder') ? $item->notforloan > 0 : $item->notforloan;
909
    return if $dont_trap or $notforloan_per_itemtype;
867
    if ( !$dont_trap ) {
868
        my $item_type = $item->effective_itemtype;
869
        if ( $item_type ) {
870
            return if Koha::ItemTypes->find( $item_type )->notforloan;
871
        }
872
    }
873
    else {
874
        return;
875
    }
910
876
911
    # Find this item in the reserves
877
    # Find this item in the reserves
912
    my @reserves = _Findgroupreserve( $bibitem, $biblio, $itemnumber, $lookahead_days, $ignore_borrowers);
878
    my @reserves = _Findgroupreserve( $item->biblionumber, $item->itemnumber, $lookahead_days, $ignore_borrowers);
913
879
914
    # $priority and $highest are used to find the most important item
880
    # $priority and $highest are used to find the most important item
915
    # in the list returned by &_Findgroupreserve. (The lower $priority,
881
    # in the list returned by &_Findgroupreserve. (The lower $priority,
Lines 921-928 sub CheckReserves { Link Here
921
        my $LocalHoldsPriority = C4::Context->preference('LocalHoldsPriority');
887
        my $LocalHoldsPriority = C4::Context->preference('LocalHoldsPriority');
922
        my $LocalHoldsPriorityPatronControl = C4::Context->preference('LocalHoldsPriorityPatronControl');
888
        my $LocalHoldsPriorityPatronControl = C4::Context->preference('LocalHoldsPriorityPatronControl');
923
        my $LocalHoldsPriorityItemControl = C4::Context->preference('LocalHoldsPriorityItemControl');
889
        my $LocalHoldsPriorityItemControl = C4::Context->preference('LocalHoldsPriorityItemControl');
924
925
        my $priority = 10000000;
890
        my $priority = 10000000;
891
926
        foreach my $res (@reserves) {
892
        foreach my $res (@reserves) {
927
            if ($res->{'found'} && $res->{'found'} eq 'W') {
893
            if ($res->{'found'} && $res->{'found'} eq 'W') {
928
                return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
894
                return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
Lines 932-943 sub CheckReserves { Link Here
932
                return ( "Transferred", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
898
                return ( "Transferred", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
933
            } else {
899
            } else {
934
                my $patron;
900
                my $patron;
935
                my $item;
936
                my $local_hold_match;
901
                my $local_hold_match;
937
902
938
                if ($LocalHoldsPriority) {
903
                if ($LocalHoldsPriority) {
939
                    $patron = Koha::Patrons->find( $res->{borrowernumber} );
904
                    $patron = Koha::Patrons->find( $res->{borrowernumber} );
940
                    $item = Koha::Items->find($itemnumber);
941
905
942
                    unless ($item->exclude_from_local_holds_priority || $patron->category->exclude_from_local_holds_priority) {
906
                    unless ($item->exclude_from_local_holds_priority || $patron->category->exclude_from_local_holds_priority) {
943
                        my $local_holds_priority_item_branchcode =
907
                        my $local_holds_priority_item_branchcode =
Lines 956-965 sub CheckReserves { Link Here
956
920
957
                # See if this item is more important than what we've got so far
921
                # See if this item is more important than what we've got so far
958
                if ( ( $res->{'priority'} && $res->{'priority'} < $priority ) || $local_hold_match ) {
922
                if ( ( $res->{'priority'} && $res->{'priority'} < $priority ) || $local_hold_match ) {
959
                    $item ||= Koha::Items->find($itemnumber);
960
                    next if $res->{item_group_id} && ( !$item->item_group || $item->item_group->id != $res->{item_group_id} );
923
                    next if $res->{item_group_id} && ( !$item->item_group || $item->item_group->id != $res->{item_group_id} );
961
                    next if $res->{itemtype} && $res->{itemtype} ne $item->effective_itemtype;
924
                    next if $res->{itemtype} && $res->{itemtype} ne $item->effective_itemtype;
962
                    $patron ||= Koha::Patrons->find( $res->{borrowernumber} );
925
                    $patron //= Koha::Patrons->find( $res->{borrowernumber} );
963
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
926
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
964
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
927
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
965
                    next if ($branchitemrule->{'holdallowed'} eq 'not_allowed');
928
                    next if ($branchitemrule->{'holdallowed'} eq 'not_allowed');
Lines 982-988 sub CheckReserves { Link Here
982
    # If we get this far, then no exact match was found.
945
    # If we get this far, then no exact match was found.
983
    # We return the most important (i.e. next) reservation.
946
    # We return the most important (i.e. next) reservation.
984
    if ($highest) {
947
    if ($highest) {
985
        $highest->{'itemnumber'} = $item;
948
        $highest->{'itemnumber'} = $item->itemnumber;
986
        return ( "Reserved", $highest, \@reserves );
949
        return ( "Reserved", $highest, \@reserves );
987
    }
950
    }
988
951
Lines 1710-1716 sub _FixPriority { Link Here
1710
1673
1711
=head2 _Findgroupreserve
1674
=head2 _Findgroupreserve
1712
1675
1713
  @results = &_Findgroupreserve($biblioitemnumber, $biblionumber, $itemnumber, $lookahead, $ignore_borrowers);
1676
  @results = &_Findgroupreserve($biblionumber, $itemnumber, $lookahead, $ignore_borrowers);
1714
1677
1715
Looks for a holds-queue based item-specific match first, then for a holds-queue title-level match, returning the
1678
Looks for a holds-queue based item-specific match first, then for a holds-queue title-level match, returning the
1716
first match found.  If neither, then we look for non-holds-queue based holds.
1679
first match found.  If neither, then we look for non-holds-queue based holds.
Lines 1731-1737 All return values will respect any borrowernumbers passed as arrayref in $ignore Link Here
1731
=cut
1694
=cut
1732
1695
1733
sub _Findgroupreserve {
1696
sub _Findgroupreserve {
1734
    my ( $bibitem, $biblio, $itemnumber, $lookahead, $ignore_borrowers) = @_;
1697
    my ( $biblionumber, $itemnumber, $lookahead, $ignore_borrowers) = @_;
1735
    my $dbh   = C4::Context->dbh;
1698
    my $dbh   = C4::Context->dbh;
1736
1699
1737
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1700
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
Lines 1835-1841 sub _Findgroupreserve { Link Here
1835
          ORDER BY priority
1798
          ORDER BY priority
1836
    };
1799
    };
1837
    $sth = $dbh->prepare($query);
1800
    $sth = $dbh->prepare($query);
1838
    $sth->execute( $biblio, $itemnumber, $lookahead||0);
1801
    $sth->execute( $biblionumber, $itemnumber, $lookahead||0);
1839
    @results = ();
1802
    @results = ();
1840
    while ( my $data = $sth->fetchrow_hashref ) {
1803
    while ( my $data = $sth->fetchrow_hashref ) {
1841
        push( @results, $data )
1804
        push( @results, $data )
Lines 2051-2057 sub MoveReserve { Link Here
2051
    $cancelreserve //= 0;
2014
    $cancelreserve //= 0;
2052
2015
2053
    my $lookahead = C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2016
    my $lookahead = C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2054
    my ( $restype, $res, undef ) = CheckReserves( $itemnumber, undef, $lookahead );
2017
    my $item = Koha::Items->find($itemnumber);
2018
    my ( $restype, $res, undef ) = CheckReserves( $item, $lookahead );
2055
    return unless $res;
2019
    return unless $res;
2056
2020
2057
    my $biblionumber = $res->{biblionumber};
2021
    my $biblionumber = $res->{biblionumber};
(-)a/C4/RotatingCollections.pm (-1 lines)
Lines 25-31 package C4::RotatingCollections; Link Here
25
use Modern::Perl;
25
use Modern::Perl;
26
26
27
use C4::Context;
27
use C4::Context;
28
use C4::Reserves qw(CheckReserves);
29
use Koha::Database;
28
use Koha::Database;
30
29
31
use Try::Tiny qw( catch try );
30
use Try::Tiny qw( catch try );
(-)a/C4/SIP/ILS/Transaction/Checkin.pm (-1 / +1 lines)
Lines 90-96 sub do_checkin { Link Here
90
90
91
    my $reserved;
91
    my $reserved;
92
    my $lookahead = C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
92
    my $lookahead = C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
93
    my ($resfound) = $item->withdrawn ? q{} : C4::Reserves::CheckReserves( $item->itemnumber, undef, $lookahead );
93
    my ($resfound) = $item->withdrawn ? q{} : CheckReserves( $item, $lookahead );
94
    if ( $resfound eq "Reserved") {
94
    if ( $resfound eq "Reserved") {
95
        $reserved = 1;
95
        $reserved = 1;
96
    }
96
    }
(-)a/C4/SIP/ILS/Transaction/Renew.pm (-4 / +6 lines)
Lines 31-38 sub new { Link Here
31
31
32
sub do_renew_for  {
32
sub do_renew_for  {
33
    my $self = shift;
33
    my $self = shift;
34
    my $borrower = shift;
34
    my $patron = shift;
35
    my ($renewokay,$renewerror) = CanBookBeRenewed($borrower->{borrowernumber},$self->{item}->{itemnumber});
35
    my $checkout = Koha::Checkouts->find({ itemnumber => $self->{item}->{itemnumber} });
36
    my ($renewokay,$renewerror) = CanBookBeRenewed($patron, $checkout);
36
    if ($renewokay) { # ok so far check charges
37
    if ($renewokay) { # ok so far check charges
37
        my ($fee, undef) = GetIssuingCharges($self->{item}->{itemnumber}, $self->{patron}->{borrowernumber});
38
        my ($fee, undef) = GetIssuingCharges($self->{item}->{itemnumber}, $self->{patron}->{borrowernumber});
38
        if ($fee > 0) {
39
        if ($fee > 0) {
Lines 45-51 sub do_renew_for { Link Here
45
46
46
    }
47
    }
47
    if ($renewokay){
48
    if ($renewokay){
48
        my $issue = AddIssue( $borrower, $self->{item}->id, undef, 0 );
49
        my $issue = AddIssue( $patron, $self->{item}->id, undef, 0 );
49
        $self->{due} = $self->duedatefromissue($issue, $self->{item}->{itemnumber});
50
        $self->{due} = $self->duedatefromissue($issue, $self->{item}->{itemnumber});
50
        $self->renewal_ok(1);
51
        $self->renewal_ok(1);
51
    } else {
52
    } else {
Lines 53-58 sub do_renew_for { Link Here
53
        $renewerror=~s/too_many/Item has reached maximum renewals/;
54
        $renewerror=~s/too_many/Item has reached maximum renewals/;
54
        $renewerror=~s/too_unseen/Item has reached maximum consecutive renewals without being seen/;
55
        $renewerror=~s/too_unseen/Item has reached maximum consecutive renewals without being seen/;
55
        $renewerror=~s/item_denied_renewal/Item renewal is not allowed/;
56
        $renewerror=~s/item_denied_renewal/Item renewal is not allowed/;
57
        $renewerror=~s/item_issued_to_other_patron/Item already issued to other borrower/;
56
        $self->screen_msg($renewerror);
58
        $self->screen_msg($renewerror);
57
        $self->renewal_ok(0);
59
        $self->renewal_ok(0);
58
    }
60
    }
Lines 64-70 sub do_renew { Link Here
64
    my $self = shift;
66
    my $self = shift;
65
    my $patron = Koha::Patrons->find( $self->{patron}->borrowernumber );
67
    my $patron = Koha::Patrons->find( $self->{patron}->borrowernumber );
66
    $patron or return; # FIXME we should log that
68
    $patron or return; # FIXME we should log that
67
    return $self->do_renew_for($patron->unblessed);
69
    return $self->do_renew_for($patron);
68
}
70
}
69
71
70
1;
72
1;
(-)a/C4/SIP/ILS/Transaction/RenewAll.pm (-4 / +3 lines)
Lines 33-44 sub new { Link Here
33
33
34
sub do_renew_all {
34
sub do_renew_all {
35
    my $self     = shift;
35
    my $self     = shift;
36
    my $patron   = $self->{patron};                           # SIP's  patron
36
    my $patron = Koha::Patrons->find( $self->{patron}->{borrowernumber} );
37
    my $borrower = Koha::Patrons->find( { cardnumber => $patron->id } )->unblessed;    # Koha's patron
38
    my $all_ok   = 1;
37
    my $all_ok   = 1;
39
    $self->{renewed}   = [];
38
    $self->{renewed}   = [];
40
    $self->{unrenewed} = [];
39
    $self->{unrenewed} = [];
41
    foreach my $itemx ( @{ $patron->{items} } ) {
40
    foreach my $itemx ( @{ $self->{patron}->{items} } ) {
42
        my $item_id = $itemx->{barcode};
41
        my $item_id = $itemx->{barcode};
43
        my $item    = C4::SIP::ILS::Item->new($item_id);
42
        my $item    = C4::SIP::ILS::Item->new($item_id);
44
        if ( !defined($item) ) {
43
        if ( !defined($item) ) {
Lines 54-60 sub do_renew_all { Link Here
54
            next;
53
            next;
55
        }
54
        }
56
        $self->{item} = $item;
55
        $self->{item} = $item;
57
        $self->do_renew_for($borrower);
56
        $self->do_renew_for($patron);
58
        if ( $self->renewal_ok ) {
57
        if ( $self->renewal_ok ) {
59
            $item->{due_date} = $self->{due};
58
            $item->{due_date} = $self->{due};
60
            push @{ $self->{renewed} }, $item_id;
59
            push @{ $self->{renewed} }, $item_id;
(-)a/C4/SIP/Sip/MsgType.pm (-1 / +2 lines)
Lines 1166-1172 sub handle_fee_paid { Link Here
1166
        "on_reserve" => "On hold for another patron",
1166
        "on_reserve" => "On hold for another patron",
1167
        "patron_restricted" => "Patron is currently restricted",
1167
        "patron_restricted" => "Patron is currently restricted",
1168
        "item_denied_renewal" => "Item is not allowed renewal",
1168
        "item_denied_renewal" => "Item is not allowed renewal",
1169
        "onsite_checkout" => "Item is an onsite checkout"
1169
        "onsite_checkout" => "Item is an onsite checkout",
1170
        "item_issued_to_other_patron" => "Item already issued to other borrower"
1170
    };
1171
    };
1171
    my @success = ();
1172
    my @success = ();
1172
    my @fail = ();
1173
    my @fail = ();
(-)a/Koha/Account/Line.pm (-4 / +3 lines)
Lines 20-26 use Modern::Perl; Link Here
20
use Data::Dumper qw( Dumper );
20
use Data::Dumper qw( Dumper );
21
21
22
use C4::Log qw( logaction );
22
use C4::Log qw( logaction );
23
use C4::Overdues qw( UpdateFine );
24
23
25
use Koha::Account::CreditType;
24
use Koha::Account::CreditType;
26
use Koha::Account::DebitType;
25
use Koha::Account::DebitType;
Lines 1023-1034 sub renew_item { Link Here
1023
    }
1022
    }
1024
1023
1025
    my $itemnumber = $self->item->itemnumber;
1024
    my $itemnumber = $self->item->itemnumber;
1026
    my $borrowernumber = $self->patron->borrowernumber;
1027
    my ( $can_renew, $error ) = C4::Circulation::CanBookBeRenewed(
1025
    my ( $can_renew, $error ) = C4::Circulation::CanBookBeRenewed(
1028
        $borrowernumber,
1026
        $self->patron,
1029
        $itemnumber
1027
        $self->item->checkout
1030
    );
1028
    );
1031
    if ( $can_renew ) {
1029
    if ( $can_renew ) {
1030
        my $borrowernumber = $self->patron->borrowernumber;
1032
        my $due_date = C4::Circulation::AddRenewal(
1031
        my $due_date = C4::Circulation::AddRenewal(
1033
            $borrowernumber,
1032
            $borrowernumber,
1034
            $itemnumber,
1033
            $itemnumber,
(-)a/Koha/Hold.pm (-1 / +1 lines)
Lines 762-768 sub cancel { Link Here
762
    );
762
    );
763
763
764
    if ($autofill_next) {
764
    if ($autofill_next) {
765
        my ( undef, $next_hold ) = C4::Reserves::CheckReserves( $self->itemnumber );
765
        my ( undef, $next_hold ) = C4::Reserves::CheckReserves( $self->item );
766
        if ($next_hold) {
766
        if ($next_hold) {
767
            my $is_transfer = $self->branchcode ne $next_hold->{branchcode};
767
            my $is_transfer = $self->branchcode ne $next_hold->{branchcode};
768
768
(-)a/Koha/REST/V1/Checkouts.pm (-10 / +5 lines)
Lines 22-28 use Mojo::JSON; Link Here
22
22
23
use C4::Auth qw( haspermission );
23
use C4::Auth qw( haspermission );
24
use C4::Context;
24
use C4::Context;
25
use C4::Circulation qw( AddRenewal );
25
use C4::Circulation qw( AddRenewal CanBookBeRenewed );
26
use Koha::Checkouts;
26
use Koha::Checkouts;
27
use Koha::Old::Checkouts;
27
use Koha::Old::Checkouts;
28
28
Lines 156-166 sub renew { Link Here
156
    }
156
    }
157
157
158
    return try {
158
    return try {
159
        my $borrowernumber = $checkout->borrowernumber;
159
        my ($can_renew, $error) = CanBookBeRenewed($checkout->patron, $checkout);
160
        my $itemnumber = $checkout->itemnumber;
161
162
        my ($can_renew, $error) = C4::Circulation::CanBookBeRenewed(
163
            $borrowernumber, $itemnumber);
164
160
165
        if (!$can_renew) {
161
        if (!$can_renew) {
166
            return $c->render(
162
            return $c->render(
Lines 170-177 sub renew { Link Here
170
        }
166
        }
171
167
172
        AddRenewal(
168
        AddRenewal(
173
            $borrowernumber,
169
            $checkout->borrowernumber,
174
            $itemnumber,
170
            $checkout->itemnumber,
175
            $checkout->branchcode,
171
            $checkout->branchcode,
176
            undef,
172
            undef,
177
            undef,
173
            undef,
Lines 210-217 sub allows_renewal { Link Here
210
    }
206
    }
211
207
212
    return try {
208
    return try {
213
        my ($can_renew, $error) = C4::Circulation::CanBookBeRenewed(
209
        my ($can_renew, $error) = CanBookBeRenewed($checkout->patron, $checkout);
214
            $checkout->borrowernumber, $checkout->itemnumber);
215
210
216
        my $renewable = Mojo::JSON->false;
211
        my $renewable = Mojo::JSON->false;
217
        $renewable = Mojo::JSON->true if $can_renew;
212
        $renewable = Mojo::JSON->true if $can_renew;
(-)a/circ/renew.pl (-14 / +13 lines)
Lines 48-75 my $override_limit = $cgi->param('override_limit'); Link Here
48
my $override_holds = $cgi->param('override_holds');
48
my $override_holds = $cgi->param('override_holds');
49
my $hard_due_date  = $cgi->param('hard_due_date');
49
my $hard_due_date  = $cgi->param('hard_due_date');
50
50
51
my ( $item, $issue, $borrower );
51
my ( $item, $checkout, $patron );
52
my $error = q{};
52
my $error = q{};
53
my ( $soonest_renew_date, $latest_auto_renew_date );
53
my ( $soonest_renew_date, $latest_auto_renew_date );
54
54
55
if ($barcode) {
55
if ($barcode) {
56
    $barcode = barcodedecode($barcode) if $barcode;
56
    $barcode = barcodedecode($barcode) if $barcode;
57
    $item = $schema->resultset("Item")->single( { barcode => $barcode } );
57
    $item = Koha::Items->find({ barcode => $barcode });
58
58
59
    if ($item) {
59
    if ($item) {
60
60
61
        $issue = $item->issue();
61
        $checkout = $item->checkout;
62
62
63
        if ($issue) {
63
        if ($checkout) {
64
64
65
            $borrower = $issue->patron();
65
            $patron = $checkout->patron;
66
            
66
67
            if ( ( $borrower->debarred() || q{} ) lt dt_from_string()->ymd() ) {
67
            if ( ( $patron->is_debarred || q{} ) lt dt_from_string()->ymd() ) {
68
                my $can_renew;
68
                my $can_renew;
69
                my $info;
69
                my $info;
70
                ( $can_renew, $error, $info ) =
70
                ( $can_renew, $error, $info ) =
71
                  CanBookBeRenewed( $borrower->borrowernumber(),
71
                  CanBookBeRenewed( $patron, $checkout, $override_limit );
72
                    $item->itemnumber(), $override_limit );
73
72
74
                if ( $error && ($error eq 'on_reserve') ) {
73
                if ( $error && ($error eq 'on_reserve') ) {
75
                    if ($override_holds) {
74
                    if ($override_holds) {
Lines 85-93 if ($barcode) { Link Here
85
                    $soonest_renew_date = $info->{soonest_renew_date};
84
                    $soonest_renew_date = $info->{soonest_renew_date};
86
                }
85
                }
87
                if ( $error && ( $error eq 'auto_too_late' ) ) {
86
                if ( $error && ( $error eq 'auto_too_late' ) ) {
88
                    $latest_auto_renew_date = C4::Circulation::GetLatestAutoRenewDate(
87
                    $latest_auto_renew_date = GetLatestAutoRenewDate(
89
                        $borrower->borrowernumber(),
88
                        $patron,
90
                        $item->itemnumber(),
89
                        $checkout,
91
                    );
90
                    );
92
                }
91
                }
93
                if ($can_renew) {
92
                if ($can_renew) {
Lines 124-131 if ($barcode) { Link Here
124
123
125
    $template->param(
124
    $template->param(
126
        item     => $item,
125
        item     => $item,
127
        issue    => $issue,
126
        issue    => $checkout,
128
        borrower => $borrower,
127
        borrower => $patron,
129
        error    => $error,
128
        error    => $error,
130
        soonestrenewdate => $soonest_renew_date,
129
        soonestrenewdate => $soonest_renew_date,
131
        latestautorenewdate => $latest_auto_renew_date,
130
        latestautorenewdate => $latest_auto_renew_date,
(-)a/koha-tmpl/intranet-tmpl/prog/en/includes/renew_strings.inc (+2 lines)
Lines 27-32 Link Here
27
    <span>Item is an onsite checkout</span>
27
    <span>Item is an onsite checkout</span>
28
[% CASE 'has_fine' %]
28
[% CASE 'has_fine' %]
29
    <span>Item has an outstanding fine</span>
29
    <span>Item has an outstanding fine</span>
30
[% CASE 'item_issued_to_other_patron'%]
31
    <span>Item already issued to other borrower</span>
30
[% CASE %]
32
[% CASE %]
31
    <span>Unknown error</span>
33
    <span>Unknown error</span>
32
[% END %]
34
[% END %]
(-)a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-user.tt (+2 lines)
Lines 108-113 Link Here
108
                                            <li>This item is on hold for another borrower.</li>
108
                                            <li>This item is on hold for another borrower.</li>
109
                                        [% ELSIF error == 'item_denied_renewal' %]
109
                                        [% ELSIF error == 'item_denied_renewal' %]
110
                                            <li>Item renewal is not allowed.</li>
110
                                            <li>Item renewal is not allowed.</li>
111
                                        [% ELSIF error == 'item_issued_to_other_patron'%]
112
                                            <li>Item already issued to other borrower.</li>
111
                                        [% ELSIF error == 'auto_too_soon' %]
113
                                        [% ELSIF error == 'auto_too_soon' %]
112
                                            <li>This item is scheduled for auto renewal.</li>
114
                                            <li>This item is scheduled for auto renewal.</li>
113
                                        [% END %]
115
                                        [% END %]
(-)a/misc/cronjobs/automatic_renewals.pl (-11 / +14 lines)
Lines 172-178 while ( my $auto_renew = $auto_renews->next ) { Link Here
172
    }
172
    }
173
173
174
    # CanBookBeRenewed returns 'auto_renew' when the renewal should be done by this script
174
    # CanBookBeRenewed returns 'auto_renew' when the renewal should be done by this script
175
    my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->borrowernumber, $auto_renew->itemnumber, undef, 1 );
175
    my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->patron, $auto_renew, undef, 1 );
176
    my $updated;
176
    my $updated;
177
    if ( $error eq 'auto_renew' ) {
177
    if ( $error eq 'auto_renew' ) {
178
        $updated = 1;
178
        $updated = 1;
Lines 187-202 while ( my $auto_renew = $auto_renews->next ) { Link Here
187
        }
187
        }
188
        push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
188
        push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
189
            if ( $wants_messages ) && !$wants_digest;
189
            if ( $wants_messages ) && !$wants_digest;
190
    } elsif ( $error eq 'too_many'
190
    } elsif (
191
        or $error eq 'on_reserve'
191
        $error eq 'too_many' ||
192
        or $error eq 'restriction'
192
        $error eq 'on_reserve' ||
193
        or $error eq 'overdue'
193
        $error eq 'restriction' ||
194
        or $error eq 'too_unseen'
194
        $error eq 'overdue' ||
195
        or $error eq 'auto_account_expired'
195
        $error eq 'too_unseen' ||
196
        or $error eq 'auto_too_late'
196
        $error eq 'auto_account_expired' ||
197
        or $error eq 'auto_too_much_oweing'
197
        $error eq 'auto_too_late' ||
198
        or $error eq 'auto_too_soon'
198
        $error eq 'auto_too_much_oweing' ||
199
        or $error eq 'item_denied_renewal' ) {
199
        $error eq 'auto_too_soon' ||
200
        $error eq 'item_denied_renewal' ||
201
        $error eq 'item_issued_to_other_patron'
202
    ) {
200
        if ( $verbose ) {
203
        if ( $verbose ) {
201
            say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
204
            say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
202
              $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $confirm ? 'will' : 'would', $error;
205
              $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $confirm ? 'will' : 'would', $error;
(-)a/opac/opac-renew.pl (-1 / +2 lines)
Lines 56-63 if ( $patron->category->effective_BlockExpiredPatronOpacActions Link Here
56
else {
56
else {
57
    my @renewed;
57
    my @renewed;
58
    for my $itemnumber (@items) {
58
    for my $itemnumber (@items) {
59
        my $item = Koha::Items->find($itemnumber);
59
        my ( $status, $error ) =
60
        my ( $status, $error ) =
60
          CanBookBeRenewed( $borrowernumber, $itemnumber );
61
          CanBookBeRenewed( $patron, $item->checkout ); #TODO: Pass issue numbers instead
61
        if ( $status == 1 && $opacrenew == 1 ) {
62
        if ( $status == 1 && $opacrenew == 1 ) {
62
            AddRenewal( $borrowernumber, $itemnumber, undef, undef, undef, undef, 0 );
63
            AddRenewal( $borrowernumber, $itemnumber, undef, undef, undef, undef, 0 );
63
            push( @renewed, $itemnumber );
64
            push( @renewed, $itemnumber );
(-)a/opac/opac-user.pl (-3 / +10 lines)
Lines 193-199 my $overdues_count = 0; Link Here
193
my @overdues;
193
my @overdues;
194
my @issuedat;
194
my @issuedat;
195
my $itemtypes = { map { $_->{itemtype} => $_ } @{ Koha::ItemTypes->search_with_localization->unblessed } };
195
my $itemtypes = { map { $_->{itemtype} => $_ } @{ Koha::ItemTypes->search_with_localization->unblessed } };
196
my $pending_checkouts = $patron->pending_checkouts->search({}, { order_by => [ { -desc => 'date_due' }, { -asc => 'issue_id' } ] });
196
my $pending_checkouts = $patron->pending_checkouts->search(
197
    {},
198
    {
199
        order_by => [ { -desc => 'date_due' }, { -asc => 'issue_id' } ],
200
        prefetch => 'item'
201
    }
202
);
197
my $are_renewable_items = 0;
203
my $are_renewable_items = 0;
198
if ( $pending_checkouts->count ) { # Useless test
204
if ( $pending_checkouts->count ) { # Useless test
199
    while ( my $c = $pending_checkouts->next ) {
205
    while ( my $c = $pending_checkouts->next ) {
Lines 226-232 if ( $pending_checkouts->count ) { # Useless test Link Here
226
        $issue->{rentalfines} = $rental_fines->total_outstanding;
232
        $issue->{rentalfines} = $rental_fines->total_outstanding;
227
233
228
        # check if item is renewable
234
        # check if item is renewable
229
        my ($status,$renewerror,$info) = CanBookBeRenewed( $borrowernumber, $issue->{'itemnumber'} );
235
        my ($status, $renewerror, $info) = CanBookBeRenewed( $patron, $c );
230
        (
236
        (
231
            $issue->{'renewcount'},
237
            $issue->{'renewcount'},
232
            $issue->{'renewsallowed'},
238
            $issue->{'renewsallowed'},
Lines 236-242 if ( $pending_checkouts->count ) { # Useless test Link Here
236
            $issue->{'unseenleft'}
242
            $issue->{'unseenleft'}
237
        ) = GetRenewCount($borrowernumber, $issue->{'itemnumber'});
243
        ) = GetRenewCount($borrowernumber, $issue->{'itemnumber'});
238
        ( $issue->{'renewalfee'}, $issue->{'renewalitemtype'} ) = GetIssuingCharges( $issue->{'itemnumber'}, $borrowernumber );
244
        ( $issue->{'renewalfee'}, $issue->{'renewalitemtype'} ) = GetIssuingCharges( $issue->{'itemnumber'}, $borrowernumber );
239
        $issue->{itemtype_object} = Koha::ItemTypes->find( Koha::Items->find( $issue->{itemnumber} )->effective_itemtype );
245
        $issue->{itemtype_object} = Koha::ItemTypes->find( $c->item->effective_itemtype );
240
        if($status && C4::Context->preference("OpacRenewalAllowed")){
246
        if($status && C4::Context->preference("OpacRenewalAllowed")){
241
            $are_renewable_items = 1;
247
            $are_renewable_items = 1;
242
            $issue->{'status'} = $status;
248
            $issue->{'status'} = $status;
Lines 254-259 if ( $pending_checkouts->count ) { # Useless test Link Here
254
            $issue->{'auto_too_late'}  = 1 if $renewerror eq 'auto_too_late';
260
            $issue->{'auto_too_late'}  = 1 if $renewerror eq 'auto_too_late';
255
            $issue->{'auto_too_much_oweing'}  = 1 if $renewerror eq 'auto_too_much_oweing';
261
            $issue->{'auto_too_much_oweing'}  = 1 if $renewerror eq 'auto_too_much_oweing';
256
            $issue->{'item_denied_renewal'}  = 1 if $renewerror eq 'item_denied_renewal';
262
            $issue->{'item_denied_renewal'}  = 1 if $renewerror eq 'item_denied_renewal';
263
            $issue->{'item_issued_to_other_patron'} = 1 if $renewerror eq 'item_issued_to_other_patron';
257
264
258
            if ( $renewerror eq 'too_soon' ) {
265
            if ( $renewerror eq 'too_soon' ) {
259
                $issue->{'too_soon'}         = 1;
266
                $issue->{'too_soon'}         = 1;
(-)a/opac/sco/sco-main.pl (-5 / +2 lines)
Lines 279-285 if ( $patron && ( $op eq 'renew' ) ) { Link Here
279
    my $item = Koha::Items->find({ barcode => $barcode });
279
    my $item = Koha::Items->find({ barcode => $barcode });
280
280
281
    if ( $patron->checkouts->find( { itemnumber => $item->itemnumber } ) ) {
281
    if ( $patron->checkouts->find( { itemnumber => $item->itemnumber } ) ) {
282
        my ($status,$renewerror) = CanBookBeRenewed( $patron->borrowernumber, $item->itemnumber );
282
        my ($status,$renewerror) = CanBookBeRenewed( $patron, $item->checkout );
283
        if ($status) {
283
        if ($status) {
284
            AddRenewal( $patron->borrowernumber, $item->itemnumber, undef, undef, undef, undef, 1 );
284
            AddRenewal( $patron->borrowernumber, $item->itemnumber, undef, undef, undef, undef, 1 );
285
            push @newissueslist, $barcode;
285
            push @newissueslist, $barcode;
Lines 296-305 if ( $patron) { Link Here
296
    my @checkouts;
296
    my @checkouts;
297
    while ( my $c = $pending_checkouts->next ) {
297
    while ( my $c = $pending_checkouts->next ) {
298
        my $checkout = $c->unblessed_all_relateds;
298
        my $checkout = $c->unblessed_all_relateds;
299
        my ($can_be_renewed, $renew_error) = CanBookBeRenewed(
299
        my ($can_be_renewed, $renew_error) = CanBookBeRenewed( $patron, $c );
300
            $patron->borrowernumber,
301
            $checkout->{itemnumber},
302
        );
303
        $checkout->{can_be_renewed} = $can_be_renewed; # In the future this will be $checkout->can_be_renewed
300
        $checkout->{can_be_renewed} = $can_be_renewed; # In the future this will be $checkout->can_be_renewed
304
        $checkout->{renew_error} = $renew_error;
301
        $checkout->{renew_error} = $renew_error;
305
        $checkout->{overdue} = $c->is_overdue;
302
        $checkout->{overdue} = $c->is_overdue;
(-)a/svc/checkouts (-1 / +3 lines)
Lines 67-72 print $input->header( -type => 'text/plain', -charset => 'UTF-8' ); Link Here
67
my @parameters;
67
my @parameters;
68
my $sql = '
68
my $sql = '
69
    SELECT
69
    SELECT
70
        issues.issue_id,
70
        issues.issuedate,
71
        issues.issuedate,
71
        issues.date_due,
72
        issues.date_due,
72
        issues.date_due < now() as date_due_overdue,
73
        issues.date_due < now() as date_due_overdue,
Lines 154-161 while ( my $c = $sth->fetchrow_hashref() ) { Link Here
154
    my ($charge) = GetIssuingCharges( $c->{itemnumber}, $c->{borrowernumber} );
155
    my ($charge) = GetIssuingCharges( $c->{itemnumber}, $c->{borrowernumber} );
155
    my $fine = GetFine( $c->{itemnumber}, $c->{borrowernumber} );
156
    my $fine = GetFine( $c->{itemnumber}, $c->{borrowernumber} );
156
157
158
    my $checkout_obj = Koha::Checkouts->find( $c->{issue_id} );
157
    my ( $can_renew, $can_renew_error, $info ) =
159
    my ( $can_renew, $can_renew_error, $info ) =
158
      CanBookBeRenewed( $c->{borrowernumber}, $c->{itemnumber} );
160
      CanBookBeRenewed( $checkout_obj->patron, $checkout_obj );
159
    my $can_renew_date =
161
    my $can_renew_date =
160
      $can_renew_error && $can_renew_error eq 'too_soon'
162
      $can_renew_error && $can_renew_error eq 'too_soon'
161
      ? output_pref(
163
      ? output_pref(
(-)a/svc/renew (-1 / +4 lines)
Lines 58-65 $data->{itemnumber} = $itemnumber; Link Here
58
$data->{borrowernumber} = $borrowernumber;
58
$data->{borrowernumber} = $borrowernumber;
59
$data->{branchcode} = $branchcode;
59
$data->{branchcode} = $branchcode;
60
60
61
my $patron = Koha::Patrons->find($borrowernumber);
62
my $item = Koha::Items->find($itemnumber);
63
61
( $data->{renew_okay}, $data->{error} ) =
64
( $data->{renew_okay}, $data->{error} ) =
62
  CanBookBeRenewed( $borrowernumber, $itemnumber, $override_limit );
65
    CanBookBeRenewed( $patron, $item->checkout, $override_limit );
63
66
64
# If we're allowing reserved items to be renewed...
67
# If we're allowing reserved items to be renewed...
65
if ( $data->{error} && $data->{error} eq 'on_reserve' && C4::Context->preference('AllowRenewalOnHoldOverride')) {
68
if ( $data->{error} && $data->{error} eq 'on_reserve' && C4::Context->preference('AllowRenewalOnHoldOverride')) {
(-)a/t/db_dependent/Circulation.t (-178 / +171 lines)
Lines 310-316 subtest "CanBookBeRenewed AllowRenewalIfOtherItemsAvailable multiple borrowers a Link Here
310
    );
310
    );
311
311
312
    # Patrons from three different branches
312
    # Patrons from three different branches
313
    my $patron_borrower = $builder->build_object({ class => 'Koha::Patrons' });
313
    my $patron = $builder->build_object({ class => 'Koha::Patrons' });
314
    my $patron_hold_1   = $builder->build_object({ class => 'Koha::Patrons' });
314
    my $patron_hold_1   = $builder->build_object({ class => 'Koha::Patrons' });
315
    my $patron_hold_2   = $builder->build_object({ class => 'Koha::Patrons' });
315
    my $patron_hold_2   = $builder->build_object({ class => 'Koha::Patrons' });
316
    my $biblio = $builder->build_sample_biblio();
316
    my $biblio = $builder->build_sample_biblio();
Lines 318-324 subtest "CanBookBeRenewed AllowRenewalIfOtherItemsAvailable multiple borrowers a Link Here
318
    # Item at each patron branch
318
    # Item at each patron branch
319
    my $item_1 = $builder->build_sample_item({
319
    my $item_1 = $builder->build_sample_item({
320
        biblionumber => $biblio->biblionumber,
320
        biblionumber => $biblio->biblionumber,
321
        homebranch   => $patron_borrower->branchcode
321
        homebranch   => $patron->branchcode
322
    });
322
    });
323
    my $item_2 = $builder->build_sample_item({
323
    my $item_2 = $builder->build_sample_item({
324
        biblionumber => $biblio->biblionumber,
324
        biblionumber => $biblio->biblionumber,
Lines 329-335 subtest "CanBookBeRenewed AllowRenewalIfOtherItemsAvailable multiple borrowers a Link Here
329
        homebranch   => $patron_hold_1->branchcode
329
        homebranch   => $patron_hold_1->branchcode
330
    });
330
    });
331
331
332
    my $issue = AddIssue( $patron_borrower->unblessed, $item_1->barcode);
332
    my $issue = AddIssue( $patron->unblessed, $item_1->barcode);
333
    my $datedue = dt_from_string( $issue->date_due() );
333
    my $datedue = dt_from_string( $issue->date_due() );
334
    is (defined $issue->date_due(), 1, "Item 1 checked out, due date: " . $issue->date_due() );
334
    is (defined $issue->date_due(), 1, "Item 1 checked out, due date: " . $issue->date_due() );
335
335
Lines 360-372 subtest "CanBookBeRenewed AllowRenewalIfOtherItemsAvailable multiple borrowers a Link Here
360
    );
360
    );
361
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 0 );
361
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 0 );
362
362
363
    my ( $renewokay, $error ) = CanBookBeRenewed($patron_borrower->borrowernumber, $item_1->itemnumber);
363
    my ( $renewokay, $error ) = CanBookBeRenewed($patron, $issue);
364
    is( $renewokay, 0, 'Cannot renew, reserved');
364
    is( $renewokay, 0, 'Cannot renew, reserved');
365
    is( $error, 'on_reserve', 'Cannot renew, reserved (returned error is on_reserve)');
365
    is( $error, 'on_reserve', 'Cannot renew, reserved (returned error is on_reserve)');
366
366
367
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 1 );
367
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 1 );
368
368
369
    ( $renewokay, $error ) = CanBookBeRenewed($patron_borrower->borrowernumber, $item_1->itemnumber);
369
    ( $renewokay, $error ) = CanBookBeRenewed($patron, $issue);
370
    is( $renewokay, 1, 'Can renew, two items available for two holds');
370
    is( $renewokay, 1, 'Can renew, two items available for two holds');
371
    is( $error, undef, 'Can renew, each reserve has an item');
371
    is( $error, undef, 'Can renew, each reserve has an item');
372
372
Lines 374-383 subtest "CanBookBeRenewed AllowRenewalIfOtherItemsAvailable multiple borrowers a Link Here
374
    my $hold = Koha::Holds->find( $reserve_1 );
374
    my $hold = Koha::Holds->find( $reserve_1 );
375
    $hold->itemnumber( $item_1->itemnumber )->store;
375
    $hold->itemnumber( $item_1->itemnumber )->store;
376
376
377
    ( $renewokay, $error ) = CanBookBeRenewed($patron_borrower->borrowernumber, $item_1->itemnumber);
377
    ( $renewokay, $error ) = CanBookBeRenewed($patron, $issue);
378
    is( $renewokay, 0, 'Cannot renew when there is an item specific hold');
378
    is( $renewokay, 0, 'Cannot renew when there is an item specific hold');
379
    is( $error, 'on_reserve', 'Cannot renew, only this item can fill the reserve');
379
    is( $error, 'on_reserve', 'Cannot renew, only this item can fill the reserve');
380
381
};
380
};
382
381
383
subtest "GetIssuingCharges tests" => sub {
382
subtest "GetIssuingCharges tests" => sub {
Lines 470-475 subtest "CanBookBeRenewed tests" => sub { Link Here
470
        surname => 'Renewal',
469
        surname => 'Renewal',
471
        categorycode => $patron_category->{categorycode},
470
        categorycode => $patron_category->{categorycode},
472
        branchcode => $branch,
471
        branchcode => $branch,
472
        autorenew_checkouts => 1,
473
    );
473
    );
474
474
475
    my %reserving_borrower_data = (
475
    my %reserving_borrower_data = (
Lines 500-517 subtest "CanBookBeRenewed tests" => sub { Link Here
500
        categorycode => $patron_category->{categorycode},
500
        categorycode => $patron_category->{categorycode},
501
        branchcode => $branch,
501
        branchcode => $branch,
502
        dateexpiry => dt_from_string->subtract( months => 1 ),
502
        dateexpiry => dt_from_string->subtract( months => 1 ),
503
        autorenew_checkouts => 1,
503
    );
504
    );
504
505
505
    my $renewing_borrowernumber = Koha::Patron->new(\%renewing_borrower_data)->store->borrowernumber;
506
    my $renewing_borrower_obj = Koha::Patron->new(\%renewing_borrower_data)->store;
507
    my $renewing_borrowernumber = $renewing_borrower_obj->borrowernumber;
506
    my $reserving_borrowernumber = Koha::Patron->new(\%reserving_borrower_data)->store->borrowernumber;
508
    my $reserving_borrowernumber = Koha::Patron->new(\%reserving_borrower_data)->store->borrowernumber;
507
    my $hold_waiting_borrowernumber = Koha::Patron->new(\%hold_waiting_borrower_data)->store->borrowernumber;
509
    my $hold_waiting_borrowernumber = Koha::Patron->new(\%hold_waiting_borrower_data)->store->borrowernumber;
508
    my $restricted_borrowernumber = Koha::Patron->new(\%restricted_borrower_data)->store->borrowernumber;
510
    my $restricted_borrower_obj = Koha::Patron->new(\%restricted_borrower_data)->store;
509
    my $expired_borrowernumber = Koha::Patron->new(\%expired_borrower_data)->store->borrowernumber;
510
511
511
    my $renewing_borrower_obj = Koha::Patrons->find( $renewing_borrowernumber );
512
    my $expired_borrower_obj = Koha::Patron->new(\%expired_borrower_data)->store;
512
    my $renewing_borrower = $renewing_borrower_obj->unblessed;
513
    my $restricted_borrower = Koha::Patrons->find( $restricted_borrowernumber )->unblessed;
514
    my $expired_borrower = Koha::Patrons->find( $expired_borrowernumber )->unblessed;
515
513
516
    my $bibitems       = '';
514
    my $bibitems       = '';
517
    my $priority       = '1';
515
    my $priority       = '1';
Lines 521-539 subtest "CanBookBeRenewed tests" => sub { Link Here
521
    my $checkitem      = undef;
519
    my $checkitem      = undef;
522
    my $found          = undef;
520
    my $found          = undef;
523
521
524
    my $issue = AddIssue( $renewing_borrower, $item_1->barcode);
522
    my $issue_1 = AddIssue( $renewing_borrower_obj->unblessed, $item_1->barcode);
525
    my $datedue = dt_from_string( $issue->date_due() );
523
    my $datedue = dt_from_string( $issue_1->date_due() );
526
    is (defined $issue->date_due(), 1, "Item 1 checked out, due date: " . $issue->date_due() );
524
    is (defined $issue_1->date_due(), 1, "Item 1 checked out, due date: " . $issue_1->date_due() );
527
528
    my $issue2 = AddIssue( $renewing_borrower, $item_2->barcode);
529
    $datedue = dt_from_string( $issue->date_due() );
530
    is (defined $issue2, 1, "Item 2 checked out, due date: " . $issue2->date_due());
531
525
526
    my $issue_2 = AddIssue( $renewing_borrower_obj->unblessed, $item_2->barcode);
527
    is (defined $issue_2, 1, "Item 2 checked out, due date: " . $issue_2->date_due());
532
528
533
    my $borrowing_borrowernumber = Koha::Checkouts->find( { itemnumber => $item_1->itemnumber } )->borrowernumber;
529
    my $borrowing_borrowernumber = Koha::Checkouts->find( { itemnumber => $item_1->itemnumber } )->borrowernumber;
534
    is ($borrowing_borrowernumber, $renewing_borrowernumber, "Item checked out to $renewing_borrower->{firstname} $renewing_borrower->{surname}");
530
    is ($borrowing_borrowernumber, $renewing_borrowernumber, "Item checked out to ".$renewing_borrower_obj->firstname." ".$renewing_borrower_obj->surname);
535
531
536
    my ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber, 1);
532
    my ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1, 1);
537
    is( $renewokay, 1, 'Can renew, no holds for this title or item');
533
    is( $renewokay, 1, 'Can renew, no holds for this title or item');
538
534
539
535
Lines 572-580 subtest "CanBookBeRenewed tests" => sub { Link Here
572
        }
568
        }
573
    );
569
    );
574
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 1 );
570
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 1 );
575
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
571
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
576
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
572
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
577
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
573
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_2);
578
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
574
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
579
575
580
576
Lines 592-598 subtest "CanBookBeRenewed tests" => sub { Link Here
592
            found            => $found,
588
            found            => $found,
593
        }
589
        }
594
    );
590
    );
595
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
591
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
596
    is( $renewokay, 0, 'Renewal not possible when single patron\'s holds exceed the number of available items');
592
    is( $renewokay, 0, 'Renewal not possible when single patron\'s holds exceed the number of available items');
597
    Koha::Holds->find($reserve_id)->delete;
593
    Koha::Holds->find($reserve_id)->delete;
598
594
Lines 607-613 subtest "CanBookBeRenewed tests" => sub { Link Here
607
            reservedate    => '1999-01-01',
603
            reservedate    => '1999-01-01',
608
        }
604
        }
609
    );
605
    );
610
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
606
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
611
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
607
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
612
    $hold->delete();
608
    $hold->delete();
613
609
Lines 623-639 subtest "CanBookBeRenewed tests" => sub { Link Here
623
            found          => 'W'
619
            found          => 'W'
624
        }
620
        }
625
    );
621
    );
626
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
622
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
627
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
623
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
628
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
624
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_2);
629
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
625
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
630
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 0 );
626
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 0 );
631
627
632
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
628
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
633
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
629
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
634
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
630
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
635
631
636
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
632
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_2);
637
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
633
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
638
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
634
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
639
635
Lines 662-677 subtest "CanBookBeRenewed tests" => sub { Link Here
662
        }
658
        }
663
    );
659
    );
664
660
665
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber, 1);
661
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1, 1);
666
    is( $renewokay, 0, '(Bug 10663) Cannot renew, item reserved');
662
    is( $renewokay, 0, '(Bug 10663) Cannot renew, item reserved');
667
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, item reserved (returned error is on_reserve)');
663
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, item reserved (returned error is on_reserve)');
668
664
669
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber, 1);
665
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_2, 1);
670
    is( $renewokay, 1, 'Can renew item 2, item-level hold is on item 1');
666
    is( $renewokay, 1, 'Can renew item 2, item-level hold is on item 1');
671
667
672
    # Items can't fill hold for reasons
668
    # Items can't fill hold for reasons
673
    $item_1->notforloan(1)->store;
669
    $issue_1->item->notforloan(1)->store;
674
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber, 1);
670
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1, 1);
675
    is( $renewokay, 0, 'Cannot renew, item is marked not for loan, but an item specific hold always blocks');
671
    is( $renewokay, 0, 'Cannot renew, item is marked not for loan, but an item specific hold always blocks');
676
    $item_1->set({notforloan => 0, itype => $itemtype })->store;
672
    $item_1->set({notforloan => 0, itype => $itemtype })->store;
677
673
Lines 686-698 subtest "CanBookBeRenewed tests" => sub { Link Here
686
            itype            => $itemtype,
682
            itype            => $itemtype,
687
        }
683
        }
688
    );
684
    );
689
    my $datedue5 = AddIssue($restricted_borrower, $item_5->barcode);
685
    my $issue_5 = AddIssue($restricted_borrower_obj->unblessed, $item_5->barcode);
690
    is (defined $datedue5, 1, "Item with date due checked out, due date: $datedue5");
686
    is (defined $issue_5, 1, "Item with date due checked out, due date: ". $issue_5->date_due);
691
687
692
    t::lib::Mocks::mock_preference('RestrictionBlockRenewing','1');
688
    t::lib::Mocks::mock_preference('RestrictionBlockRenewing','1');
693
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
689
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_2);
694
    is( $renewokay, 1, '(Bug 8236), Can renew, user is not restricted');
690
    is( $renewokay, 1, '(Bug 8236), Can renew, user is not restricted');
695
    ( $renewokay, $error ) = CanBookBeRenewed($restricted_borrowernumber, $item_5->itemnumber);
691
    ( $renewokay, $error ) = CanBookBeRenewed($restricted_borrower_obj, $issue_5);
696
    is( $renewokay, 0, '(Bug 8236), Cannot renew, user is restricted');
692
    is( $renewokay, 0, '(Bug 8236), Cannot renew, user is restricted');
697
    is( $error, 'restriction', "Correct error returned");
693
    is( $error, 'restriction', "Correct error returned");
698
694
Lines 715-758 subtest "CanBookBeRenewed tests" => sub { Link Here
715
        }
711
        }
716
    );
712
    );
717
713
718
    my $datedue6 = AddIssue( $renewing_borrower, $item_6->barcode);
714
    my $issue_6 = AddIssue( $renewing_borrower_obj->unblessed, $item_6->barcode);
719
    is (defined $datedue6, 1, "Item 2 checked out, due date: ".$datedue6->date_due);
715
    is (defined $issue_6, 1, "Item 2 checked out, due date: ".$issue_6->date_due);
720
716
721
    my $now = dt_from_string();
717
    my $now = dt_from_string();
722
    my $five_weeks = DateTime::Duration->new(weeks => 5);
718
    my $five_weeks = DateTime::Duration->new(weeks => 5);
723
    my $five_weeks_ago = $now - $five_weeks;
719
    my $five_weeks_ago = $now - $five_weeks;
724
    t::lib::Mocks::mock_preference('finesMode', 'production');
720
    t::lib::Mocks::mock_preference('finesMode', 'production');
725
721
726
    my $passeddatedue1 = AddIssue($renewing_borrower, $item_7->barcode, $five_weeks_ago);
722
    my $issue_7 = AddIssue($renewing_borrower_obj->unblessed, $item_7->barcode, $five_weeks_ago);
727
    is (defined $passeddatedue1, 1, "Item with passed date due checked out, due date: " . $passeddatedue1->date_due);
723
    is (defined $issue_7, 1, "Item with passed date due checked out, due date: " . $issue_7->date_due);
728
724
729
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','allow');
725
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','allow');
730
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_6->itemnumber);
726
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_6);
731
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is not overdue');
727
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is not overdue');
732
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_7->itemnumber);
728
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_7);
733
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is overdue but not pref does not block');
729
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is overdue but not pref does not block');
734
730
735
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','block');
731
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','block');
736
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_6->itemnumber);
732
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_6);
737
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is not overdue but patron has overdues');
733
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is not overdue but patron has overdues');
738
    is( $error, 'overdue', "Correct error returned");
734
    is( $error, 'overdue', "Correct error returned");
739
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_7->itemnumber);
735
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_7);
740
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is overdue so patron has overdues');
736
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is overdue so patron has overdues');
741
    is( $error, 'overdue', "Correct error returned");
737
    is( $error, 'overdue', "Correct error returned");
742
738
743
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','blockitem');
739
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','blockitem');
744
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_6->itemnumber);
740
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_6);
745
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is not overdue');
741
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is not overdue');
746
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_7->itemnumber);
742
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_7);
747
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is overdue');
743
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is overdue');
748
    is( $error, 'overdue', "Correct error returned");
744
    is( $error, 'overdue', "Correct error returned");
749
745
750
    my ( $fine ) = CalcFine( $item_7->unblessed, $renewing_borrower->{categorycode}, $branch, $five_weeks_ago, $now );
746
    my ( $fine ) = CalcFine( $item_7->unblessed, $renewing_borrower_obj->categorycode, $branch, $five_weeks_ago, $now );
751
    C4::Overdues::UpdateFine(
747
    C4::Overdues::UpdateFine(
752
        {
748
        {
753
            issue_id       => $passeddatedue1->id(),
749
            issue_id       => $issue_7->id(),
754
            itemnumber     => $item_7->itemnumber,
750
            itemnumber     => $item_7->itemnumber,
755
            borrowernumber => $renewing_borrower->{borrowernumber},
751
            borrowernumber => $renewing_borrower_obj->borrowernumber,
756
            amount         => $fine,
752
            amount         => $fine,
757
            due            => Koha::DateUtils::output_pref($five_weeks_ago)
753
            due            => Koha::DateUtils::output_pref($five_weeks_ago)
758
        }
754
        }
Lines 783-789 subtest "CanBookBeRenewed tests" => sub { Link Here
783
    my $old_log_size = Koha::ActionLogs->count( \%params_renewal );
779
    my $old_log_size = Koha::ActionLogs->count( \%params_renewal );
784
    my $dt = dt_from_string();
780
    my $dt = dt_from_string();
785
    Time::Fake->offset( $dt->epoch );
781
    Time::Fake->offset( $dt->epoch );
786
    my $datedue1 = AddRenewal( $renewing_borrower->{borrowernumber}, $item_7->itemnumber, $branch );
782
    my $datedue1 = AddRenewal( $renewing_borrower_obj->borrowernumber, $item_7->itemnumber, $branch );
787
    my $new_log_size = Koha::ActionLogs->count( \%params_renewal );
783
    my $new_log_size = Koha::ActionLogs->count( \%params_renewal );
788
    is ($new_log_size, $old_log_size, 'renew log not added because of the syspref RenewalLog');
784
    is ($new_log_size, $old_log_size, 'renew log not added because of the syspref RenewalLog');
789
    isnt (DateTime->compare($datedue1, $dt), 0, "AddRenewal returned a good duedate");
785
    isnt (DateTime->compare($datedue1, $dt), 0, "AddRenewal returned a good duedate");
Lines 792-809 subtest "CanBookBeRenewed tests" => sub { Link Here
792
    t::lib::Mocks::mock_preference('RenewalLog', 1);
788
    t::lib::Mocks::mock_preference('RenewalLog', 1);
793
    $date = output_pref( { dt => dt_from_string(), dateonly => 1, dateformat => 'iso' } );
789
    $date = output_pref( { dt => dt_from_string(), dateonly => 1, dateformat => 'iso' } );
794
    $old_log_size = Koha::ActionLogs->count( \%params_renewal );
790
    $old_log_size = Koha::ActionLogs->count( \%params_renewal );
795
    AddRenewal( $renewing_borrower->{borrowernumber}, $item_7->itemnumber, $branch );
791
    AddRenewal( $renewing_borrower_obj->borrowernumber, $item_7->itemnumber, $branch );
796
    $new_log_size = Koha::ActionLogs->count( \%params_renewal );
792
    $new_log_size = Koha::ActionLogs->count( \%params_renewal );
797
    is ($new_log_size, $old_log_size + 1, 'renew log successfully added');
793
    is ($new_log_size, $old_log_size + 1, 'renew log successfully added');
798
794
799
    my $fines = Koha::Account::Lines->search( { borrowernumber => $renewing_borrower->{borrowernumber}, itemnumber => $item_7->itemnumber } );
795
    my $fines = Koha::Account::Lines->search( { borrowernumber => $renewing_borrower_obj->borrowernumber, itemnumber => $item_7->itemnumber } );
800
    is( $fines->count, 1, 'AddRenewal left fine' );
796
    is( $fines->count, 1, 'AddRenewal left fine' );
801
    is( $fines->next->status, 'RENEWED', 'Fine on renewed item is closed out properly' );
797
    is( $fines->next->status, 'RENEWED', 'Fine on renewed item is closed out properly' );
802
    $fines->delete();
798
    $fines->delete();
803
799
804
    my $old_issue_log_size = Koha::ActionLogs->count( \%params_issue );
800
    my $old_issue_log_size = Koha::ActionLogs->count( \%params_issue );
805
    my $old_renew_log_size = Koha::ActionLogs->count( \%params_renewal );
801
    my $old_renew_log_size = Koha::ActionLogs->count( \%params_renewal );
806
    AddIssue( $renewing_borrower,$item_7->barcode,Koha::DateUtils::output_pref({str=>$datedue6->date_due, dateformat =>'iso'}),0,$date, 0, undef );
802
    AddIssue(
803
        $renewing_borrower_obj->unblessed,
804
        $item_7->barcode,
805
        Koha::DateUtils::output_pref({str=>$issue_6->date_due, dateformat =>'iso'}),
806
        0,
807
        $date,
808
        0,
809
        undef
810
    ); # TODO: Already issued???
807
    $new_log_size = Koha::ActionLogs->count( \%params_renewal );
811
    $new_log_size = Koha::ActionLogs->count( \%params_renewal );
808
    is ($new_log_size, $old_renew_log_size + 1, 'renew log successfully added when renewed via issuing');
812
    is ($new_log_size, $old_renew_log_size + 1, 'renew log successfully added when renewed via issuing');
809
    $new_log_size = Koha::ActionLogs->count( \%params_issue );
813
    $new_log_size = Koha::ActionLogs->count( \%params_issue );
Lines 824-837 subtest "CanBookBeRenewed tests" => sub { Link Here
824
        }
828
        }
825
    );
829
    );
826
830
827
    $issue = AddIssue( $renewing_borrower, $item_4->barcode, undef, undef, undef, undef, { auto_renew => 1 } );
831
    my $issue_4 = AddIssue( $renewing_borrower_obj->unblessed, $item_4->barcode, undef, undef, undef, undef, { auto_renew => 1 } );
828
    my $info;
832
    my $info;
829
    ( $renewokay, $error, $info ) =
833
    ( $renewokay, $error, $info ) =
830
      CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
834
      CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
831
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
835
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
832
    is( $error, 'auto_too_soon',
836
    is( $error, 'auto_too_soon',
833
        'Bug 14101: Cannot renew, renewal is automatic and premature, "No renewal before" = undef (returned code is auto_too_soon)' );
837
        'Bug 14101: Cannot renew, renewal is automatic and premature, "No renewal before" = undef (returned code is auto_too_soon)' );
834
    is( $info->{soonest_renew_date} , dt_from_string($issue->date_due), "Due date is returned as earliest renewal date when error is 'auto_too_soon'" );
838
    is( $info->{soonest_renew_date} , dt_from_string($issue_4->date_due), "Due date is returned as earliest renewal date when error is 'auto_too_soon'" );
835
    AddReserve(
839
    AddReserve(
836
        {
840
        {
837
            branchcode       => $branch,
841
            branchcode       => $branch,
Lines 847-876 subtest "CanBookBeRenewed tests" => sub { Link Here
847
            found            => $found
851
            found            => $found
848
        }
852
        }
849
    );
853
    );
850
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
854
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
851
    is( $renewokay, 0, 'Still should not be able to renew' );
855
    is( $renewokay, 0, 'Still should not be able to renew' );
852
    is( $error, 'on_reserve', 'returned code is on_reserve, reserve checked when not checking for cron' );
856
    is( $error, 'on_reserve', 'returned code is on_reserve, reserve checked when not checking for cron' );
853
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber, undef, 1 );
857
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4, undef, 1 );
854
    is( $renewokay, 0, 'Still should not be able to renew' );
858
    is( $renewokay, 0, 'Still should not be able to renew' );
855
    is( $error, 'auto_too_soon', 'returned code is auto_too_soon, reserve not checked when checking for cron' );
859
    is( $error, 'auto_too_soon', 'returned code is auto_too_soon, reserve not checked when checking for cron' );
856
    is( $info->{soonest_renew_date}, dt_from_string($issue->date_due), "Due date is returned as earliest renewal date when error is 'auto_too_soon'" );
860
    is( $info->{soonest_renew_date}, dt_from_string($issue_4->date_due), "Due date is returned as earliest renewal date when error is 'auto_too_soon'" );
857
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber, 1 );
861
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4, 1 );
858
    is( $renewokay, 0, 'Still should not be able to renew' );
862
    is( $renewokay, 0, 'Still should not be able to renew' );
859
    is( $error, 'on_reserve', 'returned code is on_reserve, auto_too_soon limit is overridden' );
863
    is( $error, 'on_reserve', 'returned code is on_reserve, auto_too_soon limit is overridden' );
860
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber, 1, 1 );
864
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4, 1, 1 );
861
    is( $renewokay, 0, 'Still should not be able to renew' );
865
    is( $renewokay, 0, 'Still should not be able to renew' );
862
    is( $error, 'on_reserve', 'returned code is on_reserve, auto_too_soon limit is overridden' );
866
    is( $error, 'on_reserve', 'returned code is on_reserve, auto_too_soon limit is overridden' );
863
    $dbh->do('UPDATE circulation_rules SET rule_value = 0 where rule_name = "norenewalbefore"');
867
    $dbh->do('UPDATE circulation_rules SET rule_value = 0 where rule_name = "norenewalbefore"');
864
    Koha::Cache::Memory::Lite->flush();
868
    Koha::Cache::Memory::Lite->flush();
865
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber, 1 );
869
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4, 1 );
866
    is( $renewokay, 0, 'Still should not be able to renew' );
870
    is( $renewokay, 0, 'Still should not be able to renew' );
867
    is( $error, 'on_reserve', 'returned code is on_reserve, auto_renew only happens if not on reserve' );
871
    is( $error, 'on_reserve', 'returned code is on_reserve, auto_renew only happens if not on reserve' );
868
    ModReserveCancelAll($item_4->itemnumber, $reserving_borrowernumber);
872
    ModReserveCancelAll($item_4->itemnumber, $reserving_borrowernumber);
869
873
870
874
    $renewing_borrower_obj = Koha::Patrons->find($renewing_borrower_obj->borrowernumber);
871
872
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
875
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
873
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
876
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
874
    is( $renewokay, 1, 'No renewal before is undef, but patron opted out of auto_renewal' );
877
    is( $renewokay, 1, 'No renewal before is undef, but patron opted out of auto_renewal' );
875
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
878
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
876
879
Lines 887-912 subtest "CanBookBeRenewed tests" => sub { Link Here
887
        }
890
        }
888
    );
891
    );
889
892
890
    ( $renewokay, $error, $info ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
893
    ( $renewokay, $error, $info ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
891
    is( $renewokay, 0, 'Bug 7413: Cannot renew, renewal is premature');
894
    is( $renewokay, 0, 'Bug 7413: Cannot renew, renewal is premature');
892
    is( $error, 'too_soon', 'Bug 7413: Cannot renew, renewal is premature (returned code is too_soon)');
895
    is( $error, 'too_soon', 'Bug 7413: Cannot renew, renewal is premature (returned code is too_soon)');
893
    is( $info->{soonest_renew_date}, dt_from_string($issue->date_due)->subtract( days => 7 ), "Soonest renew date returned when error is 'too_soon'");
896
    is( $info->{soonest_renew_date}, dt_from_string($issue_1->date_due)->subtract( days => 7 ), "Soonest renew date returned when error is 'too_soon'");
894
897
895
    # Bug 14101
898
    # Bug 14101
896
    # Test premature automatic renewal
899
    # Test premature automatic renewal
897
    ( $renewokay, $error, $info ) =
900
    ( $renewokay, $error, $info ) =
898
      CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
901
      CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
899
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
902
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
900
    is( $error, 'auto_too_soon',
903
    is( $error, 'auto_too_soon',
901
        'Bug 14101: Cannot renew, renewal is automatic and premature (returned code is auto_too_soon)'
904
        'Bug 14101: Cannot renew, renewal is automatic and premature (returned code is auto_too_soon)'
902
    );
905
    );
903
    is( $info->{soonest_renew_date}, dt_from_string($issue->date_due)->subtract( days => 7 ), "Soonest renew date returned when error is 'auto_too_soon'");
906
    is( $info->{soonest_renew_date}, dt_from_string($issue_4->date_due)->subtract( days => 7 ), "Soonest renew date returned when error is 'auto_too_soon'");
904
907
905
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
908
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
906
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
909
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
907
    is( $renewokay, 0, 'No renewal before is 7, patron opted out of auto_renewal still cannot renew early' );
910
    is( $renewokay, 0, 'No renewal before is 7, patron opted out of auto_renewal still cannot renew early' );
908
    is( $error, 'too_soon', 'Error is too_soon, no auto' );
911
    is( $error, 'too_soon', 'Error is too_soon, no auto' );
909
    is( $info->{soonest_renew_date}, dt_from_string($issue->date_due)->subtract( days => 7 ), "Soonest renew date returned when error is 'too_soon'");
912
    is( $info->{soonest_renew_date}, dt_from_string($issue_4->date_due)->subtract( days => 7 ), "Soonest renew date returned when error is 'too_soon'");
910
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
913
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
911
914
912
    # Change policy so that loans can only be renewed exactly on due date (0 days prior to due date)
915
    # Change policy so that loans can only be renewed exactly on due date (0 days prior to due date)
Lines 914-931 subtest "CanBookBeRenewed tests" => sub { Link Here
914
    $dbh->do(q{UPDATE circulation_rules SET rule_value = '0' WHERE rule_name = 'norenewalbefore'});
917
    $dbh->do(q{UPDATE circulation_rules SET rule_value = '0' WHERE rule_name = 'norenewalbefore'});
915
    Koha::Cache::Memory::Lite->flush();
918
    Koha::Cache::Memory::Lite->flush();
916
    ( $renewokay, $error, $info ) =
919
    ( $renewokay, $error, $info ) =
917
      CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
920
      CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
918
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
921
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
919
    is( $error, 'auto_too_soon',
922
    is( $error, 'auto_too_soon',
920
        'Bug 14101: Cannot renew, renewal is automatic and premature, "No renewal before" = 0 (returned code is auto_too_soon)'
923
        'Bug 14101: Cannot renew, renewal is automatic and premature, "No renewal before" = 0 (returned code is auto_too_soon)'
921
    );
924
    );
922
    is( $info->{soonest_renew_date}, dt_from_string($issue->date_due), "Soonest renew date returned when error is 'auto_too_soon'");
925
    is( $info->{soonest_renew_date}, dt_from_string($issue_4->date_due), "Soonest renew date returned when error is 'auto_too_soon'");
923
926
924
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
927
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
925
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
928
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
926
    is( $renewokay, 0, 'No renewal before is 0, patron opted out of auto_renewal still cannot renew early' );
929
    is( $renewokay, 0, 'No renewal before is 0, patron opted out of auto_renewal still cannot renew early' );
927
    is( $error, 'too_soon', 'Error is too_soon, no auto' );
930
    is( $error, 'too_soon', 'Error is too_soon, no auto' );
928
    is( $info->{soonest_renew_date}, dt_from_string($issue->date_due), "Soonest renew date returned when error is 'auto_too_soon'");
931
    is( $info->{soonest_renew_date}, dt_from_string($issue_4->date_due), "Soonest renew date returned when error is 'auto_too_soon'");
929
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
932
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
930
933
931
    # Change policy so that loans can be renewed 99 days prior to the due date
934
    # Change policy so that loans can be renewed 99 days prior to the due date
Lines 933-946 subtest "CanBookBeRenewed tests" => sub { Link Here
933
    $dbh->do(q{UPDATE circulation_rules SET rule_value = '99' WHERE rule_name = 'norenewalbefore'});
936
    $dbh->do(q{UPDATE circulation_rules SET rule_value = '99' WHERE rule_name = 'norenewalbefore'});
934
    Koha::Cache::Memory::Lite->flush();
937
    Koha::Cache::Memory::Lite->flush();
935
    ( $renewokay, $error ) =
938
    ( $renewokay, $error ) =
936
      CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
939
      CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
937
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic' );
940
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic' );
938
    is( $error, 'auto_renew',
941
    is( $error, 'auto_renew',
939
        'Bug 14101: Cannot renew, renewal is automatic (returned code is auto_renew)'
942
        'Bug 14101: Cannot renew, renewal is automatic (returned code is auto_renew)'
940
    );
943
    );
941
944
942
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
945
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
943
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
946
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
944
    is( $renewokay, 1, 'No renewal before is 99, patron opted out of auto_renewal so can renew' );
947
    is( $renewokay, 1, 'No renewal before is 99, patron opted out of auto_renewal so can renew' );
945
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
948
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
946
949
Lines 955-961 subtest "CanBookBeRenewed tests" => sub { Link Here
955
958
956
        my $ten_days_before = dt_from_string->add( days => -10 );
959
        my $ten_days_before = dt_from_string->add( days => -10 );
957
        my $ten_days_ahead  = dt_from_string->add( days => 10 );
960
        my $ten_days_ahead  = dt_from_string->add( days => 10 );
958
        AddIssue( $renewing_borrower, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
961
        my $issue = AddIssue( $renewing_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
959
962
960
        Koha::CirculationRules->set_rules(
963
        Koha::CirculationRules->set_rules(
961
            {
964
            {
Lines 969-975 subtest "CanBookBeRenewed tests" => sub { Link Here
969
            }
972
            }
970
        );
973
        );
971
        ( $renewokay, $error ) =
974
        ( $renewokay, $error ) =
972
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
975
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
973
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
976
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
974
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
977
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
975
978
Lines 985-991 subtest "CanBookBeRenewed tests" => sub { Link Here
985
            }
988
            }
986
        );
989
        );
987
        ( $renewokay, $error ) =
990
        ( $renewokay, $error ) =
988
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
991
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
989
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
992
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
990
        is( $error, 'auto_too_late', 'Cannot auto renew, too late - no_auto_renewal_after is inclusive(returned code is auto_too_late)' );
993
        is( $error, 'auto_too_late', 'Cannot auto renew, too late - no_auto_renewal_after is inclusive(returned code is auto_too_late)' );
991
994
Lines 1001-1007 subtest "CanBookBeRenewed tests" => sub { Link Here
1001
            }
1004
            }
1002
        );
1005
        );
1003
        ( $renewokay, $error ) =
1006
        ( $renewokay, $error ) =
1004
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1007
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1005
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1008
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1006
        is( $error, 'auto_too_soon', 'Cannot auto renew, too soon - no_auto_renewal_after is defined(returned code is auto_too_soon)' );
1009
        is( $error, 'auto_too_soon', 'Cannot auto renew, too soon - no_auto_renewal_after is defined(returned code is auto_too_soon)' );
1007
1010
Lines 1017-1023 subtest "CanBookBeRenewed tests" => sub { Link Here
1017
            }
1020
            }
1018
        );
1021
        );
1019
        ( $renewokay, $error ) =
1022
        ( $renewokay, $error ) =
1020
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1023
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1021
        is( $renewokay, 0,            'Do not renew, renewal is automatic' );
1024
        is( $renewokay, 0,            'Do not renew, renewal is automatic' );
1022
        is( $error,     'auto_renew', 'Cannot renew, renew is automatic' );
1025
        is( $error,     'auto_renew', 'Cannot renew, renew is automatic' );
1023
1026
Lines 1034-1040 subtest "CanBookBeRenewed tests" => sub { Link Here
1034
            }
1037
            }
1035
        );
1038
        );
1036
        ( $renewokay, $error ) =
1039
        ( $renewokay, $error ) =
1037
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1040
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1038
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1041
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1039
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
1042
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
1040
1043
Lines 1051-1057 subtest "CanBookBeRenewed tests" => sub { Link Here
1051
            }
1054
            }
1052
        );
1055
        );
1053
        ( $renewokay, $error ) =
1056
        ( $renewokay, $error ) =
1054
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1057
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1055
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1058
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1056
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
1059
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
1057
1060
Lines 1068-1074 subtest "CanBookBeRenewed tests" => sub { Link Here
1068
            }
1071
            }
1069
        );
1072
        );
1070
        ( $renewokay, $error ) =
1073
        ( $renewokay, $error ) =
1071
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1074
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1072
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1075
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1073
        is( $error, 'auto_renew', 'Cannot renew, renew is automatic' );
1076
        is( $error, 'auto_renew', 'Cannot renew, renew is automatic' );
1074
    };
1077
    };
Lines 1084-1090 subtest "CanBookBeRenewed tests" => sub { Link Here
1084
1087
1085
        my $ten_days_before = dt_from_string->add( days => -10 );
1088
        my $ten_days_before = dt_from_string->add( days => -10 );
1086
        my $ten_days_ahead = dt_from_string->add( days => 10 );
1089
        my $ten_days_ahead = dt_from_string->add( days => 10 );
1087
        AddIssue( $renewing_borrower, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1090
        my $issue = AddIssue( $renewing_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1088
1091
1089
        Koha::CirculationRules->set_rules(
1092
        Koha::CirculationRules->set_rules(
1090
            {
1093
            {
Lines 1112-1118 subtest "CanBookBeRenewed tests" => sub { Link Here
1112
            }
1115
            }
1113
        )->status('RETURNED')->store;
1116
        )->status('RETURNED')->store;
1114
        ( $renewokay, $error ) =
1117
        ( $renewokay, $error ) =
1115
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1118
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1116
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1119
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1117
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, patron has 5' );
1120
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, patron has 5' );
1118
1121
Lines 1126-1132 subtest "CanBookBeRenewed tests" => sub { Link Here
1126
            }
1129
            }
1127
        )->status('RETURNED')->store;
1130
        )->status('RETURNED')->store;
1128
        ( $renewokay, $error ) =
1131
        ( $renewokay, $error ) =
1129
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1132
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1130
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1133
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1131
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, patron has 10' );
1134
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, patron has 10' );
1132
1135
Lines 1140-1146 subtest "CanBookBeRenewed tests" => sub { Link Here
1140
            }
1143
            }
1141
        )->status('RETURNED')->store;
1144
        )->status('RETURNED')->store;
1142
        ( $renewokay, $error ) =
1145
        ( $renewokay, $error ) =
1143
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1146
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1144
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1147
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1145
        is( $error, 'auto_too_much_oweing', 'Cannot auto renew, OPACFineNoRenewals=10, patron has 15' );
1148
        is( $error, 'auto_too_much_oweing', 'Cannot auto renew, OPACFineNoRenewals=10, patron has 15' );
1146
1149
Lines 1153-1165 subtest "CanBookBeRenewed tests" => sub { Link Here
1153
            }
1156
            }
1154
        )->store;
1157
        )->store;
1155
        ( $renewokay, $error ) =
1158
        ( $renewokay, $error ) =
1156
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1159
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1157
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1160
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1158
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, OPACFineNoRenewalsIncludeCredit=1, patron has 15 debt, 5 credit'  );
1161
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, OPACFineNoRenewalsIncludeCredit=1, patron has 15 debt, 5 credit'  );
1159
1162
1160
        C4::Context->set_preference('OPACFineNoRenewalsIncludeCredit','0');
1163
        C4::Context->set_preference('OPACFineNoRenewalsIncludeCredit','0');
1161
        ( $renewokay, $error ) =
1164
        ( $renewokay, $error ) =
1162
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1165
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1163
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1166
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1164
        is( $error, 'auto_too_much_oweing', 'Cannot auto renew, OPACFineNoRenewals=10, OPACFineNoRenewalsIncludeCredit=1, patron has 15 debt, 5 credit'  );
1167
        is( $error, 'auto_too_much_oweing', 'Cannot auto renew, OPACFineNoRenewals=10, OPACFineNoRenewalsIncludeCredit=1, patron has 15 debt, 5 credit'  );
1165
1168
Lines 1194-1230 subtest "CanBookBeRenewed tests" => sub { Link Here
1194
        # Patron is expired and BlockExpiredPatronOpacActions=0
1197
        # Patron is expired and BlockExpiredPatronOpacActions=0
1195
        # => auto renew is allowed
1198
        # => auto renew is allowed
1196
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 0);
1199
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 0);
1197
        my $patron = $expired_borrower;
1200
        my $issue = AddIssue( $expired_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1198
        my $checkout = AddIssue( $patron, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1199
        ( $renewokay, $error ) =
1201
        ( $renewokay, $error ) =
1200
          CanBookBeRenewed( $patron->{borrowernumber}, $item_to_auto_renew->itemnumber );
1202
          CanBookBeRenewed( $expired_borrower_obj, $issue );
1201
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1203
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1202
        is( $error, 'auto_renew', 'Can auto renew, patron is expired but BlockExpiredPatronOpacActions=0' );
1204
        is( $error, 'auto_renew', 'Can auto renew, patron is expired but BlockExpiredPatronOpacActions=0' );
1203
        Koha::Checkouts->find( $checkout->issue_id )->delete;
1205
        Koha::Checkouts->find( $issue->issue_id )->delete;
1204
1206
1205
1207
1206
        # Patron is expired and BlockExpiredPatronOpacActions=1
1208
        # Patron is expired and BlockExpiredPatronOpacActions=1
1207
        # => auto renew is not allowed
1209
        # => auto renew is not allowed
1208
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 1);
1210
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 1);
1209
        $patron = $expired_borrower;
1211
        $issue = AddIssue( $expired_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1210
        $checkout = AddIssue( $patron, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1211
        ( $renewokay, $error ) =
1212
        ( $renewokay, $error ) =
1212
          CanBookBeRenewed( $patron->{borrowernumber}, $item_to_auto_renew->itemnumber );
1213
          CanBookBeRenewed( $expired_borrower_obj, $issue );
1213
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1214
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1214
        is( $error, 'auto_account_expired', 'Can not auto renew, lockExpiredPatronOpacActions=1 and patron is expired' );
1215
        is( $error, 'auto_account_expired', 'Can not auto renew, lockExpiredPatronOpacActions=1 and patron is expired' );
1215
        Koha::Checkouts->find( $checkout->issue_id )->delete;
1216
        $issue->delete;
1216
1217
1217
1218
        # Patron is not expired and BlockExpiredPatronOpacActions=1
1218
        # Patron is not expired and BlockExpiredPatronOpacActions=1
1219
        # => auto renew is allowed
1219
        # => auto renew is allowed
1220
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 1);
1220
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 1);
1221
        $patron = $renewing_borrower;
1221
        $issue = AddIssue( $renewing_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1222
        $checkout = AddIssue( $patron, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1223
        ( $renewokay, $error ) =
1222
        ( $renewokay, $error ) =
1224
          CanBookBeRenewed( $patron->{borrowernumber}, $item_to_auto_renew->itemnumber );
1223
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1225
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1224
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1226
        is( $error, 'auto_renew', 'Can auto renew, BlockExpiredPatronOpacActions=1 but patron is not expired' );
1225
        is( $error, 'auto_renew', 'Can auto renew, BlockExpiredPatronOpacActions=1 but patron is not expired' );
1227
        Koha::Checkouts->find( $checkout->issue_id )->delete;
1226
        $issue->delete;
1228
    };
1227
    };
1229
1228
1230
    subtest "GetLatestAutoRenewDate" => sub {
1229
    subtest "GetLatestAutoRenewDate" => sub {
Lines 1238-1244 subtest "CanBookBeRenewed tests" => sub { Link Here
1238
1237
1239
        my $ten_days_before = dt_from_string->add( days => -10 );
1238
        my $ten_days_before = dt_from_string->add( days => -10 );
1240
        my $ten_days_ahead  = dt_from_string->add( days => 10 );
1239
        my $ten_days_ahead  = dt_from_string->add( days => 10 );
1241
        AddIssue( $renewing_borrower, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1240
        my $issue = AddIssue( $renewing_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1242
        Koha::CirculationRules->set_rules(
1241
        Koha::CirculationRules->set_rules(
1243
            {
1242
            {
1244
                categorycode => undef,
1243
                categorycode => undef,
Lines 1251-1257 subtest "CanBookBeRenewed tests" => sub { Link Here
1251
                }
1250
                }
1252
            }
1251
            }
1253
        );
1252
        );
1254
        my $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1253
        my $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrower_obj, $issue );
1255
        is( $latest_auto_renew_date, undef, 'GetLatestAutoRenewDate should return undef if no_auto_renewal_after or no_auto_renewal_after_hard_limit are not defined' );
1254
        is( $latest_auto_renew_date, undef, 'GetLatestAutoRenewDate should return undef if no_auto_renewal_after or no_auto_renewal_after_hard_limit are not defined' );
1256
        my $five_days_before = dt_from_string->add( days => -5 );
1255
        my $five_days_before = dt_from_string->add( days => -5 );
1257
        Koha::CirculationRules->set_rules(
1256
        Koha::CirculationRules->set_rules(
Lines 1266-1272 subtest "CanBookBeRenewed tests" => sub { Link Here
1266
                }
1265
                }
1267
            }
1266
            }
1268
        );
1267
        );
1269
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1268
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrower_obj,, $issue );
1270
        is( $latest_auto_renew_date->truncate( to => 'minute' ),
1269
        is( $latest_auto_renew_date->truncate( to => 'minute' ),
1271
            $five_days_before->truncate( to => 'minute' ),
1270
            $five_days_before->truncate( to => 'minute' ),
1272
            'GetLatestAutoRenewDate should return -5 days if no_auto_renewal_after = 5 and date_due is 10 days before'
1271
            'GetLatestAutoRenewDate should return -5 days if no_auto_renewal_after = 5 and date_due is 10 days before'
Lines 1288-1294 subtest "CanBookBeRenewed tests" => sub { Link Here
1288
                }
1287
                }
1289
            }
1288
            }
1290
        );
1289
        );
1291
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1290
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrower_obj, $issue );
1292
        is( $latest_auto_renew_date->truncate( to => 'minute' ),
1291
        is( $latest_auto_renew_date->truncate( to => 'minute' ),
1293
            $five_days_ahead->truncate( to => 'minute' ),
1292
            $five_days_ahead->truncate( to => 'minute' ),
1294
            'GetLatestAutoRenewDate should return +5 days if no_auto_renewal_after = 15 and date_due is 10 days before'
1293
            'GetLatestAutoRenewDate should return +5 days if no_auto_renewal_after = 15 and date_due is 10 days before'
Lines 1306-1312 subtest "CanBookBeRenewed tests" => sub { Link Here
1306
                }
1305
                }
1307
            }
1306
            }
1308
        );
1307
        );
1309
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1308
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrower_obj, $issue );
1310
        is( $latest_auto_renew_date->truncate( to => 'day' ),
1309
        is( $latest_auto_renew_date->truncate( to => 'day' ),
1311
            $two_days_ahead->truncate( to => 'day' ),
1310
            $two_days_ahead->truncate( to => 'day' ),
1312
            'GetLatestAutoRenewDate should return +2 days if no_auto_renewal_after_hard_limit is defined and not no_auto_renewal_after'
1311
            'GetLatestAutoRenewDate should return +2 days if no_auto_renewal_after_hard_limit is defined and not no_auto_renewal_after'
Lines 1323-1329 subtest "CanBookBeRenewed tests" => sub { Link Here
1323
                }
1322
                }
1324
            }
1323
            }
1325
        );
1324
        );
1326
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1325
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrower_obj, $issue );
1327
        is( $latest_auto_renew_date->truncate( to => 'day' ),
1326
        is( $latest_auto_renew_date->truncate( to => 'day' ),
1328
            $two_days_ahead->truncate( to => 'day' ),
1327
            $two_days_ahead->truncate( to => 'day' ),
1329
            'GetLatestAutoRenewDate should return +2 days if no_auto_renewal_after_hard_limit is < no_auto_renewal_after'
1328
            'GetLatestAutoRenewDate should return +2 days if no_auto_renewal_after_hard_limit is < no_auto_renewal_after'
Lines 1345-1351 subtest "CanBookBeRenewed tests" => sub { Link Here
1345
        }
1344
        }
1346
    );
1345
    );
1347
1346
1348
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
1347
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
1349
    is( $renewokay, 0, 'Cannot renew, 0 renewals allowed');
1348
    is( $renewokay, 0, 'Cannot renew, 0 renewals allowed');
1350
    is( $error, 'too_many', 'Cannot renew, 0 renewals allowed (returned code is too_many)');
1349
    is( $error, 'too_many', 'Cannot renew, 0 renewals allowed (returned code is too_many)');
1351
1350
Lines 1362-1369 subtest "CanBookBeRenewed tests" => sub { Link Here
1362
        }
1361
        }
1363
    );
1362
    );
1364
    t::lib::Mocks::mock_preference('UnseenRenewals', 1);
1363
    t::lib::Mocks::mock_preference('UnseenRenewals', 1);
1365
    $dbh->do('UPDATE issues SET unseen_renewals = 2 where borrowernumber = ? AND itemnumber = ?', undef, ($renewing_borrowernumber, $item_1->itemnumber));
1364
    $issue_1->unseen_renewals(2)->store;
1366
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
1365
1366
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
1367
    is( $renewokay, 0, 'Cannot renew, 0 unseen renewals allowed');
1367
    is( $renewokay, 0, 'Cannot renew, 0 unseen renewals allowed');
1368
    is( $error, 'too_unseen', 'Cannot renew, returned code is too_unseen');
1368
    is( $error, 'too_unseen', 'Cannot renew, returned code is too_unseen');
1369
    Koha::CirculationRules->set_rules(
1369
    Koha::CirculationRules->set_rules(
Lines 1385-1405 subtest "CanBookBeRenewed tests" => sub { Link Here
1385
1385
1386
    C4::Overdues::UpdateFine(
1386
    C4::Overdues::UpdateFine(
1387
        {
1387
        {
1388
            issue_id       => $issue->id(),
1388
            issue_id       => $issue_1->id(),
1389
            itemnumber     => $item_1->itemnumber,
1389
            itemnumber     => $item_1->itemnumber,
1390
            borrowernumber => $renewing_borrower->{borrowernumber},
1390
            borrowernumber => $renewing_borrower_obj->borrowernumber,
1391
            amount         => 15.00,
1391
            amount         => 15.00,
1392
            type           => q{},
1392
            type           => q{},
1393
            due            => Koha::DateUtils::output_pref($datedue)
1393
            due            => Koha::DateUtils::output_pref($datedue)
1394
        }
1394
        }
1395
    );
1395
    );
1396
1396
1397
    my $line = Koha::Account::Lines->search({ borrowernumber => $renewing_borrower->{borrowernumber} })->next();
1397
    my $line = Koha::Account::Lines->search({ borrowernumber => $renewing_borrower_obj->borrowernumber })->next();
1398
    is( $line->debit_type_code, 'OVERDUE', 'Account line type is OVERDUE' );
1398
    is( $line->debit_type_code, 'OVERDUE', 'Account line type is OVERDUE' );
1399
    is( $line->status, 'UNRETURNED', 'Account line status is UNRETURNED' );
1399
    is( $line->status, 'UNRETURNED', 'Account line status is UNRETURNED' );
1400
    is( $line->amountoutstanding+0, 15, 'Account line amount outstanding is 15.00' );
1400
    is( $line->amountoutstanding+0, 15, 'Account line amount outstanding is 15.00' );
1401
    is( $line->amount+0, 15, 'Account line amount is 15.00' );
1401
    is( $line->amount+0, 15, 'Account line amount is 15.00' );
1402
    is( $line->issue_id, $issue->id, 'Account line issue id matches' );
1402
    is( $line->issue_id, $issue_1->id, 'Account line issue id matches' );
1403
1403
1404
    my $offset = Koha::Account::Offsets->search({ debit_id => $line->id })->next();
1404
    my $offset = Koha::Account::Offsets->search({ debit_id => $line->id })->next();
1405
    is( $offset->type, 'CREATE', 'Account offset type is CREATE' );
1405
    is( $offset->type, 'CREATE', 'Account offset type is CREATE' );
Lines 1421-1427 subtest "CanBookBeRenewed tests" => sub { Link Here
1421
1421
1422
    my $total_due = $dbh->selectrow_array(
1422
    my $total_due = $dbh->selectrow_array(
1423
        'SELECT SUM( amountoutstanding ) FROM accountlines WHERE borrowernumber = ?',
1423
        'SELECT SUM( amountoutstanding ) FROM accountlines WHERE borrowernumber = ?',
1424
        undef, $renewing_borrower->{borrowernumber}
1424
        undef, $renewing_borrower_obj->borrowernumber
1425
    );
1425
    );
1426
1426
1427
    is( $total_due+0, 15, 'Borrower only charged replacement fee with both WhenLostForgiveFine and WhenLostChargeReplacementFee enabled' );
1427
    is( $total_due+0, 15, 'Borrower only charged replacement fee with both WhenLostForgiveFine and WhenLostChargeReplacementFee enabled' );
Lines 1430-1438 subtest "CanBookBeRenewed tests" => sub { Link Here
1430
1430
1431
    C4::Overdues::UpdateFine(
1431
    C4::Overdues::UpdateFine(
1432
        {
1432
        {
1433
            issue_id       => $issue2->id(),
1433
            issue_id       => $issue_2->id(),
1434
            itemnumber     => $item_2->itemnumber,
1434
            itemnumber     => $item_2->itemnumber,
1435
            borrowernumber => $renewing_borrower->{borrowernumber},
1435
            borrowernumber => $renewing_borrower_obj->borrowernumber,
1436
            amount         => 15.00,
1436
            amount         => 15.00,
1437
            type           => q{},
1437
            type           => q{},
1438
            due            => Koha::DateUtils::output_pref($datedue)
1438
            due            => Koha::DateUtils::output_pref($datedue)
Lines 1447-1453 subtest "CanBookBeRenewed tests" => sub { Link Here
1447
1447
1448
    $total_due = $dbh->selectrow_array(
1448
    $total_due = $dbh->selectrow_array(
1449
        'SELECT SUM( amountoutstanding ) FROM accountlines WHERE borrowernumber = ?',
1449
        'SELECT SUM( amountoutstanding ) FROM accountlines WHERE borrowernumber = ?',
1450
        undef, $renewing_borrower->{borrowernumber}
1450
        undef, $renewing_borrower_obj->borrowernumber
1451
    );
1451
    );
1452
1452
1453
    ok( $total_due == 15, 'Borrower only charged fine with both WhenLostForgiveFine and WhenLostChargeReplacementFee disabled' );
1453
    ok( $total_due == 15, 'Borrower only charged fine with both WhenLostForgiveFine and WhenLostChargeReplacementFee disabled' );
Lines 1485-1495 subtest "CanBookBeRenewed tests" => sub { Link Here
1485
        },
1485
        },
1486
    });
1486
    });
1487
    my $recall_borrower = $builder->build_object({ class => 'Koha::Patrons' });
1487
    my $recall_borrower = $builder->build_object({ class => 'Koha::Patrons' });
1488
    my $recall_biblio = $builder->build_object({ class => 'Koha::Biblios' });
1488
    my $recall_biblio = $builder->build_sample_biblio();
1489
    my $recall_item1 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $recall_biblio->biblionumber } });
1489
    my $recall_item1 = $builder->build_sample_item({ biblionumber => $recall_biblio->biblionumber });
1490
    my $recall_item2 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $recall_biblio->biblionumber } });
1490
    my $recall_item2 = $builder->build_sample_item({ biblionumber => $recall_biblio->biblionumber });
1491
1491
1492
    AddIssue( $renewing_borrower, $recall_item1->barcode );
1492
    my $recall_issue = AddIssue( $renewing_borrower_obj->unblessed, $recall_item1->barcode );
1493
1493
1494
    # item-level and this item: renewal not allowed
1494
    # item-level and this item: renewal not allowed
1495
    my $recall = Koha::Recall->new({
1495
    my $recall = Koha::Recall->new({
Lines 1499-1505 subtest "CanBookBeRenewed tests" => sub { Link Here
1499
        pickup_library_id => $recall_borrower->branchcode,
1499
        pickup_library_id => $recall_borrower->branchcode,
1500
        item_level => 1,
1500
        item_level => 1,
1501
    })->store;
1501
    })->store;
1502
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1502
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $recall_issue );
1503
    is( $error, 'recalled', 'Cannot renew item that has been recalled' );
1503
    is( $error, 'recalled', 'Cannot renew item that has been recalled' );
1504
    $recall->set_cancelled;
1504
    $recall->set_cancelled;
1505
1505
Lines 1511-1517 subtest "CanBookBeRenewed tests" => sub { Link Here
1511
        pickup_library_id => $recall_borrower->branchcode,
1511
        pickup_library_id => $recall_borrower->branchcode,
1512
        item_level => 0,
1512
        item_level => 0,
1513
    })->store;
1513
    })->store;
1514
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1514
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $recall_issue );
1515
    is( $error, 'recalled', 'Cannot renew item if biblio is recalled and has no item allocated' );
1515
    is( $error, 'recalled', 'Cannot renew item if biblio is recalled and has no item allocated' );
1516
    $recall->set_cancelled;
1516
    $recall->set_cancelled;
1517
1517
Lines 1523-1529 subtest "CanBookBeRenewed tests" => sub { Link Here
1523
        pickup_library_id => $recall_borrower->branchcode,
1523
        pickup_library_id => $recall_borrower->branchcode,
1524
        item_level => 1,
1524
        item_level => 1,
1525
    })->store;
1525
    })->store;
1526
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1526
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $recall_issue );
1527
    is( $renewokay, 1, 'Can renew item if item-level recall on biblio is not on this item' );
1527
    is( $renewokay, 1, 'Can renew item if item-level recall on biblio is not on this item' );
1528
    $recall->set_cancelled;
1528
    $recall->set_cancelled;
1529
1529
Lines 1536-1542 subtest "CanBookBeRenewed tests" => sub { Link Here
1536
        item_level => 0,
1536
        item_level => 0,
1537
    })->store;
1537
    })->store;
1538
    $recall->set_waiting({ item => $recall_item1 });
1538
    $recall->set_waiting({ item => $recall_item1 });
1539
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1539
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $recall_issue );
1540
    is( $renewokay, 1, 'Can renew item if biblio-level recall has already been allocated an item' );
1540
    is( $renewokay, 1, 'Can renew item if biblio-level recall has already been allocated an item' );
1541
    $recall->set_cancelled;
1541
    $recall->set_cancelled;
1542
};
1542
};
Lines 1578-1584 subtest "GetUpcomingDueIssues" => sub { Link Here
1578
1578
1579
    my $issue = AddIssue( $a_borrower, $item_1->barcode, $yesterday );
1579
    my $issue = AddIssue( $a_borrower, $item_1->barcode, $yesterday );
1580
    my $datedue = dt_from_string( $issue->date_due() );
1580
    my $datedue = dt_from_string( $issue->date_due() );
1581
    my $issue2 = AddIssue( $a_borrower, $item_2->barcode, $two_days_ahead );
1581
    my $issue_2 = AddIssue( $a_borrower, $item_2->barcode, $two_days_ahead );
1582
    my $datedue2 = dt_from_string( $issue->date_due() );
1582
    my $datedue2 = dt_from_string( $issue->date_due() );
1583
1583
1584
    my $upcoming_dues;
1584
    my $upcoming_dues;
Lines 1704-1715 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1704
    );
1704
    );
1705
1705
1706
1706
1707
    my $borrowernumber1 = Koha::Patron->new({
1707
    my $borrower1 = Koha::Patron->new({
1708
        firstname    => 'Kyle',
1708
        firstname    => 'Kyle',
1709
        surname      => 'Hall',
1709
        surname      => 'Hall',
1710
        categorycode => $patron_category->{categorycode},
1710
        categorycode => $patron_category->{categorycode},
1711
        branchcode   => $library2->{branchcode},
1711
        branchcode   => $library2->{branchcode},
1712
    })->store->borrowernumber;
1712
    })->store;
1713
    my $borrowernumber2 = Koha::Patron->new({
1713
    my $borrowernumber2 = Koha::Patron->new({
1714
        firstname    => 'Chelsea',
1714
        firstname    => 'Chelsea',
1715
        surname      => 'Hall',
1715
        surname      => 'Hall',
Lines 1733-1744 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1733
        branchcode   => $library2->{branchcode},
1733
        branchcode   => $library2->{branchcode},
1734
    })->store->borrowernumber;
1734
    })->store->borrowernumber;
1735
1735
1736
    my $borrower1 = Koha::Patrons->find( $borrowernumber1 )->unblessed;
1736
    my $issue = AddIssue( $borrower1->unblessed, $item_1->barcode );
1737
    my $borrower2 = Koha::Patrons->find( $borrowernumber2 )->unblessed;
1738
1737
1739
    my $issue = AddIssue( $borrower1, $item_1->barcode );
1738
    my ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1740
1741
    my ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1742
    is( $renewokay, 1, 'Bug 14337 - Verify the borrower can renew with no hold on the record' );
1739
    is( $renewokay, 1, 'Bug 14337 - Verify the borrower can renew with no hold on the record' );
1743
1740
1744
    AddReserve(
1741
    AddReserve(
Lines 1761-1771 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1761
        }
1758
        }
1762
    );
1759
    );
1763
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 0 );
1760
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 0 );
1764
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1761
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1765
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable and onshelfholds are disabled' );
1762
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable and onshelfholds are disabled' );
1766
1763
1767
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 1 );
1764
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 1 );
1768
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1765
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1769
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable is enabled and onshelfholds is disabled' );
1766
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable is enabled and onshelfholds is disabled' );
1770
1767
1771
    Koha::CirculationRules->set_rules(
1768
    Koha::CirculationRules->set_rules(
Lines 1779-1789 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1779
        }
1776
        }
1780
    );
1777
    );
1781
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 0 );
1778
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 0 );
1782
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1779
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1783
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable is disabled and onshelfhold is enabled' );
1780
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable is disabled and onshelfhold is enabled' );
1784
1781
1785
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 1 );
1782
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 1 );
1786
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1783
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1787
    is( $renewokay, 1, 'Bug 14337 - Verify the borrower can renew with a hold on the record if AllowRenewalIfOtherItemsAvailable and onshelfhold are enabled' );
1784
    is( $renewokay, 1, 'Bug 14337 - Verify the borrower can renew with a hold on the record if AllowRenewalIfOtherItemsAvailable and onshelfhold are enabled' );
1788
1785
1789
    AddReserve(
1786
    AddReserve(
Lines 1795-1801 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1795
        }
1792
        }
1796
    );
1793
    );
1797
1794
1798
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1795
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1799
    is( $renewokay, 0, 'Verify the borrower cannot renew with 2 holds on the record if AllowRenewalIfOtherItemsAvailable and onshelfhold are enabled and one other item on record' );
1796
    is( $renewokay, 0, 'Verify the borrower cannot renew with 2 holds on the record if AllowRenewalIfOtherItemsAvailable and onshelfhold are enabled and one other item on record' );
1800
1797
1801
    my $item_3= $builder->build_sample_item(
1798
    my $item_3= $builder->build_sample_item(
Lines 1806-1812 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1806
        }
1803
        }
1807
    );
1804
    );
1808
1805
1809
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1806
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1810
    is( $renewokay, 1, 'Verify the borrower cannot renew with 2 holds on the record if AllowRenewalIfOtherItemsAvailable and onshelfhold are enabled and two other items on record' );
1807
    is( $renewokay, 1, 'Verify the borrower cannot renew with 2 holds on the record if AllowRenewalIfOtherItemsAvailable and onshelfhold are enabled and two other items on record' );
1811
1808
1812
    Koha::CirculationRules->set_rules(
1809
    Koha::CirculationRules->set_rules(
Lines 1820-1826 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1820
        }
1817
        }
1821
    );
1818
    );
1822
1819
1823
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1820
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1824
    is( $renewokay, 0, 'Verify the borrower cannot renew with 2 holds on the record, but only one of those holds can be filled when AllowRenewalIfOtherItemsAvailable and onshelfhold are enabled and two other items on record' );
1821
    is( $renewokay, 0, 'Verify the borrower cannot renew with 2 holds on the record, but only one of those holds can be filled when AllowRenewalIfOtherItemsAvailable and onshelfhold are enabled and two other items on record' );
1825
1822
1826
    Koha::CirculationRules->set_rules(
1823
    Koha::CirculationRules->set_rules(
Lines 1837-1843 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1837
    # Setting item not checked out to be not for loan but holdable
1834
    # Setting item not checked out to be not for loan but holdable
1838
    $item_2->notforloan(-1)->store;
1835
    $item_2->notforloan(-1)->store;
1839
1836
1840
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1837
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1841
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower can not renew with a hold on the record if AllowRenewalIfOtherItemsAvailable is enabled but the only available item is notforloan' );
1838
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower can not renew with a hold on the record if AllowRenewalIfOtherItemsAvailable is enabled but the only available item is notforloan' );
1842
1839
1843
    my $mock_circ = Test::MockModule->new("C4::Circulation");
1840
    my $mock_circ = Test::MockModule->new("C4::Circulation");
Lines 1851-1857 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1851
    # Two items total, one item available, one issued, two holds on record
1848
    # Two items total, one item available, one issued, two holds on record
1852
1849
1853
    warnings_are{
1850
    warnings_are{
1854
       ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1851
       ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1855
    } [], "CanItemBeReserved not called when there are more possible holds than available items";
1852
    } [], "CanItemBeReserved not called when there are more possible holds than available items";
1856
    is( $renewokay, 0, 'Borrower cannot renew when there are more holds than available items' );
1853
    is( $renewokay, 0, 'Borrower cannot renew when there are more holds than available items' );
1857
1854
Lines 1875-1881 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1875
    );
1872
    );
1876
1873
1877
    warnings_are{
1874
    warnings_are{
1878
       ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1875
       ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1879
    } ["Checked","Checked"], "CanItemBeReserved only called once per available item if it returns a negative result for all items for a borrower";
1876
    } ["Checked","Checked"], "CanItemBeReserved only called once per available item if it returns a negative result for all items for a borrower";
1880
    is( $renewokay, 0, 'Borrower cannot renew when there are more holds than available items' );
1877
    is( $renewokay, 0, 'Borrower cannot renew when there are more holds than available items' );
1881
1878
Lines 1896-1912 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1896
        }
1893
        }
1897
    );
1894
    );
1898
1895
1899
    my $borrowernumber = Koha::Patron->new({
1896
    my $borrower = Koha::Patron->new({
1900
        firstname =>  'fn',
1897
        firstname =>  'fn',
1901
        surname => 'dn',
1898
        surname => 'dn',
1902
        categorycode => $patron_category->{categorycode},
1899
        categorycode => $patron_category->{categorycode},
1903
        branchcode => $branch,
1900
        branchcode => $branch,
1904
    })->store->borrowernumber;
1901
    })->store;
1905
1906
    my $borrower = Koha::Patrons->find( $borrowernumber )->unblessed;
1907
1902
1908
    my $issue = AddIssue( $borrower, $item->barcode, undef, undef, undef, undef, { onsite_checkout => 1 } );
1903
    my $issue = AddIssue( $borrower->unblessed, $item->barcode, undef, undef, undef, undef, { onsite_checkout => 1 } );
1909
    my ( $renewed, $error ) = CanBookBeRenewed( $borrowernumber, $item->itemnumber );
1904
    my ( $renewed, $error ) = CanBookBeRenewed( $borrower, $issue );
1910
    is( $renewed, 0, 'CanBookBeRenewed should not allow to renew on-site checkout' );
1905
    is( $renewed, 0, 'CanBookBeRenewed should not allow to renew on-site checkout' );
1911
    is( $error, 'onsite_checkout', 'A correct error code should be returned by CanBookBeRenewed for on-site checkout' );
1906
    is( $error, 'onsite_checkout', 'A correct error code should be returned by CanBookBeRenewed for on-site checkout' );
1912
}
1907
}
Lines 1923-1946 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1923
            itype            => $itemtype,
1918
            itype            => $itemtype,
1924
        }
1919
        }
1925
    );
1920
    );
1921
    my $patron = $builder->build_object( { class => 'Koha::Patrons',  value => { branchcode => $library->{branchcode}, categorycode => $patron_category->{categorycode} } } );
1926
1922
1927
    my $patron = $builder->build({ source => 'Borrower', value => { branchcode => $library->{branchcode}, categorycode => $patron_category->{categorycode} } } );
1923
    my $issue = AddIssue( $patron->unblessed, $item->barcode );
1928
1929
    my $issue = AddIssue( $patron, $item->barcode );
1930
    UpdateFine(
1924
    UpdateFine(
1931
        {
1925
        {
1932
            issue_id       => $issue->id(),
1926
            issue_id       => $issue->id,
1933
            itemnumber     => $item->itemnumber,
1927
            itemnumber     => $item->itemnumber,
1934
            borrowernumber => $patron->{borrowernumber},
1928
            borrowernumber => $patron->borrowernumber,
1935
            amount         => 1,
1929
            amount         => 1,
1936
            type           => q{}
1930
            type           => q{}
1937
        }
1931
        }
1938
    );
1932
    );
1939
    UpdateFine(
1933
    UpdateFine(
1940
        {
1934
        {
1941
            issue_id       => $issue->id(),
1935
            issue_id       => $issue->id,
1942
            itemnumber     => $item->itemnumber,
1936
            itemnumber     => $item->itemnumber,
1943
            borrowernumber => $patron->{borrowernumber},
1937
            borrowernumber => $patron->borrowernumber,
1944
            amount         => 2,
1938
            amount         => 2,
1945
            type           => q{}
1939
            type           => q{}
1946
        }
1940
        }
Lines 2365-2373 subtest 'MultipleReserves' => sub { Link Here
2365
        categorycode => $patron_category->{categorycode},
2359
        categorycode => $patron_category->{categorycode},
2366
        branchcode => $branch,
2360
        branchcode => $branch,
2367
    );
2361
    );
2368
    my $renewing_borrowernumber = Koha::Patron->new(\%renewing_borrower_data)->store->borrowernumber;
2362
    my $patron = Koha::Patron->new(\%renewing_borrower_data)->store;
2369
    my $renewing_borrower = Koha::Patrons->find( $renewing_borrowernumber )->unblessed;
2363
    my $issue = AddIssue( $patron->unblessed, $item_1->barcode);
2370
    my $issue = AddIssue( $renewing_borrower, $item_1->barcode);
2371
    my $datedue = dt_from_string( $issue->date_due() );
2364
    my $datedue = dt_from_string( $issue->date_due() );
2372
    is (defined $issue->date_due(), 1, "item 1 checked out");
2365
    is (defined $issue->date_due(), 1, "item 1 checked out");
2373
    my $borrowing_borrowernumber = Koha::Checkouts->find({ itemnumber => $item_1->itemnumber })->borrowernumber;
2366
    my $borrowing_borrowernumber = Koha::Checkouts->find({ itemnumber => $item_1->itemnumber })->borrowernumber;
Lines 2415-2421 subtest 'MultipleReserves' => sub { Link Here
2415
    );
2408
    );
2416
2409
2417
    {
2410
    {
2418
        my ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber, 1);
2411
        my ( $renewokay, $error ) = CanBookBeRenewed($patron, $issue, 1);
2419
        is($renewokay, 0, 'Bug 17941 - should cover the case where 2 books are both reserved, so failing');
2412
        is($renewokay, 0, 'Bug 17941 - should cover the case where 2 books are both reserved, so failing');
2420
    }
2413
    }
2421
2414
Lines 2429-2435 subtest 'MultipleReserves' => sub { Link Here
2429
    );
2422
    );
2430
2423
2431
    {
2424
    {
2432
        my ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber, 1);
2425
        my ( $renewokay, $error ) = CanBookBeRenewed($patron, $issue, 1);
2433
        is($renewokay, 1, 'Bug 17941 - should cover the case where 2 books are reserved, but a third one is available');
2426
        is($renewokay, 1, 'Bug 17941 - should cover the case where 2 books are reserved, but a third one is available');
2434
    }
2427
    }
2435
};
2428
};
Lines 4031-4037 subtest 'Set waiting flag' => sub { Link Here
4031
    my $hold = Koha::Holds->find( $reserve_id );
4024
    my $hold = Koha::Holds->find( $reserve_id );
4032
    is( $hold->found, 'T', 'Hold is in transit' );
4025
    is( $hold->found, 'T', 'Hold is in transit' );
4033
4026
4034
    my ( $status ) = CheckReserves($item->itemnumber);
4027
    my ( $status ) = CheckReserves($item);
4035
    is( $status, 'Transferred', 'Hold is not waiting yet');
4028
    is( $status, 'Transferred', 'Hold is not waiting yet');
4036
4029
4037
    set_userenv( $library_2 );
4030
    set_userenv( $library_2 );
Lines 4040-4046 subtest 'Set waiting flag' => sub { Link Here
4040
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
4033
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
4041
    $hold = Koha::Holds->find( $reserve_id );
4034
    $hold = Koha::Holds->find( $reserve_id );
4042
    is( $hold->found, 'W', 'Hold is waiting' );
4035
    is( $hold->found, 'W', 'Hold is waiting' );
4043
    ( $status ) = CheckReserves($item->itemnumber);
4036
    ( $status ) = CheckReserves($item);
4044
    is( $status, 'Waiting', 'Now the hold is waiting');
4037
    is( $status, 'Waiting', 'Now the hold is waiting');
4045
4038
4046
    #Bug 21944 - Waiting transfer checked in at branch other than pickup location
4039
    #Bug 21944 - Waiting transfer checked in at branch other than pickup location
Lines 4225-4238 subtest 'ItemsDeniedRenewal rules are checked' => sub { Link Here
4225
    my $mock_item_class = Test::MockModule->new("Koha::Item");
4218
    my $mock_item_class = Test::MockModule->new("Koha::Item");
4226
    $mock_item_class->mock( 'is_denied_renewal', sub { return 1; } );
4219
    $mock_item_class->mock( 'is_denied_renewal', sub { return 1; } );
4227
4220
4228
    my ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower->borrowernumber, $issue->itemnumber );
4221
    my ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower, $issue );
4229
    is( $mayrenew, 0, 'Renewal blocked when $item->is_denied_renewal returns true' );
4222
    is( $mayrenew, 0, 'Renewal blocked when $item->is_denied_renewal returns true' );
4230
    is( $error, 'item_denied_renewal', 'Renewal blocked when $item->is_denied_renewal returns true' );
4223
    is( $error, 'item_denied_renewal', 'Renewal blocked when $item->is_denied_renewal returns true' );
4231
4224
4232
    $mock_item_class->unmock( 'is_denied_renewal' );
4225
    $mock_item_class->unmock( 'is_denied_renewal' );
4233
    $mock_item_class->mock( 'is_denied_renewal', sub { return 0; } );
4226
    $mock_item_class->mock( 'is_denied_renewal', sub { return 0; } );
4234
4227
4235
    ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower->borrowernumber, $issue->itemnumber );
4228
    ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower, $issue );
4236
    is( $mayrenew, 1, 'Renewal allowed when $item->is_denied_renewal returns false' );
4229
    is( $mayrenew, 1, 'Renewal allowed when $item->is_denied_renewal returns false' );
4237
    is( $error, undef, 'Renewal allowed when $item->is_denied_renewal returns false' );
4230
    is( $error, undef, 'Renewal allowed when $item->is_denied_renewal returns false' );
4238
4231
Lines 5720-5726 subtest "GetSoonestRenewDate tests" => sub { Link Here
5720
    # Test 'exact time' setting for syspref NoRenewalBeforePrecision
5713
    # Test 'exact time' setting for syspref NoRenewalBeforePrecision
5721
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact_time' );
5714
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact_time' );
5722
    is(
5715
    is(
5723
        GetSoonestRenewDate( $issue ),
5716
        GetSoonestRenewDate( $patron, $issue ),
5724
        $datedue->clone->add( days => -7 ),
5717
        $datedue->clone->add( days => -7 ),
5725
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5718
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5726
    );
5719
    );
Lines 5729-5735 subtest "GetSoonestRenewDate tests" => sub { Link Here
5729
    # Test 'date' setting for syspref NoRenewalBeforePrecision
5722
    # Test 'date' setting for syspref NoRenewalBeforePrecision
5730
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5723
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5731
    is(
5724
    is(
5732
        GetSoonestRenewDate( $issue ),
5725
        GetSoonestRenewDate( $patron, $issue ),
5733
        $datedue->clone->add( days => -7 )->truncate( to => 'day' ),
5726
        $datedue->clone->add( days => -7 )->truncate( to => 'day' ),
5734
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5727
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5735
    );
5728
    );
Lines 5746-5752 subtest "GetSoonestRenewDate tests" => sub { Link Here
5746
    );
5739
    );
5747
5740
5748
    is(
5741
    is(
5749
        GetSoonestRenewDate( $issue ),
5742
        GetSoonestRenewDate( $patron, $issue ),
5750
        dt_from_string,
5743
        dt_from_string,
5751
        'Checkouts without auto-renewal can be renewed immediately if no norenewalbefore'
5744
        'Checkouts without auto-renewal can be renewed immediately if no norenewalbefore'
5752
    );
5745
    );
Lines 5754-5766 subtest "GetSoonestRenewDate tests" => sub { Link Here
5754
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5747
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5755
    $issue->auto_renew(1)->store;
5748
    $issue->auto_renew(1)->store;
5756
    is(
5749
    is(
5757
        GetSoonestRenewDate( $issue ),
5750
        GetSoonestRenewDate( $patron, $issue ),
5758
        $datedue->clone->truncate( to => 'day' ),
5751
        $datedue->clone->truncate( to => 'day' ),
5759
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5752
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5760
    );
5753
    );
5761
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact' );
5754
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact' );
5762
    is(
5755
    is(
5763
        GetSoonestRenewDate( $issue ),
5756
        GetSoonestRenewDate( $patron, $issue ),
5764
        $datedue,
5757
        $datedue,
5765
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5758
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5766
    );
5759
    );
Lines 5773-5779 subtest "CanBookBeIssued + needsconfirmation message" => sub { Link Here
5773
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
5766
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
5774
    my $biblio = $builder->build_object({ class => 'Koha::Biblios' });
5767
    my $biblio = $builder->build_object({ class => 'Koha::Biblios' });
5775
    my $biblioitem = $builder->build_object({ class => 'Koha::Biblioitems', value => { biblionumber => $biblio->biblionumber }});
5768
    my $biblioitem = $builder->build_object({ class => 'Koha::Biblioitems', value => { biblionumber => $biblio->biblionumber }});
5776
    my $item = $builder->build_object({ class => 'Koha::Items' , value => { biblionumber => $biblio->biblionumber }});
5769
    my $item = $builder->build_object({ class => 'Koha::Items' , value => { itype => $itemtype, biblionumber => $biblio->biblionumber }});
5777
5770
5778
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
5771
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
5779
        biblionumber => $item->biblionumber,
5772
        biblionumber => $item->biblionumber,
(-)a/t/db_dependent/Circulation/Returns.t (+1 lines)
Lines 132-137 subtest "AddReturn logging on statistics table (item-level_itypes=1)" => sub { Link Here
132
        "item-level itype recorded on statistics for return");
132
        "item-level itype recorded on statistics for return");
133
    warning_like { AddIssue( $borrower, $item_without_itemtype->barcode ) }
133
    warning_like { AddIssue( $borrower, $item_without_itemtype->barcode ) }
134
                 [qr/^item-level_itypes set but no itemtype set for item/,
134
                 [qr/^item-level_itypes set but no itemtype set for item/,
135
                 qr/^item-level_itypes set but no itemtype set for item/,
135
                 qr/^item-level_itypes set but no itemtype set for item/],
136
                 qr/^item-level_itypes set but no itemtype set for item/],
136
                 'Item without itemtype set raises warning on AddIssue';
137
                 'Item without itemtype set raises warning on AddIssue';
137
    AddReturn( $item_without_itemtype->barcode, $branch );
138
    AddReturn( $item_without_itemtype->barcode, $branch );
(-)a/t/db_dependent/Circulation/transferbook.t (-1 / +6 lines)
Lines 116-124 subtest 'transfer already at destination' => sub { Link Here
116
        }
116
        }
117
    );
117
    );
118
118
119
    my $itemtype = $builder->build_object({ class => 'Koha::ItemTypes' })->store->itemtype;
119
    my $item = $builder->build_sample_item(
120
    my $item = $builder->build_sample_item(
120
        {
121
        {
121
            library => $library->branchcode,
122
            library => $library->branchcode,
123
            itype => $itemtype
122
        }
124
        }
123
    );
125
    );
124
126
Lines 169-175 subtest 'transfer already at destination' => sub { Link Here
169
    is( $dotransfer, 0, 'Do not transfer recalled item, it has already arrived' );
171
    is( $dotransfer, 0, 'Do not transfer recalled item, it has already arrived' );
170
    is( $messages->{RecallPlacedAtHoldingBranch}, 1, "We found the recall");
172
    is( $messages->{RecallPlacedAtHoldingBranch}, 1, "We found the recall");
171
173
172
    my $item2 = $builder->build_object({ class => 'Koha::Items' }); # this item will have a different holding branch to the pickup branch
174
    $itemtype = $builder->build_object({ class => 'Koha::ItemTypes' })->store->itemtype;
175
    my $item2 = $builder->build_object({ class => 'Koha::Items', value => { itype => $itemtype } }); # this item will have a different holding branch to the pickup branch
173
    $recall = Koha::Recall->new(
176
    $recall = Koha::Recall->new(
174
        {   biblio_id         => $item2->biblionumber,
177
        {   biblio_id         => $item2->biblionumber,
175
            item_id           => $item2->itemnumber,
178
            item_id           => $item2->itemnumber,
Lines 196-204 subtest 'transfer an issued item' => sub { Link Here
196
        }
199
        }
197
    );
200
    );
198
201
202
    my $itemtype = $builder->build_object({ class => 'Koha::ItemTypes' })->store->itemtype;
199
    my $item = $builder->build_sample_item(
203
    my $item = $builder->build_sample_item(
200
        {
204
        {
201
            library => $library->branchcode,
205
            library => $library->branchcode,
206
            itype => $itemtype
202
        }
207
        }
203
    );
208
    );
204
209
(-)a/t/db_dependent/Holds.t (-13 / +13 lines)
Lines 64-70 $insert_sth->execute('ONLY1'); Link Here
64
my $biblio = $builder->build_sample_biblio({ itemtype => 'DUMMY' });
64
my $biblio = $builder->build_sample_biblio({ itemtype => 'DUMMY' });
65
65
66
# Create item instance for testing.
66
# Create item instance for testing.
67
my $itemnumber = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber })->itemnumber;
67
my $item = $builder->build_sample_item({ library => $branch_1, biblionumber => $biblio->biblionumber });
68
my $itemnumber = $item->itemnumber;
68
69
69
# Create some borrowers
70
# Create some borrowers
70
my @borrowernumbers;
71
my @borrowernumbers;
Lines 101-107 is( $holds->next->priority, 3, "Reserve 3 has a priority of 3" ); Link Here
101
is( $holds->next->priority, 4, "Reserve 4 has a priority of 4" );
102
is( $holds->next->priority, 4, "Reserve 4 has a priority of 4" );
102
is( $holds->next->priority, 5, "Reserve 5 has a priority of 5" );
103
is( $holds->next->priority, 5, "Reserve 5 has a priority of 5" );
103
104
104
my $item = Koha::Items->find( $itemnumber );
105
$holds = $item->current_holds;
105
$holds = $item->current_holds;
106
my $first_hold = $holds->next;
106
my $first_hold = $holds->next;
107
my $reservedate = $first_hold->reservedate;
107
my $reservedate = $first_hold->reservedate;
Lines 342-348 ok( Link Here
342
my $damaged_item = Koha::Items->find($itemnumber)->damaged(1)->store; # FIXME The $itemnumber is a bit confusing here
342
my $damaged_item = Koha::Items->find($itemnumber)->damaged(1)->store; # FIXME The $itemnumber is a bit confusing here
343
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 1 );
343
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 1 );
344
is( CanItemBeReserved( $patrons[0], $damaged_item)->{status}, 'OK', "Patron can reserve damaged item with AllowHoldsOnDamagedItems enabled" );
344
is( CanItemBeReserved( $patrons[0], $damaged_item)->{status}, 'OK', "Patron can reserve damaged item with AllowHoldsOnDamagedItems enabled" );
345
ok( defined( ( CheckReserves($itemnumber) )[1] ), "Hold can be trapped for damaged item with AllowHoldsOnDamagedItems enabled" );
345
ok( defined( ( CheckReserves($damaged_item) )[1] ), "Hold can be trapped for damaged item with AllowHoldsOnDamagedItems enabled" );
346
346
347
$hold = Koha::Hold->new(
347
$hold = Koha::Hold->new(
348
    {
348
    {
Lines 359-365 $hold->delete(); Link Here
359
359
360
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 0 );
360
t::lib::Mocks::mock_preference( 'AllowHoldsOnDamagedItems', 0 );
361
ok( CanItemBeReserved( $patrons[0], $damaged_item)->{status} eq 'damaged', "Patron cannot reserve damaged item with AllowHoldsOnDamagedItems disabled" );
361
ok( CanItemBeReserved( $patrons[0], $damaged_item)->{status} eq 'damaged', "Patron cannot reserve damaged item with AllowHoldsOnDamagedItems disabled" );
362
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for damaged item with AllowHoldsOnDamagedItems disabled" );
362
ok( !defined( ( CheckReserves($damaged_item) )[1] ), "Hold cannot be trapped for damaged item with AllowHoldsOnDamagedItems disabled" );
363
363
364
# Items that are not for loan, but holdable should not be trapped until they are available for loan
364
# Items that are not for loan, but holdable should not be trapped until they are available for loan
365
t::lib::Mocks::mock_preference( 'TrapHoldsOnOrder', 0 );
365
t::lib::Mocks::mock_preference( 'TrapHoldsOnOrder', 0 );
Lines 377-395 $hold = Koha::Hold->new( Link Here
377
        branchcode     => $branch_1,
377
        branchcode     => $branch_1,
378
    }
378
    }
379
)->store();
379
)->store();
380
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for item that is not for loan but holdable ( notforloan < 0 )" );
380
ok( !defined( ( CheckReserves($nfl_item) )[1] ), "Hold cannot be trapped for item that is not for loan but holdable ( notforloan < 0 )" );
381
t::lib::Mocks::mock_preference( 'TrapHoldsOnOrder', 1 );
381
t::lib::Mocks::mock_preference( 'TrapHoldsOnOrder', 1 );
382
ok( defined( ( CheckReserves($itemnumber) )[1] ), "Hold is trapped for item that is not for loan but holdable ( notforloan < 0 )" );
382
ok( defined( ( CheckReserves($nfl_item) )[1] ), "Hold is trapped for item that is not for loan but holdable ( notforloan < 0 )" );
383
t::lib::Mocks::mock_preference( 'SkipHoldTrapOnNotForLoanValue', '-1' );
383
t::lib::Mocks::mock_preference( 'SkipHoldTrapOnNotForLoanValue', '-1' );
384
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for item with notforloan value matching SkipHoldTrapOnNotForLoanValue" );
384
ok( !defined( ( CheckReserves($nfl_item) )[1] ), "Hold cannot be trapped for item with notforloan value matching SkipHoldTrapOnNotForLoanValue" );
385
t::lib::Mocks::mock_preference( 'SkipHoldTrapOnNotForLoanValue', '-1|1' );
385
t::lib::Mocks::mock_preference( 'SkipHoldTrapOnNotForLoanValue', '-1|1' );
386
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for item with notforloan value matching SkipHoldTrapOnNotForLoanValue" );
386
ok( !defined( ( CheckReserves($nfl_item) )[1] ), "Hold cannot be trapped for item with notforloan value matching SkipHoldTrapOnNotForLoanValue" );
387
t::lib::Mocks::mock_preference( 'SkipHoldTrapOnNotForLoanValue', '' );
387
t::lib::Mocks::mock_preference( 'SkipHoldTrapOnNotForLoanValue', '' );
388
my $item_group_1 = Koha::Biblio::ItemGroup->new( { biblio_id => $biblio->id } )->store();
388
my $item_group_1 = Koha::Biblio::ItemGroup->new( { biblio_id => $biblio->id } )->store();
389
my $item_group_2 = Koha::Biblio::ItemGroup->new( { biblio_id => $biblio->id } )->store();
389
my $item_group_2 = Koha::Biblio::ItemGroup->new( { biblio_id => $biblio->id } )->store();
390
$item_group_1->add_item({ item_id => $itemnumber });
390
$item_group_1->add_item({ item_id => $itemnumber });
391
$hold->item_group_id( $item_group_2->id )->update;
391
$hold->item_group_id( $item_group_2->id )->update;
392
ok( !defined( ( CheckReserves($itemnumber) )[1] ), "Hold cannot be trapped for item with non-matching item group" );
392
ok( !defined( ( CheckReserves($nfl_item) )[1] ), "Hold cannot be trapped for item with non-matching item group" );
393
is(
393
is(
394
    CanItemBeReserved( $patrons[0], $nfl_item)->{status}, 'itemAlreadyOnHold',
394
    CanItemBeReserved( $patrons[0], $nfl_item)->{status}, 'itemAlreadyOnHold',
395
    "cannot request item that you have already reservedd"
395
    "cannot request item that you have already reservedd"
Lines 1501-1507 subtest 'non priority holds' => sub { Link Here
1501
        }
1501
        }
1502
    );
1502
    );
1503
1503
1504
    Koha::Checkout->new(
1504
    my $issue = Koha::Checkout->new(
1505
        {
1505
        {
1506
            borrowernumber => $patron1->borrowernumber,
1506
            borrowernumber => $patron1->borrowernumber,
1507
            itemnumber     => $item->itemnumber,
1507
            itemnumber     => $item->itemnumber,
Lines 1520-1526 subtest 'non priority holds' => sub { Link Here
1520
    );
1520
    );
1521
1521
1522
    my ( $ok, $err ) =
1522
    my ( $ok, $err ) =
1523
      CanBookBeRenewed( $patron1->borrowernumber, $item->itemnumber );
1523
      CanBookBeRenewed( $patron1, $issue );
1524
1524
1525
    ok( !$ok, 'Cannot renew' );
1525
    ok( !$ok, 'Cannot renew' );
1526
    is( $err, 'on_reserve', 'Item is on hold' );
1526
    is( $err, 'on_reserve', 'Item is on hold' );
Lines 1529-1535 subtest 'non priority holds' => sub { Link Here
1529
    $hold->non_priority(1)->store;
1529
    $hold->non_priority(1)->store;
1530
1530
1531
    ( $ok, $err ) =
1531
    ( $ok, $err ) =
1532
      CanBookBeRenewed( $patron1->borrowernumber, $item->itemnumber );
1532
      CanBookBeRenewed( $patron1, $issue );
1533
1533
1534
    ok( $ok, 'Can renew' );
1534
    ok( $ok, 'Can renew' );
1535
    is( $err, undef, 'Item is on non priority hold' );
1535
    is( $err, undef, 'Item is on non priority hold' );
Lines 1553-1559 subtest 'non priority holds' => sub { Link Here
1553
    );
1553
    );
1554
1554
1555
    ( $ok, $err ) =
1555
    ( $ok, $err ) =
1556
      CanBookBeRenewed( $patron1->borrowernumber, $item->itemnumber );
1556
      CanBookBeRenewed( $patron1, $issue );
1557
1557
1558
    ok( !$ok, 'Cannot renew' );
1558
    ok( !$ok, 'Cannot renew' );
1559
    is( $err, 'on_reserve', 'Item is on hold' );
1559
    is( $err, 'on_reserve', 'Item is on hold' );
(-)a/t/db_dependent/Holds/HoldFulfillmentPolicy.t (-14 / +11 lines)
Lines 67-75 $dbh->do(" Link Here
67
    VALUES ($biblionumber, $biblioitemnumber, '$library_A', '$library_B', 0, 0, 0, 0, NULL, '$itemtype')
67
    VALUES ($biblionumber, $biblioitemnumber, '$library_A', '$library_B', 0, 0, 0, 0, NULL, '$itemtype')
68
");
68
");
69
69
70
my $itemnumber =
70
my $item = Koha::Items->find({ biblionumber => $biblionumber });
71
  $dbh->selectrow_array("SELECT itemnumber FROM items WHERE biblionumber = $biblionumber")
72
  or BAIL_OUT("Cannot find newly created item");
73
71
74
# With hold_fulfillment_policy = homebranch, hold should only be picked up if pickup branch = homebranch
72
# With hold_fulfillment_policy = homebranch, hold should only be picked up if pickup branch = homebranch
75
$dbh->do("DELETE FROM circulation_rules");
73
$dbh->do("DELETE FROM circulation_rules");
Lines 93-99 my $reserve_id = AddReserve( Link Here
93
        priority       => 1,
91
        priority       => 1,
94
    }
92
    }
95
);
93
);
96
my ( $status ) = CheckReserves($itemnumber);
94
my ( $status ) = CheckReserves($item);
97
is( $status, 'Reserved', "Hold where pickup branch matches home branch targeted" );
95
is( $status, 'Reserved', "Hold where pickup branch matches home branch targeted" );
98
Koha::Holds->find( $reserve_id )->cancel;
96
Koha::Holds->find( $reserve_id )->cancel;
99
97
Lines 106-112 $reserve_id = AddReserve( Link Here
106
        priority       => 1,
104
        priority       => 1,
107
    }
105
    }
108
);
106
);
109
( $status ) = CheckReserves($itemnumber);
107
( $status ) = CheckReserves($item);
110
is($status, q{}, "Hold where pickup ne home, pickup eq home not targeted" );
108
is($status, q{}, "Hold where pickup ne home, pickup eq home not targeted" );
111
Koha::Holds->find( $reserve_id )->cancel;
109
Koha::Holds->find( $reserve_id )->cancel;
112
110
Lines 119-125 $reserve_id = AddReserve( Link Here
119
        priority       => 1,
117
        priority       => 1,
120
    }
118
    }
121
);
119
);
122
( $status ) = CheckReserves($itemnumber);
120
( $status ) = CheckReserves($item);
123
is( $status, q{}, "Hold where pickup ne home, pickup ne holding not targeted" );
121
is( $status, q{}, "Hold where pickup ne home, pickup ne holding not targeted" );
124
Koha::Holds->find( $reserve_id )->cancel;
122
Koha::Holds->find( $reserve_id )->cancel;
125
123
Lines 145-151 $reserve_id = AddReserve( Link Here
145
        priority       => 1,
143
        priority       => 1,
146
    }
144
    }
147
);
145
);
148
( $status ) = CheckReserves($itemnumber);
146
( $status ) = CheckReserves($item);
149
is( $status, q{}, "Hold where pickup eq home, pickup ne holding not targeted" );
147
is( $status, q{}, "Hold where pickup eq home, pickup ne holding not targeted" );
150
Koha::Holds->find( $reserve_id )->cancel;
148
Koha::Holds->find( $reserve_id )->cancel;
151
149
Lines 158-164 $reserve_id = AddReserve( Link Here
158
        priority       => 1,
156
        priority       => 1,
159
    }
157
    }
160
);
158
);
161
( $status ) = CheckReserves($itemnumber);
159
( $status ) = CheckReserves($item);
162
is( $status, 'Reserved', "Hold where pickup ne home, pickup eq holding targeted" );
160
is( $status, 'Reserved', "Hold where pickup ne home, pickup eq holding targeted" );
163
Koha::Holds->find( $reserve_id )->cancel;
161
Koha::Holds->find( $reserve_id )->cancel;
164
162
Lines 171-177 $reserve_id = AddReserve( Link Here
171
        priority       => 1,
169
        priority       => 1,
172
    }
170
    }
173
);
171
);
174
( $status ) = CheckReserves($itemnumber);
172
( $status ) = CheckReserves($item);
175
is( $status, q{}, "Hold where pickup ne home, pickup ne holding not targeted" );
173
is( $status, q{}, "Hold where pickup ne home, pickup ne holding not targeted" );
176
Koha::Holds->find( $reserve_id )->cancel;
174
Koha::Holds->find( $reserve_id )->cancel;
177
175
Lines 197-203 $reserve_id = AddReserve( Link Here
197
        priority       => 1,
195
        priority       => 1,
198
    }
196
    }
199
);
197
);
200
( $status ) = CheckReserves($itemnumber);
198
( $status ) = CheckReserves($item);
201
is( $status, 'Reserved', "Hold where pickup eq home, pickup ne holding targeted" );
199
is( $status, 'Reserved', "Hold where pickup eq home, pickup ne holding targeted" );
202
Koha::Holds->find( $reserve_id )->cancel;
200
Koha::Holds->find( $reserve_id )->cancel;
203
201
Lines 210-216 $reserve_id = AddReserve( Link Here
210
        priority       => 1,
208
        priority       => 1,
211
    }
209
    }
212
);
210
);
213
( $status ) = CheckReserves($itemnumber);
211
( $status ) = CheckReserves($item);
214
is( $status, 'Reserved', "Hold where pickup ne home, pickup eq holding targeted" );
212
is( $status, 'Reserved', "Hold where pickup ne home, pickup eq holding targeted" );
215
Koha::Holds->find( $reserve_id )->cancel;
213
Koha::Holds->find( $reserve_id )->cancel;
216
214
Lines 223-229 $reserve_id = AddReserve( Link Here
223
        priority       => 1,
221
        priority       => 1,
224
    }
222
    }
225
);
223
);
226
( $status ) = CheckReserves($itemnumber);
224
( $status ) = CheckReserves($item);
227
is( $status, 'Reserved', "Hold where pickup ne home, pickup ne holding targeted" );
225
is( $status, 'Reserved', "Hold where pickup ne home, pickup ne holding targeted" );
228
Koha::Holds->find( $reserve_id )->cancel;
226
Koha::Holds->find( $reserve_id )->cancel;
229
227
Lines 231-237 Koha::Holds->find( $reserve_id )->cancel; Link Here
231
t::lib::Mocks::mock_preference( 'UseBranchTransferLimits',  '1' );
229
t::lib::Mocks::mock_preference( 'UseBranchTransferLimits',  '1' );
232
t::lib::Mocks::mock_preference( 'BranchTransferLimitsType', 'itemtype' );
230
t::lib::Mocks::mock_preference( 'BranchTransferLimitsType', 'itemtype' );
233
Koha::Holds->search()->delete();
231
Koha::Holds->search()->delete();
234
my ($item) = Koha::Biblios->find($biblionumber)->items->as_list;
235
my $limit = Koha::Item::Transfer::Limit->new(
232
my $limit = Koha::Item::Transfer::Limit->new(
236
    {
233
    {
237
        toBranch   => $library_C,
234
        toBranch   => $library_C,
Lines 247-252 $reserve_id = AddReserve( Link Here
247
        priority       => 1
244
        priority       => 1
248
    }
245
    }
249
);
246
);
250
($status) = CheckReserves($itemnumber);
247
($status) = CheckReserves($item);
251
is( $status, '',  "No hold where branch transfer is not allowed" );
248
is( $status, '',  "No hold where branch transfer is not allowed" );
252
Koha::Holds->find($reserve_id)->cancel;
249
Koha::Holds->find($reserve_id)->cancel;
(-)a/t/db_dependent/Holds/HoldItemtypeLimit.t (-6 / +4 lines)
Lines 82-90 $dbh->do(" Link Here
82
    VALUES ($biblionumber, $biblioitemnumber, '$branchcode', '$branchcode', 0, 0, 0, 0, NULL, '$right_itemtype')
82
    VALUES ($biblionumber, $biblioitemnumber, '$branchcode', '$branchcode', 0, 0, 0, 0, NULL, '$right_itemtype')
83
");
83
");
84
84
85
my $itemnumber =
85
my $item = Koha::Items->find({ biblionumber => $biblionumber });
86
  $dbh->selectrow_array("SELECT itemnumber FROM items WHERE biblionumber = $biblionumber")
87
  or BAIL_OUT("Cannot find newly created item");
88
86
89
$dbh->do("DELETE FROM circulation_rules");
87
$dbh->do("DELETE FROM circulation_rules");
90
Koha::CirculationRules->set_rules(
88
Koha::CirculationRules->set_rules(
Lines 108-114 my $reserve_id = AddReserve( Link Here
108
        itemtype       => $right_itemtype,
106
        itemtype       => $right_itemtype,
109
    }
107
    }
110
);
108
);
111
my ( $status ) = CheckReserves($itemnumber);
109
my ( $status ) = CheckReserves($item);
112
is( $status, 'Reserved', "Hold where itemtype matches item's itemtype targed" );
110
is( $status, 'Reserved', "Hold where itemtype matches item's itemtype targed" );
113
Koha::Holds->find( $reserve_id )->cancel;
111
Koha::Holds->find( $reserve_id )->cancel;
114
112
Lines 123-129 $reserve_id = AddReserve( Link Here
123
    }
121
    }
124
);
122
);
125
123
126
( $status ) = CheckReserves($itemnumber);
124
( $status ) = CheckReserves($item);
127
is($status, q{}, "Hold where itemtype does not match item's itemtype not targeted" );
125
is($status, q{}, "Hold where itemtype does not match item's itemtype not targeted" );
128
Koha::Holds->find( $reserve_id )->cancel;
126
Koha::Holds->find( $reserve_id )->cancel;
129
127
Lines 136-142 $reserve_id = AddReserve( Link Here
136
        priority       => 1,
134
        priority       => 1,
137
    }
135
    }
138
);
136
);
139
( $status ) = CheckReserves($itemnumber);
137
( $status ) = CheckReserves($item);
140
is( $status, 'Reserved', "Item targeted with no hold itemtype set" );
138
is( $status, 'Reserved', "Item targeted with no hold itemtype set" );
141
Koha::Holds->find( $reserve_id )->cancel;
139
Koha::Holds->find( $reserve_id )->cancel;
142
140
(-)a/t/db_dependent/Holds/LocalHoldsPriority.t (-10 / +10 lines)
Lines 42-48 my $itemtype = $builder->build( Link Here
42
my $borrowers_count = 5;
42
my $borrowers_count = 5;
43
43
44
my $biblio = $builder->build_sample_biblio();
44
my $biblio = $builder->build_sample_biblio();
45
my $itemnumber = Koha::Item->new(
45
my $item = Koha::Item->new(
46
    {
46
    {
47
        biblionumber  => $biblio->biblionumber,
47
        biblionumber  => $biblio->biblionumber,
48
        homebranch    => $library4->{branchcode},
48
        homebranch    => $library4->{branchcode},
Lines 50-56 my $itemnumber = Koha::Item->new( Link Here
50
        itype         => $itemtype,
50
        itype         => $itemtype,
51
        exclude_from_local_holds_priority => 0,
51
        exclude_from_local_holds_priority => 0,
52
    },
52
    },
53
)->store->itemnumber;
53
)->store;
54
54
55
my @branchcodes = ( $library1->{branchcode}, $library2->{branchcode}, $library3->{branchcode}, $library4->{branchcode}, $library3->{branchcode}, $library4->{branchcode} );
55
my @branchcodes = ( $library1->{branchcode}, $library2->{branchcode}, $library3->{branchcode}, $library4->{branchcode}, $library3->{branchcode}, $library4->{branchcode} );
56
my $patron_category = $builder->build({ source => 'Category', value => {exclude_from_local_holds_priority => 0} });
56
my $patron_category = $builder->build({ source => 'Category', value => {exclude_from_local_holds_priority => 0} });
Lines 84-112 foreach my $borrowernumber (@borrowernumbers) { Link Here
84
my ($status, $reserve, $all_reserves);
84
my ($status, $reserve, $all_reserves);
85
85
86
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 0 );
86
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 0 );
87
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
87
($status, $reserve, $all_reserves) = CheckReserves($item);
88
ok( $reserve->{borrowernumber} eq $borrowernumbers[0], "Received expected results with LocalHoldsPriority disabled" );
88
ok( $reserve->{borrowernumber} eq $borrowernumbers[0], "Received expected results with LocalHoldsPriority disabled" );
89
89
90
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
90
t::lib::Mocks::mock_preference( 'LocalHoldsPriority', 1 );
91
91
92
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
92
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
93
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
93
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
94
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
94
($status, $reserve, $all_reserves) = CheckReserves($item);
95
ok( $reserve->{borrowernumber} eq $borrowernumbers[2], "Received expected results with PickupLibrary/homebranch" );
95
ok( $reserve->{borrowernumber} eq $borrowernumbers[2], "Received expected results with PickupLibrary/homebranch" );
96
96
97
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
97
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'PickupLibrary' );
98
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
98
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
99
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
99
($status, $reserve, $all_reserves) = CheckReserves($item);
100
ok( $reserve->{borrowernumber} eq $borrowernumbers[1], "Received expected results with PickupLibrary/holdingbranch" );
100
ok( $reserve->{borrowernumber} eq $borrowernumbers[1], "Received expected results with PickupLibrary/holdingbranch" );
101
101
102
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
102
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
103
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
103
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'holdingbranch' );
104
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
104
($status, $reserve, $all_reserves) = CheckReserves($item);
105
ok( $reserve->{borrowernumber} eq $borrowernumbers[2], "Received expected results with HomeLibrary/holdingbranch" );
105
ok( $reserve->{borrowernumber} eq $borrowernumbers[2], "Received expected results with HomeLibrary/holdingbranch" );
106
106
107
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
107
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityPatronControl', 'HomeLibrary' );
108
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
108
t::lib::Mocks::mock_preference( 'LocalHoldsPriorityItemControl', 'homebranch' );
109
($status, $reserve, $all_reserves) = CheckReserves($itemnumber);
109
($status, $reserve, $all_reserves) = CheckReserves($item);
110
ok( $reserve->{borrowernumber} eq $borrowernumbers[3], "Received expected results with HomeLibrary/homebranch" );
110
ok( $reserve->{borrowernumber} eq $borrowernumbers[3], "Received expected results with HomeLibrary/homebranch" );
111
111
112
$schema->storage->txn_rollback;
112
$schema->storage->txn_rollback;
Lines 160-166 subtest "exclude from local holds" => sub { Link Here
160
    );
160
    );
161
161
162
    my ($status, $reserve, $all_reserves);
162
    my ($status, $reserve, $all_reserves);
163
    ($status, $reserve, $all_reserves) = CheckReserves($item1->itemnumber);
163
    ($status, $reserve, $all_reserves) = CheckReserves($item1);
164
    is($reserve->{borrowernumber}, $patron_nex_l1->borrowernumber, "Patron not excluded with local holds priorities is next checkout");
164
    is($reserve->{borrowernumber}, $patron_nex_l1->borrowernumber, "Patron not excluded with local holds priorities is next checkout");
165
165
166
    Koha::Holds->delete;
166
    Koha::Holds->delete;
Lines 182-188 subtest "exclude from local holds" => sub { Link Here
182
        }
182
        }
183
    );
183
    );
184
184
185
    ($status, $reserve, $all_reserves) = CheckReserves($item1->itemnumber);
185
    ($status, $reserve, $all_reserves) = CheckReserves($item1);
186
    is($reserve->{borrowernumber}, $patron_nex_l2->borrowernumber, "Local patron is excluded from priority");
186
    is($reserve->{borrowernumber}, $patron_nex_l2->borrowernumber, "Local patron is excluded from priority");
187
187
188
    Koha::Holds->delete;
188
    Koha::Holds->delete;
Lines 204-210 subtest "exclude from local holds" => sub { Link Here
204
        }
204
        }
205
    );
205
    );
206
206
207
    ($status, $reserve, $all_reserves) = CheckReserves($item2->itemnumber);
207
    ($status, $reserve, $all_reserves) = CheckReserves($item2);
208
    is($reserve->{borrowernumber}, $patron_nex_l2->borrowernumber, "Patron from other library is next checkout because item is excluded");
208
    is($reserve->{borrowernumber}, $patron_nex_l2->borrowernumber, "Patron from other library is next checkout because item is excluded");
209
209
210
    $schema->storage->txn_rollback;
210
    $schema->storage->txn_rollback;
(-)a/t/db_dependent/Koha/Account/Line.t (+1 lines)
Lines 511-516 subtest 'Renewal related tests' => sub { Link Here
511
            class => 'Koha::Checkouts',
511
            class => 'Koha::Checkouts',
512
            value => {
512
            value => {
513
                itemnumber      => $item->itemnumber,
513
                itemnumber      => $item->itemnumber,
514
                borrowernumber  => $patron->borrowernumber,
514
                onsite_checkout => 0,
515
                onsite_checkout => 0,
515
                renewals_count  => 99,
516
                renewals_count  => 99,
516
                auto_renew      => 0
517
                auto_renew      => 0
(-)a/t/db_dependent/Koha/Object.t (+3 lines)
Lines 973-978 subtest 'unblessed_all_relateds' => sub { Link Here
973
    my $patron = Koha::Patron->new($patron_data)->store;
973
    my $patron = Koha::Patron->new($patron_data)->store;
974
    my ($biblionumber) = AddBiblio( MARC::Record->new, '' );
974
    my ($biblionumber) = AddBiblio( MARC::Record->new, '' );
975
    my $biblio = Koha::Biblios->find( $biblionumber );
975
    my $biblio = Koha::Biblios->find( $biblionumber );
976
    my $itemtype = $builder->build({ source => 'Itemtype' })->{itemtype};
977
976
    my $item = $builder->build_object(
978
    my $item = $builder->build_object(
977
        {
979
        {
978
            class => 'Koha::Items',
980
            class => 'Koha::Items',
Lines 982-987 subtest 'unblessed_all_relateds' => sub { Link Here
982
                biblionumber  => $biblio->biblionumber,
984
                biblionumber  => $biblio->biblionumber,
983
                itemlost      => 0,
985
                itemlost      => 0,
984
                withdrawn     => 0,
986
                withdrawn     => 0,
987
                itype => $itemtype
985
            }
988
            }
986
        }
989
        }
987
    );
990
    );
(-)a/t/db_dependent/Letters/TemplateToolkit.t (-4 / +5 lines)
Lines 311-322 subtest 'regression tests' => sub { Link Here
311
    plan tests => 8;
311
    plan tests => 8;
312
312
313
    my $library = $builder->build( { source => 'Branch' } );
313
    my $library = $builder->build( { source => 'Branch' } );
314
    my $patron  = $builder->build( { source => 'Borrower' } );
314
    my $itemtype = $builder->build_object({ class => 'Koha::ItemTypes' })->store->itemtype;
315
315
    my $item1 = $builder->build_sample_item(
316
    my $item1 = $builder->build_sample_item(
316
        {
317
        {
317
            barcode        => 'a_t_barcode',
318
            barcode        => 'a_t_barcode',
318
            library        => $library->{branchcode},
319
            library        => $library->{branchcode},
319
            itype          => 'BK',
320
            itype          => $itemtype,
320
            itemcallnumber => 'itemcallnumber1',
321
            itemcallnumber => 'itemcallnumber1',
321
        }
322
        }
322
    );
323
    );
Lines 326-332 subtest 'regression tests' => sub { Link Here
326
        {
327
        {
327
            barcode        => 'another_t_barcode',
328
            barcode        => 'another_t_barcode',
328
            library        => $library->{branchcode},
329
            library        => $library->{branchcode},
329
            itype          => 'BK',
330
            itype          => $itemtype,
330
            itemcallnumber => 'itemcallnumber2',
331
            itemcallnumber => 'itemcallnumber2',
331
        }
332
        }
332
    );
333
    );
Lines 336-342 subtest 'regression tests' => sub { Link Here
336
        {
337
        {
337
            barcode        => 'another_t_barcode_3',
338
            barcode        => 'another_t_barcode_3',
338
            library        => $library->{branchcode},
339
            library        => $library->{branchcode},
339
            itype          => 'BK',
340
            itype          => $itemtype,
340
            itemcallnumber => 'itemcallnumber3',
341
            itemcallnumber => 'itemcallnumber3',
341
        }
342
        }
342
    );
343
    );
(-)a/t/db_dependent/Reserves.t (-31 / +27 lines)
Lines 17-23 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 77;
20
use Test::More tests => 76;
21
use Test::MockModule;
21
use Test::MockModule;
22
use Test::Warn;
22
use Test::Warn;
23
23
Lines 94-99 my $biblio_with_no_item = $builder->build_sample_biblio; Link Here
94
my $testbarcode = '97531';
94
my $testbarcode = '97531';
95
$item->barcode($testbarcode)->store; # FIXME We should not hardcode a barcode! Also, what's the purpose of this?
95
$item->barcode($testbarcode)->store; # FIXME We should not hardcode a barcode! Also, what's the purpose of this?
96
96
97
97
# Create a borrower
98
# Create a borrower
98
my %data = (
99
my %data = (
99
    firstname =>  'my firstname',
100
    firstname =>  'my firstname',
Lines 106-112 my $borrowernumber = Koha::Patron->new(\%data)->store->borrowernumber; Link Here
106
my $patron = Koha::Patrons->find( $borrowernumber );
107
my $patron = Koha::Patrons->find( $borrowernumber );
107
my $borrower = $patron->unblessed;
108
my $borrower = $patron->unblessed;
108
my $biblionumber   = $bibnum;
109
my $biblionumber   = $bibnum;
109
my $barcode        = $testbarcode;
110
110
111
my $branchcode = Koha::Libraries->search->next->branchcode;
111
my $branchcode = Koha::Libraries->search->next->branchcode;
112
112
Lines 119-136 AddReserve( Link Here
119
    }
119
    }
120
);
120
);
121
121
122
my ($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber, $barcode);
122
my ($status, $reserve, $all_reserves) = CheckReserves( $item );
123
123
124
is($status, "Reserved", "CheckReserves Test 1");
124
is($status, "Reserved", "CheckReserves Test 1");
125
125
126
ok(exists($reserve->{reserve_id}), 'CheckReserves() include reserve_id in its response');
126
ok(exists($reserve->{reserve_id}), 'CheckReserves() include reserve_id in its response');
127
127
128
($status, $reserve, $all_reserves) = CheckReserves($item->itemnumber);
128
($status, $reserve, $all_reserves) = CheckReserves( $item );
129
is($status, "Reserved", "CheckReserves Test 2");
129
is($status, "Reserved", "CheckReserves Test 2");
130
130
131
($status, $reserve, $all_reserves) = CheckReserves(undef, $barcode);
132
is($status, "Reserved", "CheckReserves Test 3");
133
134
my $ReservesControlBranch = C4::Context->preference('ReservesControlBranch');
131
my $ReservesControlBranch = C4::Context->preference('ReservesControlBranch');
135
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'ItemHomeLibrary' );
132
t::lib::Mocks::mock_preference( 'ReservesControlBranch', 'ItemHomeLibrary' );
136
ok(
133
ok(
Lines 345-353 AddReserve( Link Here
345
        priority       => 1,
342
        priority       => 1,
346
    }
343
    }
347
);
344
);
348
($status)=CheckReserves($item->itemnumber,undef,undef);
345
($status)=CheckReserves( $item );
349
is( $status, 'Reserved', 'CheckReserves returns reserve without lookahead');
346
is( $status, 'Reserved', 'CheckReserves returns reserve without lookahead');
350
($status)=CheckReserves($item->itemnumber,undef,7);
347
($status)=CheckReserves( $item, 7 );
351
is( $status, 'Reserved', 'CheckReserves also returns reserve with lookahead');
348
is( $status, 'Reserved', 'CheckReserves also returns reserve with lookahead');
352
349
353
# Test 9761b: Add a reserve with future date, CheckReserve should not return it
350
# Test 9761b: Add a reserve with future date, CheckReserve should not return it
Lines 364-389 my $reserve_id = AddReserve( Link Here
364
        reservation_date => $resdate,
361
        reservation_date => $resdate,
365
    }
362
    }
366
);
363
);
367
($status)=CheckReserves($item->itemnumber,undef,undef);
364
($status)=CheckReserves( $item );
368
is( $status, '', 'CheckReserves returns no future reserve without lookahead');
365
is( $status, '', 'CheckReserves returns no future reserve without lookahead');
369
366
370
# Test 9761c: Add a reserve with future date, CheckReserve should return it if lookahead is high enough
367
# Test 9761c: Add a reserve with future date, CheckReserve should return it if lookahead is high enough
371
($status)=CheckReserves($item->itemnumber,undef,3);
368
($status)=CheckReserves( $item, 3 );
372
is( $status, '', 'CheckReserves returns no future reserve with insufficient lookahead');
369
is( $status, '', 'CheckReserves returns no future reserve with insufficient lookahead');
373
($status)=CheckReserves($item->itemnumber,undef,4);
370
($status)=CheckReserves( $item, 4 );
374
is( $status, 'Reserved', 'CheckReserves returns future reserve with sufficient lookahead');
371
is( $status, 'Reserved', 'CheckReserves returns future reserve with sufficient lookahead');
375
372
376
# Test 9761d: Check ResFound message of AddReturn for future hold
373
# Test 9761d: Check ResFound message of AddReturn for future hold
377
# Note that AddReturn is in Circulation.pm, but this test really pertains to reserves; AddReturn uses the ConfirmFutureHolds pref when calling CheckReserves
374
# Note that AddReturn is in Circulation.pm, but this test really pertains to reserves; AddReturn uses the ConfirmFutureHolds pref when calling CheckReserves
378
# In this test we do not need an issued item; it is just a 'checkin'
375
# In this test we do not need an issued item; it is just a 'checkin'
379
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 0);
376
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 0);
380
(my $doreturn, $messages)= AddReturn('97531',$branch_1);
377
(my $doreturn, $messages)= AddReturn($testbarcode,$branch_1);
381
is($messages->{ResFound}//'', '', 'AddReturn does not care about future reserve when ConfirmFutureHolds is off');
378
is($messages->{ResFound}//'', '', 'AddReturn does not care about future reserve when ConfirmFutureHolds is off');
382
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 3);
379
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 3);
383
($doreturn, $messages)= AddReturn('97531',$branch_1);
380
($doreturn, $messages)= AddReturn($testbarcode,$branch_1);
384
is(exists $messages->{ResFound}?1:0, 0, 'AddReturn ignores future reserve beyond ConfirmFutureHolds days');
381
is(exists $messages->{ResFound}?1:0, 0, 'AddReturn ignores future reserve beyond ConfirmFutureHolds days');
385
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 7);
382
t::lib::Mocks::mock_preference('ConfirmFutureHolds', 7);
386
($doreturn, $messages)= AddReturn('97531',$branch_1);
383
($doreturn, $messages)= AddReturn($testbarcode,$branch_1);
387
is(exists $messages->{ResFound}?1:0, 1, 'AddReturn considers future reserve within ConfirmFutureHolds days');
384
is(exists $messages->{ResFound}?1:0, 1, 'AddReturn considers future reserve within ConfirmFutureHolds days');
388
385
389
my $now_holder = $builder->build_object({ class => 'Koha::Patrons', value => {
386
my $now_holder = $builder->build_object({ class => 'Koha::Patrons', value => {
Lines 399-407 my $now_reserve_id = AddReserve( Link Here
399
    }
396
    }
400
);
397
);
401
my $which_highest;
398
my $which_highest;
402
($status,$which_highest)=CheckReserves($item->itemnumber,undef,3);
399
($status,$which_highest)=CheckReserves( $item, 3 );
403
is( $which_highest->{reserve_id}, $now_reserve_id, 'CheckReserves returns lower priority current reserve with insufficient lookahead');
400
is( $which_highest->{reserve_id}, $now_reserve_id, 'CheckReserves returns lower priority current reserve with insufficient lookahead');
404
($status, $which_highest)=CheckReserves($item->itemnumber,undef,4);
401
($status, $which_highest)=CheckReserves( $item, 4 );
405
is( $which_highest->{reserve_id}, $reserve_id, 'CheckReserves returns higher priority future reserve with sufficient lookahead');
402
is( $which_highest->{reserve_id}, $reserve_id, 'CheckReserves returns higher priority future reserve with sufficient lookahead');
406
ModReserve({ reserve_id => $now_reserve_id, rank => 'del', cancellation_reason => 'test reserve' });
403
ModReserve({ reserve_id => $now_reserve_id, rank => 'del', cancellation_reason => 'test reserve' });
407
404
Lines 586-592 AddReserve( Link Here
586
        priority       => 1,
583
        priority       => 1,
587
    }
584
    }
588
);
585
);
589
my (undef, $canres, undef) = CheckReserves($item->itemnumber);
586
my (undef, $canres, undef) = CheckReserves( $item );
590
587
591
is( CanReserveBeCanceledFromOpac(), undef,
588
is( CanReserveBeCanceledFromOpac(), undef,
592
    'CanReserveBeCanceledFromOpac should return undef if called without any parameter'
589
    'CanReserveBeCanceledFromOpac should return undef if called without any parameter'
Lines 624-630 AddReserve( Link Here
624
        priority       => 1,
621
        priority       => 1,
625
    }
622
    }
626
);
623
);
627
(undef, $canres, undef) = CheckReserves($item->itemnumber);
624
(undef, $canres, undef) = CheckReserves( $item );
628
625
629
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 0);
626
ModReserveAffect($item->itemnumber, $requesters{$branch_1}, 0);
630
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
627
$cancancel = CanReserveBeCanceledFromOpac($canres->{reserve_id}, $requesters{$branch_1});
Lines 708-714 AddReserve( Link Here
708
    }
705
    }
709
);
706
);
710
MoveReserve( $item->itemnumber, $borrowernumber );
707
MoveReserve( $item->itemnumber, $borrowernumber );
711
($status)=CheckReserves( $item->itemnumber );
708
($status)=CheckReserves( $item );
712
is( $status, '', 'MoveReserve filled hold');
709
is( $status, '', 'MoveReserve filled hold');
713
#   hold from A waiting, today, no fut holds: MoveReserve should fill it
710
#   hold from A waiting, today, no fut holds: MoveReserve should fill it
714
AddReserve(
711
AddReserve(
Lines 721-727 AddReserve( Link Here
721
    }
718
    }
722
);
719
);
723
MoveReserve( $item->itemnumber, $borrowernumber );
720
MoveReserve( $item->itemnumber, $borrowernumber );
724
($status)=CheckReserves( $item->itemnumber );
721
($status)=CheckReserves( $item );
725
is( $status, '', 'MoveReserve filled waiting hold');
722
is( $status, '', 'MoveReserve filled waiting hold');
726
#   hold from A pos 1, tomorrow, no fut holds: not filled
723
#   hold from A pos 1, tomorrow, no fut holds: not filled
727
$resdate= dt_from_string();
724
$resdate= dt_from_string();
Lines 736-742 AddReserve( Link Here
736
    }
733
    }
737
);
734
);
738
MoveReserve( $item->itemnumber, $borrowernumber );
735
MoveReserve( $item->itemnumber, $borrowernumber );
739
($status)=CheckReserves( $item->itemnumber, undef, 1 );
736
($status)=CheckReserves( $item, 1 );
740
is( $status, 'Reserved', 'MoveReserve did not fill future hold');
737
is( $status, 'Reserved', 'MoveReserve did not fill future hold');
741
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
738
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
742
#   hold from A pos 1, tomorrow, fut holds=2: MoveReserve should fill it
739
#   hold from A pos 1, tomorrow, fut holds=2: MoveReserve should fill it
Lines 751-757 AddReserve( Link Here
751
    }
748
    }
752
);
749
);
753
MoveReserve( $item->itemnumber, $borrowernumber );
750
MoveReserve( $item->itemnumber, $borrowernumber );
754
($status)=CheckReserves( $item->itemnumber, undef, 2 );
751
($status)=CheckReserves( $item, undef, 2 );
755
is( $status, '', 'MoveReserve filled future hold now');
752
is( $status, '', 'MoveReserve filled future hold now');
756
#   hold from A waiting, tomorrow, fut holds=2: MoveReserve should fill it
753
#   hold from A waiting, tomorrow, fut holds=2: MoveReserve should fill it
757
AddReserve(
754
AddReserve(
Lines 764-770 AddReserve( Link Here
764
    }
761
    }
765
);
762
);
766
MoveReserve( $item->itemnumber, $borrowernumber );
763
MoveReserve( $item->itemnumber, $borrowernumber );
767
($status)=CheckReserves( $item->itemnumber, undef, 2 );
764
($status)=CheckReserves( $item, undef, 2 );
768
is( $status, '', 'MoveReserve filled future waiting hold now');
765
is( $status, '', 'MoveReserve filled future waiting hold now');
769
#   hold from A pos 1, today+3, fut holds=2: MoveReserve should not fill it
766
#   hold from A pos 1, today+3, fut holds=2: MoveReserve should not fill it
770
$resdate= dt_from_string();
767
$resdate= dt_from_string();
Lines 779-785 AddReserve( Link Here
779
    }
776
    }
780
);
777
);
781
MoveReserve( $item->itemnumber, $borrowernumber );
778
MoveReserve( $item->itemnumber, $borrowernumber );
782
($status)=CheckReserves( $item->itemnumber, undef, 3 );
779
($status)=CheckReserves( $item, 3 );
783
is( $status, 'Reserved', 'MoveReserve did not fill future hold of 3 days');
780
is( $status, 'Reserved', 'MoveReserve did not fill future hold of 3 days');
784
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
781
$dbh->do('DELETE FROM reserves', undef, ($bibnum));
785
782
Lines 1241-1247 subtest 'CheckReserves additional tests' => sub { Link Here
1241
    ModReserveAffect( $item->itemnumber, $reserve1->borrowernumber, 1,
1238
    ModReserveAffect( $item->itemnumber, $reserve1->borrowernumber, 1,
1242
        $reserve1->reserve_id );
1239
        $reserve1->reserve_id );
1243
    my ( $status, $matched_reserve, $possible_reserves ) =
1240
    my ( $status, $matched_reserve, $possible_reserves ) =
1244
      CheckReserves( $item->itemnumber );
1241
      CheckReserves( $item );
1245
1242
1246
    is( $status, 'Transferred', "We found a reserve" );
1243
    is( $status, 'Transferred', "We found a reserve" );
1247
    is( $matched_reserve->{reserve_id},
1244
    is( $matched_reserve->{reserve_id},
Lines 1284-1290 subtest 'CheckReserves additional tests' => sub { Link Here
1284
1281
1285
    ok( $reserve_id, "We can place a record level hold because one item is owned by patron's home library");
1282
    ok( $reserve_id, "We can place a record level hold because one item is owned by patron's home library");
1286
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
1283
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
1287
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A->itemnumber );
1284
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A );
1288
    is( $status, "", "We do not fill the hold with item A because it is not from the patron's homebranch");
1285
    is( $status, "", "We do not fill the hold with item A because it is not from the patron's homebranch");
1289
    Koha::CirculationRules->set_rule({
1286
    Koha::CirculationRules->set_rule({
1290
        branchcode => $item_A->homebranch,
1287
        branchcode => $item_A->homebranch,
Lines 1292-1304 subtest 'CheckReserves additional tests' => sub { Link Here
1292
        rule_name  => 'holdallowed',
1289
        rule_name  => 'holdallowed',
1293
        rule_value => 'from_any_library'
1290
        rule_value => 'from_any_library'
1294
    });
1291
    });
1295
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A->itemnumber );
1292
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A );
1296
    is( $status, "Reserved", "We fill the hold with item A because item's branch rule says allow any");
1293
    is( $status, "Reserved", "We fill the hold with item A because item's branch rule says allow any");
1297
1294
1298
1295
1299
    # Changing the control branch should change only the rule we get
1296
    # Changing the control branch should change only the rule we get
1300
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
1297
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
1301
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A->itemnumber );
1298
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A );
1302
    is( $status, "", "We do not fill the hold with item A because it is not from the patron's homebranch");
1299
    is( $status, "", "We do not fill the hold with item A because it is not from the patron's homebranch");
1303
    Koha::CirculationRules->set_rule({
1300
    Koha::CirculationRules->set_rule({
1304
        branchcode   => $patron_B->branchcode,
1301
        branchcode   => $patron_B->branchcode,
Lines 1306-1312 subtest 'CheckReserves additional tests' => sub { Link Here
1306
        rule_name  => 'holdallowed',
1303
        rule_name  => 'holdallowed',
1307
        rule_value => 'from_any_library'
1304
        rule_value => 'from_any_library'
1308
    });
1305
    });
1309
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A->itemnumber );
1306
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A );
1310
    is( $status, "Reserved", "We fill the hold with item A because patron's branch rule says allow any");
1307
    is( $status, "Reserved", "We fill the hold with item A because patron's branch rule says allow any");
1311
1308
1312
};
1309
};
1313
- 

Return to bug 31735