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 957-966 sub CanBookBeIssued { Link Here
957
                and C4::Context->preference('SwitchOnSiteCheckouts') ) {
957
                and C4::Context->preference('SwitchOnSiteCheckouts') ) {
958
            $messages{ONSITE_CHECKOUT_WILL_BE_SWITCHED} = 1;
958
            $messages{ONSITE_CHECKOUT_WILL_BE_SWITCHED} = 1;
959
        } else {
959
        } else {
960
            my ($CanBookBeRenewed,$renewerror) = CanBookBeRenewed(
960
            my ($CanBookBeRenewed,$renewerror) = CanBookBeRenewed($patron, $issue);
961
                $patron->borrowernumber,
962
                $item_object->itemnumber,
963
            );
964
            if ( $CanBookBeRenewed == 0 ) {    # no more renewals allowed
961
            if ( $CanBookBeRenewed == 0 ) {    # no more renewals allowed
965
                if ( $renewerror eq 'onsite_checkout' ) {
962
                if ( $renewerror eq 'onsite_checkout' ) {
966
                    $issuingimpossible{NO_RENEWAL_FOR_ONSITE_CHECKOUTS} = 1;
963
                    $issuingimpossible{NO_RENEWAL_FOR_ONSITE_CHECKOUTS} = 1;
Lines 982-999 sub CanBookBeIssued { Link Here
982
979
983
        my ( $can_be_returned, $message ) = CanBookBeReturned( $item_unblessed, C4::Context->userenv->{branch} );
980
        my ( $can_be_returned, $message ) = CanBookBeReturned( $item_unblessed, C4::Context->userenv->{branch} );
984
981
985
        unless ( $can_be_returned ) {
982
        if ( !$can_be_returned ) {
986
            $issuingimpossible{RETURN_IMPOSSIBLE} = 1;
983
            $issuingimpossible{RETURN_IMPOSSIBLE} = 1;
987
            $issuingimpossible{branch_to_return} = $message;
984
            $issuingimpossible{branch_to_return} = $message;
988
        } else {
985
        } else {
989
            if ( C4::Context->preference('AutoReturnCheckedOutItems') ) {
986
            if ( C4::Context->preference('AutoReturnCheckedOutItems') ) {
990
                $alerts{RETURNED_FROM_ANOTHER} = { patron => $patron };
987
                $alerts{RETURNED_FROM_ANOTHER} = { patron => $patron };
991
            } else {
988
            }
992
            $needsconfirmation{ISSUED_TO_ANOTHER} = 1;
989
            else {
993
            $needsconfirmation{issued_firstname} = $patron->firstname;
990
                $needsconfirmation{ISSUED_TO_ANOTHER} = 1;
994
            $needsconfirmation{issued_surname} = $patron->surname;
991
                $needsconfirmation{issued_firstname} = $patron->firstname;
995
            $needsconfirmation{issued_cardnumber} = $patron->cardnumber;
992
                $needsconfirmation{issued_surname} = $patron->surname;
996
            $needsconfirmation{issued_borrowernumber} = $patron->borrowernumber;
993
                $needsconfirmation{issued_cardnumber} = $patron->cardnumber;
994
                $needsconfirmation{issued_borrowernumber} = $patron->borrowernumber;
997
            }
995
            }
998
        }
996
        }
999
    }
997
    }
Lines 1026-1034 sub CanBookBeIssued { Link Here
1026
    # CHECKPREVCHECKOUT: CHECK IF ITEM HAS EVER BEEN LENT TO PATRON
1024
    # CHECKPREVCHECKOUT: CHECK IF ITEM HAS EVER BEEN LENT TO PATRON
1027
    #
1025
    #
1028
    $patron = Koha::Patrons->find( $patron->borrowernumber ); # FIXME Refetch just in case, to avoid regressions. But must not be needed
1026
    $patron = Koha::Patrons->find( $patron->borrowernumber ); # FIXME Refetch just in case, to avoid regressions. But must not be needed
1029
    my $wants_check = $patron->wants_check_for_previous_checkout;
1027
    if ( $patron->wants_check_for_previous_checkout && $patron->do_check_for_previous_checkout($item_unblessed) ) {
1030
    $needsconfirmation{PREVISSUE} = 1
1028
        $needsconfirmation{PREVISSUE} = 1;
1031
        if ($wants_check and $patron->do_check_for_previous_checkout($item_unblessed));
1029
    }
1032
1030
1033
    #
1031
    #
1034
    # ITEM CHECKING
1032
    # ITEM CHECKING
Lines 1166-1172 sub CanBookBeIssued { Link Here
1166
1164
1167
    unless ( $ignore_reserves and defined $recall ) {
1165
    unless ( $ignore_reserves and defined $recall ) {
1168
        # See if the item is on reserve.
1166
        # See if the item is on reserve.
1169
        my ( $restype, $res ) = C4::Reserves::CheckReserves( $item_object->itemnumber );
1167
        my ( $restype, $res ) = CheckReserves( $item_object );
1170
        if ($restype) {
1168
        if ($restype) {
1171
            my $resbor = $res->{'borrowernumber'};
1169
            my $resbor = $res->{'borrowernumber'};
1172
            if ( $resbor ne $patron->borrowernumber ) {
1170
            if ( $resbor ne $patron->borrowernumber ) {
Lines 2356-2362 sub AddReturn { Link Here
2356
    # launch the Checkreserves routine to find any holds
2354
    # launch the Checkreserves routine to find any holds
2357
    my ($resfound, $resrec);
2355
    my ($resfound, $resrec);
2358
    my $lookahead= C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2356
    my $lookahead= C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2359
    ($resfound, $resrec, undef) = C4::Reserves::CheckReserves( $item->itemnumber, undef, $lookahead ) unless ( $item->withdrawn );
2357
    ($resfound, $resrec, undef) = CheckReserves( $item, $lookahead ) unless ( $item->withdrawn );
2360
    # 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)
2358
    # 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)
2361
    if ( $resfound and $resfound eq "Waiting" and $branch ne $resrec->{branchcode} ) {
2359
    if ( $resfound and $resfound eq "Waiting" and $branch ne $resrec->{branchcode} ) {
2362
        my $hold = C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
2360
        my $hold = C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
Lines 2852-2865 sub GetUpcomingDueIssues { Link Here
2852
2850
2853
=head2 CanBookBeRenewed
2851
=head2 CanBookBeRenewed
2854
2852
2855
  ($ok,$error,$info) = &CanBookBeRenewed($borrowernumber, $itemnumber[, $override_limit]);
2853
  ($ok,$error,$info) = &CanBookBeRenewed($patron, $issue, $override_limit);
2856
2854
2857
Find out whether a borrowed item may be renewed.
2855
Find out whether a borrowed item may be renewed.
2858
2856
2859
C<$borrowernumber> is the borrower number of the patron who currently
2857
C<$patron> is the patron who currently has the issue.
2860
has the item on loan.
2861
2858
2862
C<$itemnumber> is the number of the item to renew.
2859
C<$issue> is the checkout to renew.
2863
2860
2864
C<$override_limit>, if supplied with a true value, causes
2861
C<$override_limit>, if supplied with a true value, causes
2865
the limit on the number of times that the loan can be renewed
2862
the limit on the number of times that the loan can be renewed
Lines 2878-2896 already renewed the loan. Link Here
2878
=cut
2875
=cut
2879
2876
2880
sub CanBookBeRenewed {
2877
sub CanBookBeRenewed {
2881
    my ( $borrowernumber, $itemnumber, $override_limit, $cron ) = @_;
2878
    my ( $patron, $issue, $override_limit, $cron ) = @_;
2882
2879
2883
    my $auto_renew = "no";
2880
    my $auto_renew = "no";
2884
    my $soonest;
2881
    my $soonest;
2882
    my $item = $issue->item;
2885
2883
2886
    my $item      = Koha::Items->find($itemnumber)      or return ( 0, 'no_item' );
2884
    return ( 0, 'no_item' ) unless $item;
2887
    my $issue = $item->checkout or return ( 0, 'no_checkout' );
2885
    return ( 0, 'no_checkout' ) unless $issue;
2888
    return ( 0, 'onsite_checkout' ) if $issue->onsite_checkout;
2886
    return ( 0, 'onsite_checkout' ) if $issue->onsite_checkout;
2887
    return ( 0, 'item_issued_to_other_patron') if $issue->borrowernumber != $patron->borrowernumber;
2889
    return ( 0, 'item_denied_renewal') if $item->is_denied_renewal;
2888
    return ( 0, 'item_denied_renewal') if $item->is_denied_renewal;
2890
2889
2891
    my $patron = $issue->patron or return;
2890
       # override_limit will override anything else except on_reserve
2892
2893
    # override_limit will override anything else except on_reserve
2894
    unless ( $override_limit ){
2891
    unless ( $override_limit ){
2895
        my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
2892
        my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
2896
        my $issuing_rule = Koha::CirculationRules->get_effective_rules(
2893
        my $issuing_rule = Koha::CirculationRules->get_effective_rules(
Lines 2916-2922 sub CanBookBeRenewed { Link Here
2916
2913
2917
        my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing');
2914
        my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing');
2918
        my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
2915
        my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
2919
        $patron         = Koha::Patrons->find($borrowernumber); # FIXME Is this really useful?
2920
        my $restricted  = $patron->is_debarred;
2916
        my $restricted  = $patron->is_debarred;
2921
        my $hasoverdues = $patron->has_overdues;
2917
        my $hasoverdues = $patron->has_overdues;
2922
2918
Lines 2960-2968 sub CanBookBeRenewed { Link Here
2960
            non_priority => 0,
2956
            non_priority => 0,
2961
            found        => undef,
2957
            found        => undef,
2962
            reservedate  => { '<=' => \'NOW()' },
2958
            reservedate  => { '<=' => \'NOW()' },
2963
            suspend      => 0,
2959
            suspend      => 0
2964
        },
2960
        }
2965
        { prefetch => 'patron' }
2966
    );
2961
    );
2967
    if ( $fillable_holds->count ) {
2962
    if ( $fillable_holds->count ) {
2968
        if ( C4::Context->preference('AllowRenewalIfOtherItemsAvailable') ) {
2963
        if ( C4::Context->preference('AllowRenewalIfOtherItemsAvailable') ) {
Lines 2974-2980 sub CanBookBeRenewed { Link Here
2974
                biblionumber => $item->biblionumber,
2969
                biblionumber => $item->biblionumber,
2975
                onloan       => undef,
2970
                onloan       => undef,
2976
                notforloan   => 0,
2971
                notforloan   => 0,
2977
                -not         => { itemnumber => $itemnumber } })->as_list;
2972
                -not         => { itemnumber => $item->itemnumber } })->as_list;
2978
2973
2979
            return ( 0, "on_reserve" ) if @possible_holds && (scalar @other_items < scalar @possible_holds);
2974
            return ( 0, "on_reserve" ) if @possible_holds && (scalar @other_items < scalar @possible_holds);
2980
2975
Lines 2982-2988 sub CanBookBeRenewed { Link Here
2982
            foreach my $possible_hold (@possible_holds) {
2977
            foreach my $possible_hold (@possible_holds) {
2983
                my $fillable = 0;
2978
                my $fillable = 0;
2984
                my $patron_with_reserve = Koha::Patrons->find($possible_hold->borrowernumber);
2979
                my $patron_with_reserve = Koha::Patrons->find($possible_hold->borrowernumber);
2985
                my $items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $item->biblionumber, patron => $patron_with_reserve });
2980
                my $items_any_available = ItemsAnyAvailableAndNotRestricted({
2981
                    biblionumber => $item->biblionumber,
2982
                    patron => $patron_with_reserve
2983
                });
2986
2984
2987
                # FIXME: We are not checking whether the item we are renewing can fill the hold
2985
                # FIXME: We are not checking whether the item we are renewing can fill the hold
2988
2986
Lines 3000-3014 sub CanBookBeRenewed { Link Here
3000
                }
2998
                }
3001
                return ( 0, "on_reserve" ) unless $fillable;
2999
                return ( 0, "on_reserve" ) unless $fillable;
3002
            }
3000
            }
3003
3001
        }
3004
        } else {
3002
        else {
3005
            my ($status, $matched_reserve, $possible_reserves) = CheckReserves($itemnumber);
3003
            my ($status, $matched_reserve, $possible_reserves) = CheckReserves($item);
3006
            return ( 0, "on_reserve" ) if $status;
3004
            return ( 0, "on_reserve" ) if $status;
3007
        }
3005
        }
3008
    }
3006
    }
3009
3007
3010
    return ( 0, $auto_renew, { soonest_renew_date => $soonest } ) if $auto_renew =~ 'too_soon';#$auto_renew ne "no" && $auto_renew ne "ok";
3008
    return ( 0, $auto_renew, { soonest_renew_date => $soonest } ) if $auto_renew =~ 'too_soon';#$auto_renew ne "no" && $auto_renew ne "ok";
3011
    $soonest = GetSoonestRenewDate($issue);
3009
    $soonest = GetSoonestRenewDate($patron, $issue);
3012
    if ( $soonest > dt_from_string() ){
3010
    if ( $soonest > dt_from_string() ){
3013
        return (0, "too_soon", { soonest_renew_date => $soonest } ) unless $override_limit;
3011
        return (0, "too_soon", { soonest_renew_date => $soonest } ) unless $override_limit;
3014
    }
3012
    }
Lines 3247-3253 sub AddRenewal { Link Here
3247
3245
3248
sub GetRenewCount {
3246
sub GetRenewCount {
3249
    # check renewal status
3247
    # check renewal status
3250
    my ( $bornum, $itemno ) = @_;
3248
    my ( $borrowernumber_or_patron, $itemnumber_or_item ) = @_;
3249
3251
    my $dbh           = C4::Context->dbh;
3250
    my $dbh           = C4::Context->dbh;
3252
    my $renewcount    = 0;
3251
    my $renewcount    = 0;
3253
    my $unseencount    = 0;
3252
    my $unseencount    = 0;
Lines 3255-3263 sub GetRenewCount { Link Here
3255
    my $unseenallowed = 0;
3254
    my $unseenallowed = 0;
3256
    my $renewsleft    = 0;
3255
    my $renewsleft    = 0;
3257
    my $unseenleft    = 0;
3256
    my $unseenleft    = 0;
3258
3257
    my $patron = blessed $borrowernumber_or_patron ?
3259
    my $patron = Koha::Patrons->find( $bornum );
3258
        $borrowernumber_or_patron : Koha::Patrons->find($borrowernumber_or_patron);
3260
    my $item   = Koha::Items->find($itemno);
3259
    my $item = blessed $itemnumber_or_item ?
3260
        $itemnumber_or_item : Koha::Items->find($itemnumber_or_item);
3261
3261
3262
    return (0, 0, 0, 0, 0, 0) unless $patron or $item; # Wrong call, no renewal allowed
3262
    return (0, 0, 0, 0, 0, 0) unless $patron or $item; # Wrong call, no renewal allowed
3263
3263
Lines 3265-3276 sub GetRenewCount { Link Here
3265
    # and not yet returned.
3265
    # and not yet returned.
3266
3266
3267
    # FIXME - I think this function could be redone to use only one SQL call.
3267
    # FIXME - I think this function could be redone to use only one SQL call.
3268
    my $sth = $dbh->prepare(
3268
    my $sth = $dbh->prepare(q{
3269
        "select * from issues
3269
        SELECT * FROM issues
3270
                                where (borrowernumber = ?)
3270
        WHERE  (borrowernumber = ?) AND (itemnumber = ?)
3271
                                and (itemnumber = ?)"
3271
    });
3272
    );
3272
    $sth->execute( $patron->borrowernumber, $item->itemnumber );
3273
    $sth->execute( $bornum, $itemno );
3274
    my $data = $sth->fetchrow_hashref;
3273
    my $data = $sth->fetchrow_hashref;
3275
    $renewcount = $data->{'renewals_count'} if $data->{'renewals_count'};
3274
    $renewcount = $data->{'renewals_count'} if $data->{'renewals_count'};
3276
    $unseencount = $data->{'unseen_renewals'} if $data->{'unseen_renewals'};
3275
    $unseencount = $data->{'unseen_renewals'} if $data->{'unseen_renewals'};
Lines 3305-3315 sub GetRenewCount { Link Here
3305
3304
3306
=head2 GetSoonestRenewDate
3305
=head2 GetSoonestRenewDate
3307
3306
3308
  $NoRenewalBeforeThisDate = &GetSoonestRenewDate($checkout);
3307
  $NoRenewalBeforeThisDate = &GetSoonestRenewDate($patron, $issue);
3309
3308
3310
Find out the soonest possible renew date of a borrowed item.
3309
Find out the soonest possible renew date of a borrowed item.
3311
3310
3312
C<$checkout> is the checkout object to renew.
3311
C<$patron> is the patron who currently has the item on loan.
3312
3313
C<$issue> is the the item issue.
3313
3314
3314
C<$GetSoonestRenewDate> returns the DateTime of the soonest possible
3315
C<$GetSoonestRenewDate> returns the DateTime of the soonest possible
3315
renew date, based on the value "No renewal before" of the applicable
3316
renew date, based on the value "No renewal before" of the applicable
Lines 3320-3329 cannot be found. Link Here
3320
=cut
3321
=cut
3321
3322
3322
sub GetSoonestRenewDate {
3323
sub GetSoonestRenewDate {
3323
    my ( $checkout ) = @_;
3324
    my ( $patron, $issue ) = @_;
3325
    return unless $issue;
3326
    return unless $patron;
3324
3327
3325
    my $item   = $checkout->item or return;
3328
    my $item = $issue->item;
3326
    my $patron = $checkout->patron or return;
3329
    return unless $item;
3330
3331
    my $dbh = C4::Context->dbh;
3327
3332
3328
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3333
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3329
    my $issuing_rule = Koha::CirculationRules->get_effective_rules(
3334
    my $issuing_rule = Koha::CirculationRules->get_effective_rules(
Lines 3343-3349 sub GetSoonestRenewDate { Link Here
3343
        and $issuing_rule->{norenewalbefore} ne "" )
3348
        and $issuing_rule->{norenewalbefore} ne "" )
3344
    {
3349
    {
3345
        my $soonestrenewal =
3350
        my $soonestrenewal =
3346
          dt_from_string( $checkout->date_due )->subtract(
3351
          dt_from_string( $issue->date_due )->subtract(
3347
            $issuing_rule->{lengthunit} => $issuing_rule->{norenewalbefore} );
3352
            $issuing_rule->{lengthunit} => $issuing_rule->{norenewalbefore} );
3348
3353
3349
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
3354
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
Lines 3352-3360 sub GetSoonestRenewDate { Link Here
3352
            $soonestrenewal->truncate( to => 'day' );
3357
            $soonestrenewal->truncate( to => 'day' );
3353
        }
3358
        }
3354
        return $soonestrenewal if $now < $soonestrenewal;
3359
        return $soonestrenewal if $now < $soonestrenewal;
3355
    } elsif ( $checkout->auto_renew && $patron->autorenew_checkouts ) {
3360
    } elsif ( $issue->auto_renew && $patron->autorenew_checkouts ) {
3356
        # Checkouts with auto-renewing fall back to due date
3361
        # Checkouts with auto-renewing fall back to due date
3357
        my $soonestrenewal = dt_from_string( $checkout->date_due );
3362
        my $soonestrenewal = dt_from_string( $issue->date_due );
3358
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
3363
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
3359
            and $issuing_rule->{lengthunit} eq 'days' )
3364
            and $issuing_rule->{lengthunit} eq 'days' )
3360
        {
3365
        {
Lines 3367-3380 sub GetSoonestRenewDate { Link Here
3367
3372
3368
=head2 GetLatestAutoRenewDate
3373
=head2 GetLatestAutoRenewDate
3369
3374
3370
  $NoAutoRenewalAfterThisDate = &GetLatestAutoRenewDate($borrowernumber, $itemnumber);
3375
  $NoAutoRenewalAfterThisDate = &GetLatestAutoRenewDate($patron, $issue);
3371
3376
3372
Find out the latest possible auto renew date of a borrowed item.
3377
Find out the latest possible auto renew date of a borrowed item.
3373
3378
3374
C<$borrowernumber> is the borrower number of the patron who currently
3379
C<$patron> is the patron who currently has the item on loan.
3375
has the item on loan.
3376
3380
3377
C<$itemnumber> is the number of the item to renew.
3381
C<$issue> is the item issue.
3378
3382
3379
C<$GetLatestAutoRenewDate> returns the DateTime of the latest possible
3383
C<$GetLatestAutoRenewDate> returns the DateTime of the latest possible
3380
auto renew date, based on the value "No auto renewal after" and the "No auto
3384
auto renew date, based on the value "No auto renewal after" and the "No auto
Lines 3385-3400 or item cannot be found. Link Here
3385
=cut
3389
=cut
3386
3390
3387
sub GetLatestAutoRenewDate {
3391
sub GetLatestAutoRenewDate {
3388
    my ( $borrowernumber, $itemnumber ) = @_;
3392
    my ( $patron, $issue ) = @_;
3389
3393
    return unless $issue;
3390
    my $dbh = C4::Context->dbh;
3394
    return unless $patron;
3391
3395
3392
    my $item      = Koha::Items->find($itemnumber)  or return;
3396
    my $item = $issue->item;
3393
    my $itemissue = $item->checkout                 or return;
3397
    return unless $item;
3394
3398
3395
    $borrowernumber ||= $itemissue->borrowernumber;
3399
    my $dbh = C4::Context->dbh;
3396
    my $patron = Koha::Patrons->find( $borrowernumber )
3397
      or return;
3398
3400
3399
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3401
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3400
    my $circulation_rules = Koha::CirculationRules->get_effective_rules(
3402
    my $circulation_rules = Koha::CirculationRules->get_effective_rules(
Lines 3419-3425 sub GetLatestAutoRenewDate { Link Here
3419
3421
3420
    my $maximum_renewal_date;
3422
    my $maximum_renewal_date;
3421
    if ( $circulation_rules->{no_auto_renewal_after} ) {
3423
    if ( $circulation_rules->{no_auto_renewal_after} ) {
3422
        $maximum_renewal_date = dt_from_string($itemissue->issuedate);
3424
        $maximum_renewal_date = dt_from_string($issue->issuedate);
3423
        $maximum_renewal_date->add(
3425
        $maximum_renewal_date->add(
3424
            $circulation_rules->{lengthunit} => $circulation_rules->{no_auto_renewal_after}
3426
            $circulation_rules->{lengthunit} => $circulation_rules->{no_auto_renewal_after}
3425
        );
3427
        );
Lines 3469-3481 sub GetIssuingCharges { Link Here
3469
3471
3470
    my $sth = $dbh->prepare($charge_query);
3472
    my $sth = $dbh->prepare($charge_query);
3471
    $sth->execute($itemnumber);
3473
    $sth->execute($itemnumber);
3474
    my $patron;
3472
    if ( my $item_data = $sth->fetchrow_hashref ) {
3475
    if ( my $item_data = $sth->fetchrow_hashref ) {
3473
        $item_type = $item_data->{itemtype};
3476
        $item_type = $item_data->{itemtype};
3474
        $charge    = $item_data->{rentalcharge};
3477
        $charge    = $item_data->{rentalcharge};
3475
        if ($charge) {
3478
        if ($charge) {
3476
            # FIXME This should follow CircControl
3479
            # FIXME This should follow CircControl
3477
            my $branch = C4::Context::mybranch();
3480
            my $branch = C4::Context::mybranch();
3478
            my $patron = Koha::Patrons->find( $borrowernumber );
3481
            $patron //= Koha::Patrons->find( $borrowernumber );
3479
            my $discount = Koha::CirculationRules->get_effective_rule({
3482
            my $discount = Koha::CirculationRules->get_effective_rule({
3480
                categorycode => $patron->categorycode,
3483
                categorycode => $patron->categorycode,
3481
                branchcode   => $branch,
3484
                branchcode   => $branch,
Lines 4412-4418 sub _CanBookBeAutoRenewed { Link Here
4412
        }
4415
        }
4413
    );
4416
    );
4414
4417
4415
    if ( $patron->category->effective_BlockExpiredPatronOpacActions and $patron->is_expired ) {
4418
    if ( $patron->is_expired && $patron->category->effective_BlockExpiredPatronOpacActions ) {
4416
        return 'auto_account_expired';
4419
        return 'auto_account_expired';
4417
    }
4420
    }
4418
4421
Lines 4448-4454 sub _CanBookBeAutoRenewed { Link Here
4448
        }
4451
        }
4449
    }
4452
    }
4450
4453
4451
    my $soonest = GetSoonestRenewDate($issue);
4454
    my $soonest = GetSoonestRenewDate($patron, $issue);
4452
    if ( $soonest > dt_from_string() )
4455
    if ( $soonest > dt_from_string() )
4453
    {
4456
    {
4454
        return ( "auto_too_soon", $soonest );
4457
        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 822-834 sub GetReserveStatus { Link Here
822
822
823
=head2 CheckReserves
823
=head2 CheckReserves
824
824
825
  ($status, $matched_reserve, $possible_reserves) = &CheckReserves($itemnumber);
825
  ($status, $matched_reserve, $possible_reserves) = &CheckReserves($item);
826
  ($status, $matched_reserve, $possible_reserves) = &CheckReserves(undef, $barcode);
826
  ($status, $matched_reserve, $possible_reserves) = &CheckReserves($item, $lookahead);
827
  ($status, $matched_reserve, $possible_reserves) = &CheckReserves($itemnumber,undef,$lookahead);
828
827
829
Find a book in the reserves.
828
Find a book in the reserves.
830
829
831
C<$itemnumber> is the book's item number.
830
C<$item> is the book's item.
832
C<$lookahead> is the number of days to look in advance for future reserves.
831
C<$lookahead> is the number of days to look in advance for future reserves.
833
832
834
As I understand it, C<&CheckReserves> looks for the given item in the
833
As I understand it, C<&CheckReserves> looks for the given item in the
Lines 850-914 table in the Koha database. Link Here
850
=cut
849
=cut
851
850
852
sub CheckReserves {
851
sub CheckReserves {
853
    my ( $item, $barcode, $lookahead_days, $ignore_borrowers) = @_;
852
    my ( $item, $lookahead_days, $ignore_borrowers ) = @_;
854
    my $dbh = C4::Context->dbh;
855
    my $sth;
856
    my $select;
857
    if (C4::Context->preference('item-level_itypes')){
858
	$select = "
859
           SELECT items.biblionumber,
860
           items.biblioitemnumber,
861
           itemtypes.notforloan,
862
           items.notforloan AS itemnotforloan,
863
           items.itemnumber,
864
           items.damaged,
865
           items.homebranch,
866
           items.holdingbranch
867
           FROM   items
868
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
869
           LEFT JOIN itemtypes   ON items.itype   = itemtypes.itemtype
870
        ";
871
    }
872
    else {
873
	$select = "
874
           SELECT items.biblionumber,
875
           items.biblioitemnumber,
876
           itemtypes.notforloan,
877
           items.notforloan AS itemnotforloan,
878
           items.itemnumber,
879
           items.damaged,
880
           items.homebranch,
881
           items.holdingbranch
882
           FROM   items
883
           LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
884
           LEFT JOIN itemtypes   ON biblioitems.itemtype   = itemtypes.itemtype
885
        ";
886
    }
887
888
    if ($item) {
889
        $sth = $dbh->prepare("$select WHERE itemnumber = ?");
890
        $sth->execute($item);
891
    }
892
    else {
893
        $sth = $dbh->prepare("$select WHERE barcode = ?");
894
        $sth->execute($barcode);
895
    }
896
    # note: we get the itemnumber because we might have started w/ just the barcode.  Now we know for sure we have it.
853
    # note: we get the itemnumber because we might have started w/ just the barcode.  Now we know for sure we have it.
897
    my ( $biblio, $bibitem, $notforloan_per_itemtype, $notforloan_per_item, $itemnumber, $damaged, $item_homebranch, $item_holdingbranch ) = $sth->fetchrow_array;
898
    return if ( $damaged && !C4::Context->preference('AllowHoldsOnDamagedItems') );
899
854
900
    return unless $itemnumber; # bail if we got nothing.
855
    return unless $item; # bail if we got nothing.
856
857
    return if ( $item->damaged && !C4::Context->preference('AllowHoldsOnDamagedItems') );
858
901
    # if item is not for loan it cannot be reserved either.....
859
    # if item is not for loan it cannot be reserved either.....
902
    # except where items.notforloan < 0 :  This indicates the item is holdable.
860
    # except where items.notforloan < 0 :  This indicates the item is holdable.
903
861
904
    my @SkipHoldTrapOnNotForLoanValue = split( '\|', C4::Context->preference('SkipHoldTrapOnNotForLoanValue') );
862
    my @SkipHoldTrapOnNotForLoanValue = split( '\|', C4::Context->preference('SkipHoldTrapOnNotForLoanValue') );
905
    return if grep { $_ eq $notforloan_per_item } @SkipHoldTrapOnNotForLoanValue;
863
    return if grep { $_ eq $item->notforloan } @SkipHoldTrapOnNotForLoanValue;
906
864
907
    my $dont_trap = C4::Context->preference('TrapHoldsOnOrder') ? ($notforloan_per_item > 0) : ($notforloan_per_item && 1 );
865
    my $dont_trap = C4::Context->preference('TrapHoldsOnOrder') ? $item->notforloan > 0 : $item->notforloan;
908
    return if $dont_trap or $notforloan_per_itemtype;
866
    if ( !$dont_trap ) {
867
        my $item_type = $item->effective_itemtype;
868
        if ( $item_type ) {
869
            return if Koha::ItemTypes->find( $item_type )->notforloan;
870
        }
871
    }
872
    else {
873
        return;
874
    }
909
875
910
    # Find this item in the reserves
876
    # Find this item in the reserves
911
    my @reserves = _Findgroupreserve( $bibitem, $biblio, $itemnumber, $lookahead_days, $ignore_borrowers);
877
    my @reserves = _Findgroupreserve( $item->biblionumber, $item->itemnumber, $lookahead_days, $ignore_borrowers);
912
878
913
    # $priority and $highest are used to find the most important item
879
    # $priority and $highest are used to find the most important item
914
    # in the list returned by &_Findgroupreserve. (The lower $priority,
880
    # in the list returned by &_Findgroupreserve. (The lower $priority,
Lines 920-927 sub CheckReserves { Link Here
920
        my $LocalHoldsPriority = C4::Context->preference('LocalHoldsPriority');
886
        my $LocalHoldsPriority = C4::Context->preference('LocalHoldsPriority');
921
        my $LocalHoldsPriorityPatronControl = C4::Context->preference('LocalHoldsPriorityPatronControl');
887
        my $LocalHoldsPriorityPatronControl = C4::Context->preference('LocalHoldsPriorityPatronControl');
922
        my $LocalHoldsPriorityItemControl = C4::Context->preference('LocalHoldsPriorityItemControl');
888
        my $LocalHoldsPriorityItemControl = C4::Context->preference('LocalHoldsPriorityItemControl');
923
924
        my $priority = 10000000;
889
        my $priority = 10000000;
890
925
        foreach my $res (@reserves) {
891
        foreach my $res (@reserves) {
926
            if ($res->{'found'} && $res->{'found'} eq 'W') {
892
            if ($res->{'found'} && $res->{'found'} eq 'W') {
927
                return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
893
                return ( "Waiting", $res, \@reserves ); # Found it, it is waiting
Lines 931-942 sub CheckReserves { Link Here
931
                return ( "Transferred", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
897
                return ( "Transferred", $res, \@reserves ); # Found determinated hold, e. g. the transferred one
932
            } else {
898
            } else {
933
                my $patron;
899
                my $patron;
934
                my $item;
935
                my $local_hold_match;
900
                my $local_hold_match;
936
901
937
                if ($LocalHoldsPriority) {
902
                if ($LocalHoldsPriority) {
938
                    $patron = Koha::Patrons->find( $res->{borrowernumber} );
903
                    $patron = Koha::Patrons->find( $res->{borrowernumber} );
939
                    $item = Koha::Items->find($itemnumber);
940
904
941
                    unless ($item->exclude_from_local_holds_priority || $patron->category->exclude_from_local_holds_priority) {
905
                    unless ($item->exclude_from_local_holds_priority || $patron->category->exclude_from_local_holds_priority) {
942
                        my $local_holds_priority_item_branchcode =
906
                        my $local_holds_priority_item_branchcode =
Lines 955-964 sub CheckReserves { Link Here
955
919
956
                # See if this item is more important than what we've got so far
920
                # See if this item is more important than what we've got so far
957
                if ( ( $res->{'priority'} && $res->{'priority'} < $priority ) || $local_hold_match ) {
921
                if ( ( $res->{'priority'} && $res->{'priority'} < $priority ) || $local_hold_match ) {
958
                    $item ||= Koha::Items->find($itemnumber);
959
                    next if $res->{item_group_id} && ( !$item->item_group || $item->item_group->id != $res->{item_group_id} );
922
                    next if $res->{item_group_id} && ( !$item->item_group || $item->item_group->id != $res->{item_group_id} );
960
                    next if $res->{itemtype} && $res->{itemtype} ne $item->effective_itemtype;
923
                    next if $res->{itemtype} && $res->{itemtype} ne $item->effective_itemtype;
961
                    $patron ||= Koha::Patrons->find( $res->{borrowernumber} );
924
                    $patron //= Koha::Patrons->find( $res->{borrowernumber} );
962
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
925
                    my $branch = GetReservesControlBranch( $item->unblessed, $patron->unblessed );
963
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
926
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$item->effective_itemtype);
964
                    next if ($branchitemrule->{'holdallowed'} eq 'not_allowed');
927
                    next if ($branchitemrule->{'holdallowed'} eq 'not_allowed');
Lines 981-987 sub CheckReserves { Link Here
981
    # If we get this far, then no exact match was found.
944
    # If we get this far, then no exact match was found.
982
    # We return the most important (i.e. next) reservation.
945
    # We return the most important (i.e. next) reservation.
983
    if ($highest) {
946
    if ($highest) {
984
        $highest->{'itemnumber'} = $item;
947
        $highest->{'itemnumber'} = $item->itemnumber;
985
        return ( "Reserved", $highest, \@reserves );
948
        return ( "Reserved", $highest, \@reserves );
986
    }
949
    }
987
950
Lines 1709-1715 sub _FixPriority { Link Here
1709
1672
1710
=head2 _Findgroupreserve
1673
=head2 _Findgroupreserve
1711
1674
1712
  @results = &_Findgroupreserve($biblioitemnumber, $biblionumber, $itemnumber, $lookahead, $ignore_borrowers);
1675
  @results = &_Findgroupreserve($biblionumber, $itemnumber, $lookahead, $ignore_borrowers);
1713
1676
1714
Looks for a holds-queue based item-specific match first, then for a holds-queue title-level match, returning the
1677
Looks for a holds-queue based item-specific match first, then for a holds-queue title-level match, returning the
1715
first match found.  If neither, then we look for non-holds-queue based holds.
1678
first match found.  If neither, then we look for non-holds-queue based holds.
Lines 1730-1736 All return values will respect any borrowernumbers passed as arrayref in $ignore Link Here
1730
=cut
1693
=cut
1731
1694
1732
sub _Findgroupreserve {
1695
sub _Findgroupreserve {
1733
    my ( $bibitem, $biblio, $itemnumber, $lookahead, $ignore_borrowers) = @_;
1696
    my ( $biblionumber, $itemnumber, $lookahead, $ignore_borrowers) = @_;
1734
    my $dbh   = C4::Context->dbh;
1697
    my $dbh   = C4::Context->dbh;
1735
1698
1736
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1699
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
Lines 1834-1840 sub _Findgroupreserve { Link Here
1834
          ORDER BY priority
1797
          ORDER BY priority
1835
    };
1798
    };
1836
    $sth = $dbh->prepare($query);
1799
    $sth = $dbh->prepare($query);
1837
    $sth->execute( $biblio, $itemnumber, $lookahead||0);
1800
    $sth->execute( $biblionumber, $itemnumber, $lookahead||0);
1838
    @results = ();
1801
    @results = ();
1839
    while ( my $data = $sth->fetchrow_hashref ) {
1802
    while ( my $data = $sth->fetchrow_hashref ) {
1840
        push( @results, $data )
1803
        push( @results, $data )
Lines 2050-2056 sub MoveReserve { Link Here
2050
    $cancelreserve //= 0;
2013
    $cancelreserve //= 0;
2051
2014
2052
    my $lookahead = C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2015
    my $lookahead = C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2053
    my ( $restype, $res, undef ) = CheckReserves( $itemnumber, undef, $lookahead );
2016
    my $item = Koha::Items->find($itemnumber);
2017
    my ( $restype, $res, undef ) = CheckReserves( $item, $lookahead );
2054
    return unless $res;
2018
    return unless $res;
2055
2019
2056
    my $biblionumber = $res->{biblionumber};
2020
    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 171-177 while ( my $auto_renew = $auto_renews->next ) { Link Here
171
    }
171
    }
172
172
173
    # CanBookBeRenewed returns 'auto_renew' when the renewal should be done by this script
173
    # CanBookBeRenewed returns 'auto_renew' when the renewal should be done by this script
174
    my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->borrowernumber, $auto_renew->itemnumber, undef, 1 );
174
    my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->patron, $auto_renew, undef, 1 );
175
    my $updated;
175
    my $updated;
176
    if ( $error eq 'auto_renew' ) {
176
    if ( $error eq 'auto_renew' ) {
177
        $updated = 1;
177
        $updated = 1;
Lines 185-200 while ( my $auto_renew = $auto_renews->next ) { Link Here
185
        }
185
        }
186
        push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
186
        push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
187
            if ( $wants_messages ) && !$wants_digest;
187
            if ( $wants_messages ) && !$wants_digest;
188
    } elsif ( $error eq 'too_many'
188
    } elsif (
189
        or $error eq 'on_reserve'
189
        $error eq 'too_many' ||
190
        or $error eq 'restriction'
190
        $error eq 'on_reserve' ||
191
        or $error eq 'overdue'
191
        $error eq 'restriction' ||
192
        or $error eq 'too_unseen'
192
        $error eq 'overdue' ||
193
        or $error eq 'auto_account_expired'
193
        $error eq 'too_unseen' ||
194
        or $error eq 'auto_too_late'
194
        $error eq 'auto_account_expired' ||
195
        or $error eq 'auto_too_much_oweing'
195
        $error eq 'auto_too_late' ||
196
        or $error eq 'auto_too_soon'
196
        $error eq 'auto_too_much_oweing' ||
197
        or $error eq 'item_denied_renewal' ) {
197
        $error eq 'auto_too_soon' ||
198
        $error eq 'item_denied_renewal' ||
199
        $error eq 'item_issued_to_other_patron'
200
    ) {
198
        if ( $verbose ) {
201
        if ( $verbose ) {
199
            say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
202
            say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
200
              $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $confirm ? 'will' : 'would', $error;
203
              $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 188-194 my $overdues_count = 0; Link Here
188
my @overdues;
188
my @overdues;
189
my @issuedat;
189
my @issuedat;
190
my $itemtypes = { map { $_->{itemtype} => $_ } @{ Koha::ItemTypes->search_with_localization->unblessed } };
190
my $itemtypes = { map { $_->{itemtype} => $_ } @{ Koha::ItemTypes->search_with_localization->unblessed } };
191
my $pending_checkouts = $patron->pending_checkouts->search({}, { order_by => [ { -desc => 'date_due' }, { -asc => 'issue_id' } ] });
191
my $pending_checkouts = $patron->pending_checkouts->search(
192
    {},
193
    {
194
        order_by => [ { -desc => 'date_due' }, { -asc => 'issue_id' } ],
195
        prefetch => 'item'
196
    }
197
);
192
my $are_renewable_items = 0;
198
my $are_renewable_items = 0;
193
if ( $pending_checkouts->count ) { # Useless test
199
if ( $pending_checkouts->count ) { # Useless test
194
    while ( my $c = $pending_checkouts->next ) {
200
    while ( my $c = $pending_checkouts->next ) {
Lines 221-227 if ( $pending_checkouts->count ) { # Useless test Link Here
221
        $issue->{rentalfines} = $rental_fines->total_outstanding;
227
        $issue->{rentalfines} = $rental_fines->total_outstanding;
222
228
223
        # check if item is renewable
229
        # check if item is renewable
224
        my ($status,$renewerror,$info) = CanBookBeRenewed( $borrowernumber, $issue->{'itemnumber'} );
230
        my ($status, $renewerror, $info) = CanBookBeRenewed( $patron, $c );
225
        (
231
        (
226
            $issue->{'renewcount'},
232
            $issue->{'renewcount'},
227
            $issue->{'renewsallowed'},
233
            $issue->{'renewsallowed'},
Lines 231-237 if ( $pending_checkouts->count ) { # Useless test Link Here
231
            $issue->{'unseenleft'}
237
            $issue->{'unseenleft'}
232
        ) = GetRenewCount($borrowernumber, $issue->{'itemnumber'});
238
        ) = GetRenewCount($borrowernumber, $issue->{'itemnumber'});
233
        ( $issue->{'renewalfee'}, $issue->{'renewalitemtype'} ) = GetIssuingCharges( $issue->{'itemnumber'}, $borrowernumber );
239
        ( $issue->{'renewalfee'}, $issue->{'renewalitemtype'} ) = GetIssuingCharges( $issue->{'itemnumber'}, $borrowernumber );
234
        $issue->{itemtype_object} = Koha::ItemTypes->find( Koha::Items->find( $issue->{itemnumber} )->effective_itemtype );
240
        $issue->{itemtype_object} = Koha::ItemTypes->find( $c->item->effective_itemtype );
235
        if($status && C4::Context->preference("OpacRenewalAllowed")){
241
        if($status && C4::Context->preference("OpacRenewalAllowed")){
236
            $are_renewable_items = 1;
242
            $are_renewable_items = 1;
237
            $issue->{'status'} = $status;
243
            $issue->{'status'} = $status;
Lines 249-254 if ( $pending_checkouts->count ) { # Useless test Link Here
249
            $issue->{'auto_too_late'}  = 1 if $renewerror eq 'auto_too_late';
255
            $issue->{'auto_too_late'}  = 1 if $renewerror eq 'auto_too_late';
250
            $issue->{'auto_too_much_oweing'}  = 1 if $renewerror eq 'auto_too_much_oweing';
256
            $issue->{'auto_too_much_oweing'}  = 1 if $renewerror eq 'auto_too_much_oweing';
251
            $issue->{'item_denied_renewal'}  = 1 if $renewerror eq 'item_denied_renewal';
257
            $issue->{'item_denied_renewal'}  = 1 if $renewerror eq 'item_denied_renewal';
258
            $issue->{'item_issued_to_other_patron'} = 1 if $renewerror eq 'item_issued_to_other_patron';
252
259
253
            if ( $renewerror eq 'too_soon' ) {
260
            if ( $renewerror eq 'too_soon' ) {
254
                $issue->{'too_soon'}         = 1;
261
                $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 (-177 / +170 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-376 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
373
374
};
373
};
375
374
376
subtest "GetIssuingCharges tests" => sub {
375
subtest "GetIssuingCharges tests" => sub {
Lines 463-468 subtest "CanBookBeRenewed tests" => sub { Link Here
463
        surname => 'Renewal',
462
        surname => 'Renewal',
464
        categorycode => $patron_category->{categorycode},
463
        categorycode => $patron_category->{categorycode},
465
        branchcode => $branch,
464
        branchcode => $branch,
465
        autorenew_checkouts => 1,
466
    );
466
    );
467
467
468
    my %reserving_borrower_data = (
468
    my %reserving_borrower_data = (
Lines 493-510 subtest "CanBookBeRenewed tests" => sub { Link Here
493
        categorycode => $patron_category->{categorycode},
493
        categorycode => $patron_category->{categorycode},
494
        branchcode => $branch,
494
        branchcode => $branch,
495
        dateexpiry => dt_from_string->subtract( months => 1 ),
495
        dateexpiry => dt_from_string->subtract( months => 1 ),
496
        autorenew_checkouts => 1,
496
    );
497
    );
497
498
498
    my $renewing_borrowernumber = Koha::Patron->new(\%renewing_borrower_data)->store->borrowernumber;
499
    my $renewing_borrower_obj = Koha::Patron->new(\%renewing_borrower_data)->store;
500
    my $renewing_borrowernumber = $renewing_borrower_obj->borrowernumber;
499
    my $reserving_borrowernumber = Koha::Patron->new(\%reserving_borrower_data)->store->borrowernumber;
501
    my $reserving_borrowernumber = Koha::Patron->new(\%reserving_borrower_data)->store->borrowernumber;
500
    my $hold_waiting_borrowernumber = Koha::Patron->new(\%hold_waiting_borrower_data)->store->borrowernumber;
502
    my $hold_waiting_borrowernumber = Koha::Patron->new(\%hold_waiting_borrower_data)->store->borrowernumber;
501
    my $restricted_borrowernumber = Koha::Patron->new(\%restricted_borrower_data)->store->borrowernumber;
503
    my $restricted_borrower_obj = Koha::Patron->new(\%restricted_borrower_data)->store;
502
    my $expired_borrowernumber = Koha::Patron->new(\%expired_borrower_data)->store->borrowernumber;
503
504
504
    my $renewing_borrower_obj = Koha::Patrons->find( $renewing_borrowernumber );
505
    my $expired_borrower_obj = Koha::Patron->new(\%expired_borrower_data)->store;
505
    my $renewing_borrower = $renewing_borrower_obj->unblessed;
506
    my $restricted_borrower = Koha::Patrons->find( $restricted_borrowernumber )->unblessed;
507
    my $expired_borrower = Koha::Patrons->find( $expired_borrowernumber )->unblessed;
508
506
509
    my $bibitems       = '';
507
    my $bibitems       = '';
510
    my $priority       = '1';
508
    my $priority       = '1';
Lines 514-532 subtest "CanBookBeRenewed tests" => sub { Link Here
514
    my $checkitem      = undef;
512
    my $checkitem      = undef;
515
    my $found          = undef;
513
    my $found          = undef;
516
514
517
    my $issue = AddIssue( $renewing_borrower, $item_1->barcode);
515
    my $issue_1 = AddIssue( $renewing_borrower_obj->unblessed, $item_1->barcode);
518
    my $datedue = dt_from_string( $issue->date_due() );
516
    my $datedue = dt_from_string( $issue_1->date_due() );
519
    is (defined $issue->date_due(), 1, "Item 1 checked out, due date: " . $issue->date_due() );
517
    is (defined $issue_1->date_due(), 1, "Item 1 checked out, due date: " . $issue_1->date_due() );
520
521
    my $issue2 = AddIssue( $renewing_borrower, $item_2->barcode);
522
    $datedue = dt_from_string( $issue->date_due() );
523
    is (defined $issue2, 1, "Item 2 checked out, due date: " . $issue2->date_due());
524
518
519
    my $issue_2 = AddIssue( $renewing_borrower_obj->unblessed, $item_2->barcode);
520
    is (defined $issue_2, 1, "Item 2 checked out, due date: " . $issue_2->date_due());
525
521
526
    my $borrowing_borrowernumber = Koha::Checkouts->find( { itemnumber => $item_1->itemnumber } )->borrowernumber;
522
    my $borrowing_borrowernumber = Koha::Checkouts->find( { itemnumber => $item_1->itemnumber } )->borrowernumber;
527
    is ($borrowing_borrowernumber, $renewing_borrowernumber, "Item checked out to $renewing_borrower->{firstname} $renewing_borrower->{surname}");
523
    is ($borrowing_borrowernumber, $renewing_borrowernumber, "Item checked out to ".$renewing_borrower_obj->firstname." ".$renewing_borrower_obj->surname);
528
524
529
    my ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber, 1);
525
    my ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1, 1);
530
    is( $renewokay, 1, 'Can renew, no holds for this title or item');
526
    is( $renewokay, 1, 'Can renew, no holds for this title or item');
531
527
532
528
Lines 565-573 subtest "CanBookBeRenewed tests" => sub { Link Here
565
        }
561
        }
566
    );
562
    );
567
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 1 );
563
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 1 );
568
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
564
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
569
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
565
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
570
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
566
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_2);
571
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
567
    is( $renewokay, 1, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
572
568
573
569
Lines 585-591 subtest "CanBookBeRenewed tests" => sub { Link Here
585
            found            => $found,
581
            found            => $found,
586
        }
582
        }
587
    );
583
    );
588
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
584
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
589
    is( $renewokay, 0, 'Renewal not possible when single patron\'s holds exceed the number of available items');
585
    is( $renewokay, 0, 'Renewal not possible when single patron\'s holds exceed the number of available items');
590
    Koha::Holds->find($reserve_id)->delete;
586
    Koha::Holds->find($reserve_id)->delete;
591
587
Lines 600-606 subtest "CanBookBeRenewed tests" => sub { Link Here
600
            reservedate    => '1999-01-01',
596
            reservedate    => '1999-01-01',
601
        }
597
        }
602
    );
598
    );
603
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
599
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
604
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
600
    is( $renewokay, 0, 'Bug 13919 - Renewal possible with item level hold on item');
605
    $hold->delete();
601
    $hold->delete();
606
602
Lines 616-632 subtest "CanBookBeRenewed tests" => sub { Link Here
616
            found          => 'W'
612
            found          => 'W'
617
        }
613
        }
618
    );
614
    );
619
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
615
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
620
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
616
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
621
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
617
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_2);
622
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
618
    is( $renewokay, 0, 'Bug 11634 - Allow renewal of item with unfilled holds if other available items can fill those holds');
623
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 0 );
619
    t::lib::Mocks::mock_preference('AllowRenewalIfOtherItemsAvailable', 0 );
624
620
625
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
621
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
626
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
622
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
627
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
623
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
628
624
629
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
625
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_2);
630
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
626
    is( $renewokay, 0, '(Bug 10663) Cannot renew, reserved');
631
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
627
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, reserved (returned error is on_reserve)');
632
628
Lines 655-670 subtest "CanBookBeRenewed tests" => sub { Link Here
655
        }
651
        }
656
    );
652
    );
657
653
658
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber, 1);
654
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1, 1);
659
    is( $renewokay, 0, '(Bug 10663) Cannot renew, item reserved');
655
    is( $renewokay, 0, '(Bug 10663) Cannot renew, item reserved');
660
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, item reserved (returned error is on_reserve)');
656
    is( $error, 'on_reserve', '(Bug 10663) Cannot renew, item reserved (returned error is on_reserve)');
661
657
662
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber, 1);
658
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_2, 1);
663
    is( $renewokay, 1, 'Can renew item 2, item-level hold is on item 1');
659
    is( $renewokay, 1, 'Can renew item 2, item-level hold is on item 1');
664
660
665
    # Items can't fill hold for reasons
661
    # Items can't fill hold for reasons
666
    $item_1->notforloan(1)->store;
662
    $issue_1->item->notforloan(1)->store;
667
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber, 1);
663
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1, 1);
668
    is( $renewokay, 1, 'Can renew, item is marked not for loan, hold does not block');
664
    is( $renewokay, 1, 'Can renew, item is marked not for loan, hold does not block');
669
    $item_1->set({notforloan => 0, itype => $itemtype })->store;
665
    $item_1->set({notforloan => 0, itype => $itemtype })->store;
670
666
Lines 679-691 subtest "CanBookBeRenewed tests" => sub { Link Here
679
            itype            => $itemtype,
675
            itype            => $itemtype,
680
        }
676
        }
681
    );
677
    );
682
    my $datedue5 = AddIssue($restricted_borrower, $item_5->barcode);
678
    my $issue_5 = AddIssue($restricted_borrower_obj->unblessed, $item_5->barcode);
683
    is (defined $datedue5, 1, "Item with date due checked out, due date: $datedue5");
679
    is (defined $issue_5, 1, "Item with date due checked out, due date: ". $issue_5->date_due);
684
680
685
    t::lib::Mocks::mock_preference('RestrictionBlockRenewing','1');
681
    t::lib::Mocks::mock_preference('RestrictionBlockRenewing','1');
686
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_2->itemnumber);
682
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_2);
687
    is( $renewokay, 1, '(Bug 8236), Can renew, user is not restricted');
683
    is( $renewokay, 1, '(Bug 8236), Can renew, user is not restricted');
688
    ( $renewokay, $error ) = CanBookBeRenewed($restricted_borrowernumber, $item_5->itemnumber);
684
    ( $renewokay, $error ) = CanBookBeRenewed($restricted_borrower_obj, $issue_5);
689
    is( $renewokay, 0, '(Bug 8236), Cannot renew, user is restricted');
685
    is( $renewokay, 0, '(Bug 8236), Cannot renew, user is restricted');
690
    is( $error, 'restriction', "Correct error returned");
686
    is( $error, 'restriction', "Correct error returned");
691
687
Lines 708-751 subtest "CanBookBeRenewed tests" => sub { Link Here
708
        }
704
        }
709
    );
705
    );
710
706
711
    my $datedue6 = AddIssue( $renewing_borrower, $item_6->barcode);
707
    my $issue_6 = AddIssue( $renewing_borrower_obj->unblessed, $item_6->barcode);
712
    is (defined $datedue6, 1, "Item 2 checked out, due date: ".$datedue6->date_due);
708
    is (defined $issue_6, 1, "Item 2 checked out, due date: ".$issue_6->date_due);
713
709
714
    my $now = dt_from_string();
710
    my $now = dt_from_string();
715
    my $five_weeks = DateTime::Duration->new(weeks => 5);
711
    my $five_weeks = DateTime::Duration->new(weeks => 5);
716
    my $five_weeks_ago = $now - $five_weeks;
712
    my $five_weeks_ago = $now - $five_weeks;
717
    t::lib::Mocks::mock_preference('finesMode', 'production');
713
    t::lib::Mocks::mock_preference('finesMode', 'production');
718
714
719
    my $passeddatedue1 = AddIssue($renewing_borrower, $item_7->barcode, $five_weeks_ago);
715
    my $issue_7 = AddIssue($renewing_borrower_obj->unblessed, $item_7->barcode, $five_weeks_ago);
720
    is (defined $passeddatedue1, 1, "Item with passed date due checked out, due date: " . $passeddatedue1->date_due);
716
    is (defined $issue_7, 1, "Item with passed date due checked out, due date: " . $issue_7->date_due);
721
717
722
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','allow');
718
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','allow');
723
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_6->itemnumber);
719
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_6);
724
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is not overdue');
720
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is not overdue');
725
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_7->itemnumber);
721
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_7);
726
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is overdue but not pref does not block');
722
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is overdue but not pref does not block');
727
723
728
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','block');
724
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','block');
729
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_6->itemnumber);
725
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_6);
730
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is not overdue but patron has overdues');
726
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is not overdue but patron has overdues');
731
    is( $error, 'overdue', "Correct error returned");
727
    is( $error, 'overdue', "Correct error returned");
732
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_7->itemnumber);
728
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_7);
733
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is overdue so patron has overdues');
729
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is overdue so patron has overdues');
734
    is( $error, 'overdue', "Correct error returned");
730
    is( $error, 'overdue', "Correct error returned");
735
731
736
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','blockitem');
732
    t::lib::Mocks::mock_preference('OverduesBlockRenewing','blockitem');
737
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_6->itemnumber);
733
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_6);
738
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is not overdue');
734
    is( $renewokay, 1, '(Bug 8236), Can renew, this item is not overdue');
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');
736
    is( $renewokay, 0, '(Bug 8236), Cannot renew, this item is overdue');
741
    is( $error, 'overdue', "Correct error returned");
737
    is( $error, 'overdue', "Correct error returned");
742
738
743
    my ( $fine ) = CalcFine( $item_7->unblessed, $renewing_borrower->{categorycode}, $branch, $five_weeks_ago, $now );
739
    my ( $fine ) = CalcFine( $item_7->unblessed, $renewing_borrower_obj->categorycode, $branch, $five_weeks_ago, $now );
744
    C4::Overdues::UpdateFine(
740
    C4::Overdues::UpdateFine(
745
        {
741
        {
746
            issue_id       => $passeddatedue1->id(),
742
            issue_id       => $issue_7->id(),
747
            itemnumber     => $item_7->itemnumber,
743
            itemnumber     => $item_7->itemnumber,
748
            borrowernumber => $renewing_borrower->{borrowernumber},
744
            borrowernumber => $renewing_borrower_obj->borrowernumber,
749
            amount         => $fine,
745
            amount         => $fine,
750
            due            => Koha::DateUtils::output_pref($five_weeks_ago)
746
            due            => Koha::DateUtils::output_pref($five_weeks_ago)
751
        }
747
        }
Lines 776-782 subtest "CanBookBeRenewed tests" => sub { Link Here
776
    my $old_log_size = Koha::ActionLogs->count( \%params_renewal );
772
    my $old_log_size = Koha::ActionLogs->count( \%params_renewal );
777
    my $dt = dt_from_string();
773
    my $dt = dt_from_string();
778
    Time::Fake->offset( $dt->epoch );
774
    Time::Fake->offset( $dt->epoch );
779
    my $datedue1 = AddRenewal( $renewing_borrower->{borrowernumber}, $item_7->itemnumber, $branch );
775
    my $datedue1 = AddRenewal( $renewing_borrower_obj->borrowernumber, $item_7->itemnumber, $branch );
780
    my $new_log_size = Koha::ActionLogs->count( \%params_renewal );
776
    my $new_log_size = Koha::ActionLogs->count( \%params_renewal );
781
    is ($new_log_size, $old_log_size, 'renew log not added because of the syspref RenewalLog');
777
    is ($new_log_size, $old_log_size, 'renew log not added because of the syspref RenewalLog');
782
    isnt (DateTime->compare($datedue1, $dt), 0, "AddRenewal returned a good duedate");
778
    isnt (DateTime->compare($datedue1, $dt), 0, "AddRenewal returned a good duedate");
Lines 785-802 subtest "CanBookBeRenewed tests" => sub { Link Here
785
    t::lib::Mocks::mock_preference('RenewalLog', 1);
781
    t::lib::Mocks::mock_preference('RenewalLog', 1);
786
    $date = output_pref( { dt => dt_from_string(), dateonly => 1, dateformat => 'iso' } );
782
    $date = output_pref( { dt => dt_from_string(), dateonly => 1, dateformat => 'iso' } );
787
    $old_log_size = Koha::ActionLogs->count( \%params_renewal );
783
    $old_log_size = Koha::ActionLogs->count( \%params_renewal );
788
    AddRenewal( $renewing_borrower->{borrowernumber}, $item_7->itemnumber, $branch );
784
    AddRenewal( $renewing_borrower_obj->borrowernumber, $item_7->itemnumber, $branch );
789
    $new_log_size = Koha::ActionLogs->count( \%params_renewal );
785
    $new_log_size = Koha::ActionLogs->count( \%params_renewal );
790
    is ($new_log_size, $old_log_size + 1, 'renew log successfully added');
786
    is ($new_log_size, $old_log_size + 1, 'renew log successfully added');
791
787
792
    my $fines = Koha::Account::Lines->search( { borrowernumber => $renewing_borrower->{borrowernumber}, itemnumber => $item_7->itemnumber } );
788
    my $fines = Koha::Account::Lines->search( { borrowernumber => $renewing_borrower_obj->borrowernumber, itemnumber => $item_7->itemnumber } );
793
    is( $fines->count, 1, 'AddRenewal left fine' );
789
    is( $fines->count, 1, 'AddRenewal left fine' );
794
    is( $fines->next->status, 'RENEWED', 'Fine on renewed item is closed out properly' );
790
    is( $fines->next->status, 'RENEWED', 'Fine on renewed item is closed out properly' );
795
    $fines->delete();
791
    $fines->delete();
796
792
797
    my $old_issue_log_size = Koha::ActionLogs->count( \%params_issue );
793
    my $old_issue_log_size = Koha::ActionLogs->count( \%params_issue );
798
    my $old_renew_log_size = Koha::ActionLogs->count( \%params_renewal );
794
    my $old_renew_log_size = Koha::ActionLogs->count( \%params_renewal );
799
    AddIssue( $renewing_borrower,$item_7->barcode,Koha::DateUtils::output_pref({str=>$datedue6->date_due, dateformat =>'iso'}),0,$date, 0, undef );
795
    AddIssue(
796
        $renewing_borrower_obj->unblessed,
797
        $item_7->barcode,
798
        Koha::DateUtils::output_pref({str=>$issue_6->date_due, dateformat =>'iso'}),
799
        0,
800
        $date,
801
        0,
802
        undef
803
    ); # TODO: Already issued???
800
    $new_log_size = Koha::ActionLogs->count( \%params_renewal );
804
    $new_log_size = Koha::ActionLogs->count( \%params_renewal );
801
    is ($new_log_size, $old_renew_log_size + 1, 'renew log successfully added when renewed via issuing');
805
    is ($new_log_size, $old_renew_log_size + 1, 'renew log successfully added when renewed via issuing');
802
    $new_log_size = Koha::ActionLogs->count( \%params_issue );
806
    $new_log_size = Koha::ActionLogs->count( \%params_issue );
Lines 817-830 subtest "CanBookBeRenewed tests" => sub { Link Here
817
        }
821
        }
818
    );
822
    );
819
823
820
    $issue = AddIssue( $renewing_borrower, $item_4->barcode, undef, undef, undef, undef, { auto_renew => 1 } );
824
    my $issue_4 = AddIssue( $renewing_borrower_obj->unblessed, $item_4->barcode, undef, undef, undef, undef, { auto_renew => 1 } );
821
    my $info;
825
    my $info;
822
    ( $renewokay, $error, $info ) =
826
    ( $renewokay, $error, $info ) =
823
      CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
827
      CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
824
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
828
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
825
    is( $error, 'auto_too_soon',
829
    is( $error, 'auto_too_soon',
826
        'Bug 14101: Cannot renew, renewal is automatic and premature, "No renewal before" = undef (returned code is auto_too_soon)' );
830
        'Bug 14101: Cannot renew, renewal is automatic and premature, "No renewal before" = undef (returned code is auto_too_soon)' );
827
    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'" );
831
    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'" );
828
    AddReserve(
832
    AddReserve(
829
        {
833
        {
830
            branchcode       => $branch,
834
            branchcode       => $branch,
Lines 840-869 subtest "CanBookBeRenewed tests" => sub { Link Here
840
            found            => $found
844
            found            => $found
841
        }
845
        }
842
    );
846
    );
843
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
847
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
844
    is( $renewokay, 0, 'Still should not be able to renew' );
848
    is( $renewokay, 0, 'Still should not be able to renew' );
845
    is( $error, 'on_reserve', 'returned code is on_reserve, reserve checked when not checking for cron' );
849
    is( $error, 'on_reserve', 'returned code is on_reserve, reserve checked when not checking for cron' );
846
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber, undef, 1 );
850
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4, undef, 1 );
847
    is( $renewokay, 0, 'Still should not be able to renew' );
851
    is( $renewokay, 0, 'Still should not be able to renew' );
848
    is( $error, 'auto_too_soon', 'returned code is auto_too_soon, reserve not checked when checking for cron' );
852
    is( $error, 'auto_too_soon', 'returned code is auto_too_soon, reserve not checked when checking for cron' );
849
    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'" );
853
    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'" );
850
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber, 1 );
854
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4, 1 );
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, auto_too_soon limit is overridden' );
856
    is( $error, 'on_reserve', 'returned code is on_reserve, auto_too_soon limit is overridden' );
853
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber, 1, 1 );
857
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4, 1, 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, 'on_reserve', 'returned code is on_reserve, auto_too_soon limit is overridden' );
859
    is( $error, 'on_reserve', 'returned code is on_reserve, auto_too_soon limit is overridden' );
856
    $dbh->do('UPDATE circulation_rules SET rule_value = 0 where rule_name = "norenewalbefore"');
860
    $dbh->do('UPDATE circulation_rules SET rule_value = 0 where rule_name = "norenewalbefore"');
857
    Koha::Cache::Memory::Lite->flush();
861
    Koha::Cache::Memory::Lite->flush();
858
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber, 1 );
862
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4, 1 );
859
    is( $renewokay, 0, 'Still should not be able to renew' );
863
    is( $renewokay, 0, 'Still should not be able to renew' );
860
    is( $error, 'on_reserve', 'returned code is on_reserve, auto_renew only happens if not on reserve' );
864
    is( $error, 'on_reserve', 'returned code is on_reserve, auto_renew only happens if not on reserve' );
861
    ModReserveCancelAll($item_4->itemnumber, $reserving_borrowernumber);
865
    ModReserveCancelAll($item_4->itemnumber, $reserving_borrowernumber);
862
866
863
867
    $renewing_borrower_obj = Koha::Patrons->find($renewing_borrower_obj->borrowernumber);
864
865
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
868
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
866
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
869
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
867
    is( $renewokay, 1, 'No renewal before is undef, but patron opted out of auto_renewal' );
870
    is( $renewokay, 1, 'No renewal before is undef, but patron opted out of auto_renewal' );
868
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
871
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
869
872
Lines 880-905 subtest "CanBookBeRenewed tests" => sub { Link Here
880
        }
883
        }
881
    );
884
    );
882
885
883
    ( $renewokay, $error, $info ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
886
    ( $renewokay, $error, $info ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
884
    is( $renewokay, 0, 'Bug 7413: Cannot renew, renewal is premature');
887
    is( $renewokay, 0, 'Bug 7413: Cannot renew, renewal is premature');
885
    is( $error, 'too_soon', 'Bug 7413: Cannot renew, renewal is premature (returned code is too_soon)');
888
    is( $error, 'too_soon', 'Bug 7413: Cannot renew, renewal is premature (returned code is too_soon)');
886
    is( $info->{soonest_renew_date}, dt_from_string($issue->date_due)->subtract( days => 7 ), "Soonest renew date returned when error is 'too_soon'");
889
    is( $info->{soonest_renew_date}, dt_from_string($issue_1->date_due)->subtract( days => 7 ), "Soonest renew date returned when error is 'too_soon'");
887
890
888
    # Bug 14101
891
    # Bug 14101
889
    # Test premature automatic renewal
892
    # Test premature automatic renewal
890
    ( $renewokay, $error, $info ) =
893
    ( $renewokay, $error, $info ) =
891
      CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
894
      CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
892
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
895
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
893
    is( $error, 'auto_too_soon',
896
    is( $error, 'auto_too_soon',
894
        'Bug 14101: Cannot renew, renewal is automatic and premature (returned code is auto_too_soon)'
897
        'Bug 14101: Cannot renew, renewal is automatic and premature (returned code is auto_too_soon)'
895
    );
898
    );
896
    is( $info->{soonest_renew_date}, dt_from_string($issue->date_due)->subtract( days => 7 ), "Soonest renew date returned when error is 'auto_too_soon'");
899
    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'");
897
900
898
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
901
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
899
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
902
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
900
    is( $renewokay, 0, 'No renewal before is 7, patron opted out of auto_renewal still cannot renew early' );
903
    is( $renewokay, 0, 'No renewal before is 7, patron opted out of auto_renewal still cannot renew early' );
901
    is( $error, 'too_soon', 'Error is too_soon, no auto' );
904
    is( $error, 'too_soon', 'Error is too_soon, no auto' );
902
    is( $info->{soonest_renew_date}, dt_from_string($issue->date_due)->subtract( days => 7 ), "Soonest renew date returned when error is 'too_soon'");
905
    is( $info->{soonest_renew_date}, dt_from_string($issue_4->date_due)->subtract( days => 7 ), "Soonest renew date returned when error is 'too_soon'");
903
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
906
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
904
907
905
    # Change policy so that loans can only be renewed exactly on due date (0 days prior to due date)
908
    # Change policy so that loans can only be renewed exactly on due date (0 days prior to due date)
Lines 907-924 subtest "CanBookBeRenewed tests" => sub { Link Here
907
    $dbh->do(q{UPDATE circulation_rules SET rule_value = '0' WHERE rule_name = 'norenewalbefore'});
910
    $dbh->do(q{UPDATE circulation_rules SET rule_value = '0' WHERE rule_name = 'norenewalbefore'});
908
    Koha::Cache::Memory::Lite->flush();
911
    Koha::Cache::Memory::Lite->flush();
909
    ( $renewokay, $error, $info ) =
912
    ( $renewokay, $error, $info ) =
910
      CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
913
      CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
911
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
914
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic and premature' );
912
    is( $error, 'auto_too_soon',
915
    is( $error, 'auto_too_soon',
913
        'Bug 14101: Cannot renew, renewal is automatic and premature, "No renewal before" = 0 (returned code is auto_too_soon)'
916
        'Bug 14101: Cannot renew, renewal is automatic and premature, "No renewal before" = 0 (returned code is auto_too_soon)'
914
    );
917
    );
915
    is( $info->{soonest_renew_date}, dt_from_string($issue->date_due), "Soonest renew date returned when error is 'auto_too_soon'");
918
    is( $info->{soonest_renew_date}, dt_from_string($issue_4->date_due), "Soonest renew date returned when error is 'auto_too_soon'");
916
919
917
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
920
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
918
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
921
    ( $renewokay, $error, $info ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
919
    is( $renewokay, 0, 'No renewal before is 0, patron opted out of auto_renewal still cannot renew early' );
922
    is( $renewokay, 0, 'No renewal before is 0, patron opted out of auto_renewal still cannot renew early' );
920
    is( $error, 'too_soon', 'Error is too_soon, no auto' );
923
    is( $error, 'too_soon', 'Error is too_soon, no auto' );
921
    is( $info->{soonest_renew_date}, dt_from_string($issue->date_due), "Soonest renew date returned when error is 'auto_too_soon'");
924
    is( $info->{soonest_renew_date}, dt_from_string($issue_4->date_due), "Soonest renew date returned when error is 'auto_too_soon'");
922
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
925
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
923
926
924
    # Change policy so that loans can be renewed 99 days prior to the due date
927
    # Change policy so that loans can be renewed 99 days prior to the due date
Lines 926-939 subtest "CanBookBeRenewed tests" => sub { Link Here
926
    $dbh->do(q{UPDATE circulation_rules SET rule_value = '99' WHERE rule_name = 'norenewalbefore'});
929
    $dbh->do(q{UPDATE circulation_rules SET rule_value = '99' WHERE rule_name = 'norenewalbefore'});
927
    Koha::Cache::Memory::Lite->flush();
930
    Koha::Cache::Memory::Lite->flush();
928
    ( $renewokay, $error ) =
931
    ( $renewokay, $error ) =
929
      CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
932
      CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
930
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic' );
933
    is( $renewokay, 0, 'Bug 14101: Cannot renew, renewal is automatic' );
931
    is( $error, 'auto_renew',
934
    is( $error, 'auto_renew',
932
        'Bug 14101: Cannot renew, renewal is automatic (returned code is auto_renew)'
935
        'Bug 14101: Cannot renew, renewal is automatic (returned code is auto_renew)'
933
    );
936
    );
934
937
935
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
938
    $renewing_borrower_obj->autorenew_checkouts(0)->store;
936
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $item_4->itemnumber );
939
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $issue_4 );
937
    is( $renewokay, 1, 'No renewal before is 99, patron opted out of auto_renewal so can renew' );
940
    is( $renewokay, 1, 'No renewal before is 99, patron opted out of auto_renewal so can renew' );
938
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
941
    $renewing_borrower_obj->autorenew_checkouts(1)->store;
939
942
Lines 948-954 subtest "CanBookBeRenewed tests" => sub { Link Here
948
951
949
        my $ten_days_before = dt_from_string->add( days => -10 );
952
        my $ten_days_before = dt_from_string->add( days => -10 );
950
        my $ten_days_ahead  = dt_from_string->add( days => 10 );
953
        my $ten_days_ahead  = dt_from_string->add( days => 10 );
951
        AddIssue( $renewing_borrower, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
954
        my $issue = AddIssue( $renewing_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
952
955
953
        Koha::CirculationRules->set_rules(
956
        Koha::CirculationRules->set_rules(
954
            {
957
            {
Lines 962-968 subtest "CanBookBeRenewed tests" => sub { Link Here
962
            }
965
            }
963
        );
966
        );
964
        ( $renewokay, $error ) =
967
        ( $renewokay, $error ) =
965
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
968
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
966
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
969
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
967
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
970
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
968
971
Lines 978-984 subtest "CanBookBeRenewed tests" => sub { Link Here
978
            }
981
            }
979
        );
982
        );
980
        ( $renewokay, $error ) =
983
        ( $renewokay, $error ) =
981
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
984
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
982
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
985
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
983
        is( $error, 'auto_too_late', 'Cannot auto renew, too late - no_auto_renewal_after is inclusive(returned code is auto_too_late)' );
986
        is( $error, 'auto_too_late', 'Cannot auto renew, too late - no_auto_renewal_after is inclusive(returned code is auto_too_late)' );
984
987
Lines 994-1000 subtest "CanBookBeRenewed tests" => sub { Link Here
994
            }
997
            }
995
        );
998
        );
996
        ( $renewokay, $error ) =
999
        ( $renewokay, $error ) =
997
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1000
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
998
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1001
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
999
        is( $error, 'auto_too_soon', 'Cannot auto renew, too soon - no_auto_renewal_after is defined(returned code is auto_too_soon)' );
1002
        is( $error, 'auto_too_soon', 'Cannot auto renew, too soon - no_auto_renewal_after is defined(returned code is auto_too_soon)' );
1000
1003
Lines 1010-1016 subtest "CanBookBeRenewed tests" => sub { Link Here
1010
            }
1013
            }
1011
        );
1014
        );
1012
        ( $renewokay, $error ) =
1015
        ( $renewokay, $error ) =
1013
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1016
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1014
        is( $renewokay, 0,            'Do not renew, renewal is automatic' );
1017
        is( $renewokay, 0,            'Do not renew, renewal is automatic' );
1015
        is( $error,     'auto_renew', 'Cannot renew, renew is automatic' );
1018
        is( $error,     'auto_renew', 'Cannot renew, renew is automatic' );
1016
1019
Lines 1027-1033 subtest "CanBookBeRenewed tests" => sub { Link Here
1027
            }
1030
            }
1028
        );
1031
        );
1029
        ( $renewokay, $error ) =
1032
        ( $renewokay, $error ) =
1030
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1033
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1031
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1034
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1032
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
1035
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
1033
1036
Lines 1044-1050 subtest "CanBookBeRenewed tests" => sub { Link Here
1044
            }
1047
            }
1045
        );
1048
        );
1046
        ( $renewokay, $error ) =
1049
        ( $renewokay, $error ) =
1047
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1050
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1048
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1051
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1049
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
1052
        is( $error, 'auto_too_late', 'Cannot renew, too late(returned code is auto_too_late)' );
1050
1053
Lines 1061-1067 subtest "CanBookBeRenewed tests" => sub { Link Here
1061
            }
1064
            }
1062
        );
1065
        );
1063
        ( $renewokay, $error ) =
1066
        ( $renewokay, $error ) =
1064
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1067
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1065
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1068
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1066
        is( $error, 'auto_renew', 'Cannot renew, renew is automatic' );
1069
        is( $error, 'auto_renew', 'Cannot renew, renew is automatic' );
1067
    };
1070
    };
Lines 1077-1083 subtest "CanBookBeRenewed tests" => sub { Link Here
1077
1080
1078
        my $ten_days_before = dt_from_string->add( days => -10 );
1081
        my $ten_days_before = dt_from_string->add( days => -10 );
1079
        my $ten_days_ahead = dt_from_string->add( days => 10 );
1082
        my $ten_days_ahead = dt_from_string->add( days => 10 );
1080
        AddIssue( $renewing_borrower, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1083
        my $issue = AddIssue( $renewing_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1081
1084
1082
        Koha::CirculationRules->set_rules(
1085
        Koha::CirculationRules->set_rules(
1083
            {
1086
            {
Lines 1105-1111 subtest "CanBookBeRenewed tests" => sub { Link Here
1105
            }
1108
            }
1106
        )->status('RETURNED')->store;
1109
        )->status('RETURNED')->store;
1107
        ( $renewokay, $error ) =
1110
        ( $renewokay, $error ) =
1108
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1111
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1109
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1112
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1110
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, patron has 5' );
1113
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, patron has 5' );
1111
1114
Lines 1119-1125 subtest "CanBookBeRenewed tests" => sub { Link Here
1119
            }
1122
            }
1120
        )->status('RETURNED')->store;
1123
        )->status('RETURNED')->store;
1121
        ( $renewokay, $error ) =
1124
        ( $renewokay, $error ) =
1122
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1125
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1123
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1126
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1124
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, patron has 10' );
1127
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, patron has 10' );
1125
1128
Lines 1133-1139 subtest "CanBookBeRenewed tests" => sub { Link Here
1133
            }
1136
            }
1134
        )->status('RETURNED')->store;
1137
        )->status('RETURNED')->store;
1135
        ( $renewokay, $error ) =
1138
        ( $renewokay, $error ) =
1136
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1139
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1137
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1140
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1138
        is( $error, 'auto_too_much_oweing', 'Cannot auto renew, OPACFineNoRenewals=10, patron has 15' );
1141
        is( $error, 'auto_too_much_oweing', 'Cannot auto renew, OPACFineNoRenewals=10, patron has 15' );
1139
1142
Lines 1146-1158 subtest "CanBookBeRenewed tests" => sub { Link Here
1146
            }
1149
            }
1147
        )->store;
1150
        )->store;
1148
        ( $renewokay, $error ) =
1151
        ( $renewokay, $error ) =
1149
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1152
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1150
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1153
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1151
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, OPACFineNoRenewalsIncludeCredit=1, patron has 15 debt, 5 credit'  );
1154
        is( $error, 'auto_renew', 'Can auto renew, OPACFineNoRenewals=10, OPACFineNoRenewalsIncludeCredit=1, patron has 15 debt, 5 credit'  );
1152
1155
1153
        C4::Context->set_preference('OPACFineNoRenewalsIncludeCredit','0');
1156
        C4::Context->set_preference('OPACFineNoRenewalsIncludeCredit','0');
1154
        ( $renewokay, $error ) =
1157
        ( $renewokay, $error ) =
1155
          CanBookBeRenewed( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1158
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1156
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1159
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1157
        is( $error, 'auto_too_much_oweing', 'Cannot auto renew, OPACFineNoRenewals=10, OPACFineNoRenewalsIncludeCredit=1, patron has 15 debt, 5 credit'  );
1160
        is( $error, 'auto_too_much_oweing', 'Cannot auto renew, OPACFineNoRenewals=10, OPACFineNoRenewalsIncludeCredit=1, patron has 15 debt, 5 credit'  );
1158
1161
Lines 1187-1223 subtest "CanBookBeRenewed tests" => sub { Link Here
1187
        # Patron is expired and BlockExpiredPatronOpacActions=0
1190
        # Patron is expired and BlockExpiredPatronOpacActions=0
1188
        # => auto renew is allowed
1191
        # => auto renew is allowed
1189
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 0);
1192
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 0);
1190
        my $patron = $expired_borrower;
1193
        my $issue = AddIssue( $expired_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1191
        my $checkout = AddIssue( $patron, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1192
        ( $renewokay, $error ) =
1194
        ( $renewokay, $error ) =
1193
          CanBookBeRenewed( $patron->{borrowernumber}, $item_to_auto_renew->itemnumber );
1195
          CanBookBeRenewed( $expired_borrower_obj, $issue );
1194
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1196
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1195
        is( $error, 'auto_renew', 'Can auto renew, patron is expired but BlockExpiredPatronOpacActions=0' );
1197
        is( $error, 'auto_renew', 'Can auto renew, patron is expired but BlockExpiredPatronOpacActions=0' );
1196
        Koha::Checkouts->find( $checkout->issue_id )->delete;
1198
        Koha::Checkouts->find( $issue->issue_id )->delete;
1197
1199
1198
1200
1199
        # Patron is expired and BlockExpiredPatronOpacActions=1
1201
        # Patron is expired and BlockExpiredPatronOpacActions=1
1200
        # => auto renew is not allowed
1202
        # => auto renew is not allowed
1201
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 1);
1203
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 1);
1202
        $patron = $expired_borrower;
1204
        $issue = AddIssue( $expired_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1203
        $checkout = AddIssue( $patron, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1204
        ( $renewokay, $error ) =
1205
        ( $renewokay, $error ) =
1205
          CanBookBeRenewed( $patron->{borrowernumber}, $item_to_auto_renew->itemnumber );
1206
          CanBookBeRenewed( $expired_borrower_obj, $issue );
1206
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1207
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1207
        is( $error, 'auto_account_expired', 'Can not auto renew, lockExpiredPatronOpacActions=1 and patron is expired' );
1208
        is( $error, 'auto_account_expired', 'Can not auto renew, lockExpiredPatronOpacActions=1 and patron is expired' );
1208
        Koha::Checkouts->find( $checkout->issue_id )->delete;
1209
        $issue->delete;
1209
1210
1210
1211
        # Patron is not expired and BlockExpiredPatronOpacActions=1
1211
        # Patron is not expired and BlockExpiredPatronOpacActions=1
1212
        # => auto renew is allowed
1212
        # => auto renew is allowed
1213
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 1);
1213
        t::lib::Mocks::mock_preference('BlockExpiredPatronOpacActions', 1);
1214
        $patron = $renewing_borrower;
1214
        $issue = AddIssue( $renewing_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1215
        $checkout = AddIssue( $patron, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1216
        ( $renewokay, $error ) =
1215
        ( $renewokay, $error ) =
1217
          CanBookBeRenewed( $patron->{borrowernumber}, $item_to_auto_renew->itemnumber );
1216
          CanBookBeRenewed( $renewing_borrower_obj, $issue );
1218
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1217
        is( $renewokay, 0, 'Do not renew, renewal is automatic' );
1219
        is( $error, 'auto_renew', 'Can auto renew, BlockExpiredPatronOpacActions=1 but patron is not expired' );
1218
        is( $error, 'auto_renew', 'Can auto renew, BlockExpiredPatronOpacActions=1 but patron is not expired' );
1220
        Koha::Checkouts->find( $checkout->issue_id )->delete;
1219
        $issue->delete;
1221
    };
1220
    };
1222
1221
1223
    subtest "GetLatestAutoRenewDate" => sub {
1222
    subtest "GetLatestAutoRenewDate" => sub {
Lines 1231-1237 subtest "CanBookBeRenewed tests" => sub { Link Here
1231
1230
1232
        my $ten_days_before = dt_from_string->add( days => -10 );
1231
        my $ten_days_before = dt_from_string->add( days => -10 );
1233
        my $ten_days_ahead  = dt_from_string->add( days => 10 );
1232
        my $ten_days_ahead  = dt_from_string->add( days => 10 );
1234
        AddIssue( $renewing_borrower, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1233
        my $issue = AddIssue( $renewing_borrower_obj->unblessed, $item_to_auto_renew->barcode, $ten_days_ahead, undef, $ten_days_before, undef, { auto_renew => 1 } );
1235
        Koha::CirculationRules->set_rules(
1234
        Koha::CirculationRules->set_rules(
1236
            {
1235
            {
1237
                categorycode => undef,
1236
                categorycode => undef,
Lines 1244-1250 subtest "CanBookBeRenewed tests" => sub { Link Here
1244
                }
1243
                }
1245
            }
1244
            }
1246
        );
1245
        );
1247
        my $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1246
        my $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrower_obj, $issue );
1248
        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' );
1247
        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' );
1249
        my $five_days_before = dt_from_string->add( days => -5 );
1248
        my $five_days_before = dt_from_string->add( days => -5 );
1250
        Koha::CirculationRules->set_rules(
1249
        Koha::CirculationRules->set_rules(
Lines 1259-1265 subtest "CanBookBeRenewed tests" => sub { Link Here
1259
                }
1258
                }
1260
            }
1259
            }
1261
        );
1260
        );
1262
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1261
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrower_obj,, $issue );
1263
        is( $latest_auto_renew_date->truncate( to => 'minute' ),
1262
        is( $latest_auto_renew_date->truncate( to => 'minute' ),
1264
            $five_days_before->truncate( to => 'minute' ),
1263
            $five_days_before->truncate( to => 'minute' ),
1265
            'GetLatestAutoRenewDate should return -5 days if no_auto_renewal_after = 5 and date_due is 10 days before'
1264
            'GetLatestAutoRenewDate should return -5 days if no_auto_renewal_after = 5 and date_due is 10 days before'
Lines 1281-1287 subtest "CanBookBeRenewed tests" => sub { Link Here
1281
                }
1280
                }
1282
            }
1281
            }
1283
        );
1282
        );
1284
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1283
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrower_obj, $issue );
1285
        is( $latest_auto_renew_date->truncate( to => 'minute' ),
1284
        is( $latest_auto_renew_date->truncate( to => 'minute' ),
1286
            $five_days_ahead->truncate( to => 'minute' ),
1285
            $five_days_ahead->truncate( to => 'minute' ),
1287
            'GetLatestAutoRenewDate should return +5 days if no_auto_renewal_after = 15 and date_due is 10 days before'
1286
            'GetLatestAutoRenewDate should return +5 days if no_auto_renewal_after = 15 and date_due is 10 days before'
Lines 1299-1305 subtest "CanBookBeRenewed tests" => sub { Link Here
1299
                }
1298
                }
1300
            }
1299
            }
1301
        );
1300
        );
1302
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1301
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrower_obj, $issue );
1303
        is( $latest_auto_renew_date->truncate( to => 'day' ),
1302
        is( $latest_auto_renew_date->truncate( to => 'day' ),
1304
            $two_days_ahead->truncate( to => 'day' ),
1303
            $two_days_ahead->truncate( to => 'day' ),
1305
            'GetLatestAutoRenewDate should return +2 days if no_auto_renewal_after_hard_limit is defined and not no_auto_renewal_after'
1304
            'GetLatestAutoRenewDate should return +2 days if no_auto_renewal_after_hard_limit is defined and not no_auto_renewal_after'
Lines 1316-1322 subtest "CanBookBeRenewed tests" => sub { Link Here
1316
                }
1315
                }
1317
            }
1316
            }
1318
        );
1317
        );
1319
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrowernumber, $item_to_auto_renew->itemnumber );
1318
        $latest_auto_renew_date = GetLatestAutoRenewDate( $renewing_borrower_obj, $issue );
1320
        is( $latest_auto_renew_date->truncate( to => 'day' ),
1319
        is( $latest_auto_renew_date->truncate( to => 'day' ),
1321
            $two_days_ahead->truncate( to => 'day' ),
1320
            $two_days_ahead->truncate( to => 'day' ),
1322
            'GetLatestAutoRenewDate should return +2 days if no_auto_renewal_after_hard_limit is < no_auto_renewal_after'
1321
            'GetLatestAutoRenewDate should return +2 days if no_auto_renewal_after_hard_limit is < no_auto_renewal_after'
Lines 1338-1344 subtest "CanBookBeRenewed tests" => sub { Link Here
1338
        }
1337
        }
1339
    );
1338
    );
1340
1339
1341
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
1340
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
1342
    is( $renewokay, 0, 'Cannot renew, 0 renewals allowed');
1341
    is( $renewokay, 0, 'Cannot renew, 0 renewals allowed');
1343
    is( $error, 'too_many', 'Cannot renew, 0 renewals allowed (returned code is too_many)');
1342
    is( $error, 'too_many', 'Cannot renew, 0 renewals allowed (returned code is too_many)');
1344
1343
Lines 1355-1362 subtest "CanBookBeRenewed tests" => sub { Link Here
1355
        }
1354
        }
1356
    );
1355
    );
1357
    t::lib::Mocks::mock_preference('UnseenRenewals', 1);
1356
    t::lib::Mocks::mock_preference('UnseenRenewals', 1);
1358
    $dbh->do('UPDATE issues SET unseen_renewals = 2 where borrowernumber = ? AND itemnumber = ?', undef, ($renewing_borrowernumber, $item_1->itemnumber));
1357
    $issue_1->unseen_renewals(2)->store;
1359
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber);
1358
1359
    ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrower_obj, $issue_1);
1360
    is( $renewokay, 0, 'Cannot renew, 0 unseen renewals allowed');
1360
    is( $renewokay, 0, 'Cannot renew, 0 unseen renewals allowed');
1361
    is( $error, 'too_unseen', 'Cannot renew, returned code is too_unseen');
1361
    is( $error, 'too_unseen', 'Cannot renew, returned code is too_unseen');
1362
    Koha::CirculationRules->set_rules(
1362
    Koha::CirculationRules->set_rules(
Lines 1378-1398 subtest "CanBookBeRenewed tests" => sub { Link Here
1378
1378
1379
    C4::Overdues::UpdateFine(
1379
    C4::Overdues::UpdateFine(
1380
        {
1380
        {
1381
            issue_id       => $issue->id(),
1381
            issue_id       => $issue_1->id(),
1382
            itemnumber     => $item_1->itemnumber,
1382
            itemnumber     => $item_1->itemnumber,
1383
            borrowernumber => $renewing_borrower->{borrowernumber},
1383
            borrowernumber => $renewing_borrower_obj->borrowernumber,
1384
            amount         => 15.00,
1384
            amount         => 15.00,
1385
            type           => q{},
1385
            type           => q{},
1386
            due            => Koha::DateUtils::output_pref($datedue)
1386
            due            => Koha::DateUtils::output_pref($datedue)
1387
        }
1387
        }
1388
    );
1388
    );
1389
1389
1390
    my $line = Koha::Account::Lines->search({ borrowernumber => $renewing_borrower->{borrowernumber} })->next();
1390
    my $line = Koha::Account::Lines->search({ borrowernumber => $renewing_borrower_obj->borrowernumber })->next();
1391
    is( $line->debit_type_code, 'OVERDUE', 'Account line type is OVERDUE' );
1391
    is( $line->debit_type_code, 'OVERDUE', 'Account line type is OVERDUE' );
1392
    is( $line->status, 'UNRETURNED', 'Account line status is UNRETURNED' );
1392
    is( $line->status, 'UNRETURNED', 'Account line status is UNRETURNED' );
1393
    is( $line->amountoutstanding+0, 15, 'Account line amount outstanding is 15.00' );
1393
    is( $line->amountoutstanding+0, 15, 'Account line amount outstanding is 15.00' );
1394
    is( $line->amount+0, 15, 'Account line amount is 15.00' );
1394
    is( $line->amount+0, 15, 'Account line amount is 15.00' );
1395
    is( $line->issue_id, $issue->id, 'Account line issue id matches' );
1395
    is( $line->issue_id, $issue_1->id, 'Account line issue id matches' );
1396
1396
1397
    my $offset = Koha::Account::Offsets->search({ debit_id => $line->id })->next();
1397
    my $offset = Koha::Account::Offsets->search({ debit_id => $line->id })->next();
1398
    is( $offset->type, 'CREATE', 'Account offset type is CREATE' );
1398
    is( $offset->type, 'CREATE', 'Account offset type is CREATE' );
Lines 1414-1420 subtest "CanBookBeRenewed tests" => sub { Link Here
1414
1414
1415
    my $total_due = $dbh->selectrow_array(
1415
    my $total_due = $dbh->selectrow_array(
1416
        'SELECT SUM( amountoutstanding ) FROM accountlines WHERE borrowernumber = ?',
1416
        'SELECT SUM( amountoutstanding ) FROM accountlines WHERE borrowernumber = ?',
1417
        undef, $renewing_borrower->{borrowernumber}
1417
        undef, $renewing_borrower_obj->borrowernumber
1418
    );
1418
    );
1419
1419
1420
    is( $total_due+0, 15, 'Borrower only charged replacement fee with both WhenLostForgiveFine and WhenLostChargeReplacementFee enabled' );
1420
    is( $total_due+0, 15, 'Borrower only charged replacement fee with both WhenLostForgiveFine and WhenLostChargeReplacementFee enabled' );
Lines 1423-1431 subtest "CanBookBeRenewed tests" => sub { Link Here
1423
1423
1424
    C4::Overdues::UpdateFine(
1424
    C4::Overdues::UpdateFine(
1425
        {
1425
        {
1426
            issue_id       => $issue2->id(),
1426
            issue_id       => $issue_2->id(),
1427
            itemnumber     => $item_2->itemnumber,
1427
            itemnumber     => $item_2->itemnumber,
1428
            borrowernumber => $renewing_borrower->{borrowernumber},
1428
            borrowernumber => $renewing_borrower_obj->borrowernumber,
1429
            amount         => 15.00,
1429
            amount         => 15.00,
1430
            type           => q{},
1430
            type           => q{},
1431
            due            => Koha::DateUtils::output_pref($datedue)
1431
            due            => Koha::DateUtils::output_pref($datedue)
Lines 1440-1446 subtest "CanBookBeRenewed tests" => sub { Link Here
1440
1440
1441
    $total_due = $dbh->selectrow_array(
1441
    $total_due = $dbh->selectrow_array(
1442
        'SELECT SUM( amountoutstanding ) FROM accountlines WHERE borrowernumber = ?',
1442
        'SELECT SUM( amountoutstanding ) FROM accountlines WHERE borrowernumber = ?',
1443
        undef, $renewing_borrower->{borrowernumber}
1443
        undef, $renewing_borrower_obj->borrowernumber
1444
    );
1444
    );
1445
1445
1446
    ok( $total_due == 15, 'Borrower only charged fine with both WhenLostForgiveFine and WhenLostChargeReplacementFee disabled' );
1446
    ok( $total_due == 15, 'Borrower only charged fine with both WhenLostForgiveFine and WhenLostChargeReplacementFee disabled' );
Lines 1478-1488 subtest "CanBookBeRenewed tests" => sub { Link Here
1478
        },
1478
        },
1479
    });
1479
    });
1480
    my $recall_borrower = $builder->build_object({ class => 'Koha::Patrons' });
1480
    my $recall_borrower = $builder->build_object({ class => 'Koha::Patrons' });
1481
    my $recall_biblio = $builder->build_object({ class => 'Koha::Biblios' });
1481
    my $recall_biblio = $builder->build_sample_biblio();
1482
    my $recall_item1 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $recall_biblio->biblionumber } });
1482
    my $recall_item1 = $builder->build_sample_item({ biblionumber => $recall_biblio->biblionumber });
1483
    my $recall_item2 = $builder->build_object({ class => 'Koha::Items' }, { value => { biblionumber => $recall_biblio->biblionumber } });
1483
    my $recall_item2 = $builder->build_sample_item({ biblionumber => $recall_biblio->biblionumber });
1484
1484
1485
    AddIssue( $renewing_borrower, $recall_item1->barcode );
1485
    my $recall_issue = AddIssue( $renewing_borrower_obj->unblessed, $recall_item1->barcode );
1486
1486
1487
    # item-level and this item: renewal not allowed
1487
    # item-level and this item: renewal not allowed
1488
    my $recall = Koha::Recall->new({
1488
    my $recall = Koha::Recall->new({
Lines 1492-1498 subtest "CanBookBeRenewed tests" => sub { Link Here
1492
        pickup_library_id => $recall_borrower->branchcode,
1492
        pickup_library_id => $recall_borrower->branchcode,
1493
        item_level => 1,
1493
        item_level => 1,
1494
    })->store;
1494
    })->store;
1495
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1495
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $recall_issue );
1496
    is( $error, 'recalled', 'Cannot renew item that has been recalled' );
1496
    is( $error, 'recalled', 'Cannot renew item that has been recalled' );
1497
    $recall->set_cancelled;
1497
    $recall->set_cancelled;
1498
1498
Lines 1504-1510 subtest "CanBookBeRenewed tests" => sub { Link Here
1504
        pickup_library_id => $recall_borrower->branchcode,
1504
        pickup_library_id => $recall_borrower->branchcode,
1505
        item_level => 0,
1505
        item_level => 0,
1506
    })->store;
1506
    })->store;
1507
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1507
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $recall_issue );
1508
    is( $error, 'recalled', 'Cannot renew item if biblio is recalled and has no item allocated' );
1508
    is( $error, 'recalled', 'Cannot renew item if biblio is recalled and has no item allocated' );
1509
    $recall->set_cancelled;
1509
    $recall->set_cancelled;
1510
1510
Lines 1516-1522 subtest "CanBookBeRenewed tests" => sub { Link Here
1516
        pickup_library_id => $recall_borrower->branchcode,
1516
        pickup_library_id => $recall_borrower->branchcode,
1517
        item_level => 1,
1517
        item_level => 1,
1518
    })->store;
1518
    })->store;
1519
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1519
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $recall_issue );
1520
    is( $renewokay, 1, 'Can renew item if item-level recall on biblio is not on this item' );
1520
    is( $renewokay, 1, 'Can renew item if item-level recall on biblio is not on this item' );
1521
    $recall->set_cancelled;
1521
    $recall->set_cancelled;
1522
1522
Lines 1529-1535 subtest "CanBookBeRenewed tests" => sub { Link Here
1529
        item_level => 0,
1529
        item_level => 0,
1530
    })->store;
1530
    })->store;
1531
    $recall->set_waiting({ item => $recall_item1 });
1531
    $recall->set_waiting({ item => $recall_item1 });
1532
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrowernumber, $recall_item1->itemnumber );
1532
    ( $renewokay, $error ) = CanBookBeRenewed( $renewing_borrower_obj, $recall_issue );
1533
    is( $renewokay, 1, 'Can renew item if biblio-level recall has already been allocated an item' );
1533
    is( $renewokay, 1, 'Can renew item if biblio-level recall has already been allocated an item' );
1534
    $recall->set_cancelled;
1534
    $recall->set_cancelled;
1535
};
1535
};
Lines 1571-1577 subtest "GetUpcomingDueIssues" => sub { Link Here
1571
1571
1572
    my $issue = AddIssue( $a_borrower, $item_1->barcode, $yesterday );
1572
    my $issue = AddIssue( $a_borrower, $item_1->barcode, $yesterday );
1573
    my $datedue = dt_from_string( $issue->date_due() );
1573
    my $datedue = dt_from_string( $issue->date_due() );
1574
    my $issue2 = AddIssue( $a_borrower, $item_2->barcode, $two_days_ahead );
1574
    my $issue_2 = AddIssue( $a_borrower, $item_2->barcode, $two_days_ahead );
1575
    my $datedue2 = dt_from_string( $issue->date_due() );
1575
    my $datedue2 = dt_from_string( $issue->date_due() );
1576
1576
1577
    my $upcoming_dues;
1577
    my $upcoming_dues;
Lines 1697-1708 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1697
    );
1697
    );
1698
1698
1699
1699
1700
    my $borrowernumber1 = Koha::Patron->new({
1700
    my $borrower1 = Koha::Patron->new({
1701
        firstname    => 'Kyle',
1701
        firstname    => 'Kyle',
1702
        surname      => 'Hall',
1702
        surname      => 'Hall',
1703
        categorycode => $patron_category->{categorycode},
1703
        categorycode => $patron_category->{categorycode},
1704
        branchcode   => $library2->{branchcode},
1704
        branchcode   => $library2->{branchcode},
1705
    })->store->borrowernumber;
1705
    })->store;
1706
    my $borrowernumber2 = Koha::Patron->new({
1706
    my $borrowernumber2 = Koha::Patron->new({
1707
        firstname    => 'Chelsea',
1707
        firstname    => 'Chelsea',
1708
        surname      => 'Hall',
1708
        surname      => 'Hall',
Lines 1726-1737 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1726
        branchcode   => $library2->{branchcode},
1726
        branchcode   => $library2->{branchcode},
1727
    })->store->borrowernumber;
1727
    })->store->borrowernumber;
1728
1728
1729
    my $borrower1 = Koha::Patrons->find( $borrowernumber1 )->unblessed;
1729
    my $issue = AddIssue( $borrower1->unblessed, $item_1->barcode );
1730
    my $borrower2 = Koha::Patrons->find( $borrowernumber2 )->unblessed;
1731
1730
1732
    my $issue = AddIssue( $borrower1, $item_1->barcode );
1731
    my ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1733
1734
    my ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1735
    is( $renewokay, 1, 'Bug 14337 - Verify the borrower can renew with no hold on the record' );
1732
    is( $renewokay, 1, 'Bug 14337 - Verify the borrower can renew with no hold on the record' );
1736
1733
1737
    AddReserve(
1734
    AddReserve(
Lines 1754-1764 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1754
        }
1751
        }
1755
    );
1752
    );
1756
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 0 );
1753
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 0 );
1757
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1754
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1758
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable and onshelfholds are disabled' );
1755
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable and onshelfholds are disabled' );
1759
1756
1760
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 1 );
1757
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 1 );
1761
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1758
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1762
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable is enabled and onshelfholds is disabled' );
1759
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable is enabled and onshelfholds is disabled' );
1763
1760
1764
    Koha::CirculationRules->set_rules(
1761
    Koha::CirculationRules->set_rules(
Lines 1772-1782 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1772
        }
1769
        }
1773
    );
1770
    );
1774
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 0 );
1771
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 0 );
1775
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1772
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1776
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable is disabled and onshelfhold is enabled' );
1773
    is( $renewokay, 0, 'Bug 14337 - Verify the borrower cannot renew with a hold on the record if AllowRenewalIfOtherItemsAvailable is disabled and onshelfhold is enabled' );
1777
1774
1778
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 1 );
1775
    t::lib::Mocks::mock_preference( 'AllowRenewalIfOtherItemsAvailable', 1 );
1779
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1776
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1780
    is( $renewokay, 1, 'Bug 14337 - Verify the borrower can renew with a hold on the record if AllowRenewalIfOtherItemsAvailable and onshelfhold are enabled' );
1777
    is( $renewokay, 1, 'Bug 14337 - Verify the borrower can renew with a hold on the record if AllowRenewalIfOtherItemsAvailable and onshelfhold are enabled' );
1781
1778
1782
    AddReserve(
1779
    AddReserve(
Lines 1788-1794 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1788
        }
1785
        }
1789
    );
1786
    );
1790
1787
1791
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1788
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1792
    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' );
1789
    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' );
1793
1790
1794
    my $item_3= $builder->build_sample_item(
1791
    my $item_3= $builder->build_sample_item(
Lines 1799-1805 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1799
        }
1796
        }
1800
    );
1797
    );
1801
1798
1802
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1799
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1803
    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' );
1800
    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' );
1804
1801
1805
    Koha::CirculationRules->set_rules(
1802
    Koha::CirculationRules->set_rules(
Lines 1813-1819 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1813
        }
1810
        }
1814
    );
1811
    );
1815
1812
1816
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1813
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1817
    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' );
1814
    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' );
1818
1815
1819
    Koha::CirculationRules->set_rules(
1816
    Koha::CirculationRules->set_rules(
Lines 1830-1836 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1830
    # Setting item not checked out to be not for loan but holdable
1827
    # Setting item not checked out to be not for loan but holdable
1831
    $item_2->notforloan(-1)->store;
1828
    $item_2->notforloan(-1)->store;
1832
1829
1833
    ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1830
    ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1834
    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' );
1831
    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' );
1835
1832
1836
    my $mock_circ = Test::MockModule->new("C4::Circulation");
1833
    my $mock_circ = Test::MockModule->new("C4::Circulation");
Lines 1844-1850 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1844
    # Two items total, one item available, one issued, two holds on record
1841
    # Two items total, one item available, one issued, two holds on record
1845
1842
1846
    warnings_are{
1843
    warnings_are{
1847
       ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1844
       ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1848
    } [], "CanItemBeReserved not called when there are more possible holds than available items";
1845
    } [], "CanItemBeReserved not called when there are more possible holds than available items";
1849
    is( $renewokay, 0, 'Borrower cannot renew when there are more holds than available items' );
1846
    is( $renewokay, 0, 'Borrower cannot renew when there are more holds than available items' );
1850
1847
Lines 1868-1874 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1868
    );
1865
    );
1869
1866
1870
    warnings_are{
1867
    warnings_are{
1871
       ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1868
       ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
1872
    } ["Checked","Checked"], "CanItemBeReserved only called once per available item if it returns a negative result for all items for a borrower";
1869
    } ["Checked","Checked"], "CanItemBeReserved only called once per available item if it returns a negative result for all items for a borrower";
1873
    is( $renewokay, 0, 'Borrower cannot renew when there are more holds than available items' );
1870
    is( $renewokay, 0, 'Borrower cannot renew when there are more holds than available items' );
1874
1871
Lines 1889-1905 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1889
        }
1886
        }
1890
    );
1887
    );
1891
1888
1892
    my $borrowernumber = Koha::Patron->new({
1889
    my $borrower = Koha::Patron->new({
1893
        firstname =>  'fn',
1890
        firstname =>  'fn',
1894
        surname => 'dn',
1891
        surname => 'dn',
1895
        categorycode => $patron_category->{categorycode},
1892
        categorycode => $patron_category->{categorycode},
1896
        branchcode => $branch,
1893
        branchcode => $branch,
1897
    })->store->borrowernumber;
1894
    })->store;
1898
1899
    my $borrower = Koha::Patrons->find( $borrowernumber )->unblessed;
1900
1895
1901
    my $issue = AddIssue( $borrower, $item->barcode, undef, undef, undef, undef, { onsite_checkout => 1 } );
1896
    my $issue = AddIssue( $borrower->unblessed, $item->barcode, undef, undef, undef, undef, { onsite_checkout => 1 } );
1902
    my ( $renewed, $error ) = CanBookBeRenewed( $borrowernumber, $item->itemnumber );
1897
    my ( $renewed, $error ) = CanBookBeRenewed( $borrower, $issue );
1903
    is( $renewed, 0, 'CanBookBeRenewed should not allow to renew on-site checkout' );
1898
    is( $renewed, 0, 'CanBookBeRenewed should not allow to renew on-site checkout' );
1904
    is( $error, 'onsite_checkout', 'A correct error code should be returned by CanBookBeRenewed for on-site checkout' );
1899
    is( $error, 'onsite_checkout', 'A correct error code should be returned by CanBookBeRenewed for on-site checkout' );
1905
}
1900
}
Lines 1916-1939 subtest "AllowRenewalIfOtherItemsAvailable tests" => sub { Link Here
1916
            itype            => $itemtype,
1911
            itype            => $itemtype,
1917
        }
1912
        }
1918
    );
1913
    );
1914
    my $patron = $builder->build_object( { class => 'Koha::Patrons',  value => { branchcode => $library->{branchcode}, categorycode => $patron_category->{categorycode} } } );
1919
1915
1920
    my $patron = $builder->build({ source => 'Borrower', value => { branchcode => $library->{branchcode}, categorycode => $patron_category->{categorycode} } } );
1916
    my $issue = AddIssue( $patron->unblessed, $item->barcode );
1921
1922
    my $issue = AddIssue( $patron, $item->barcode );
1923
    UpdateFine(
1917
    UpdateFine(
1924
        {
1918
        {
1925
            issue_id       => $issue->id(),
1919
            issue_id       => $issue->id,
1926
            itemnumber     => $item->itemnumber,
1920
            itemnumber     => $item->itemnumber,
1927
            borrowernumber => $patron->{borrowernumber},
1921
            borrowernumber => $patron->borrowernumber,
1928
            amount         => 1,
1922
            amount         => 1,
1929
            type           => q{}
1923
            type           => q{}
1930
        }
1924
        }
1931
    );
1925
    );
1932
    UpdateFine(
1926
    UpdateFine(
1933
        {
1927
        {
1934
            issue_id       => $issue->id(),
1928
            issue_id       => $issue->id,
1935
            itemnumber     => $item->itemnumber,
1929
            itemnumber     => $item->itemnumber,
1936
            borrowernumber => $patron->{borrowernumber},
1930
            borrowernumber => $patron->borrowernumber,
1937
            amount         => 2,
1931
            amount         => 2,
1938
            type           => q{}
1932
            type           => q{}
1939
        }
1933
        }
Lines 2349-2357 subtest 'MultipleReserves' => sub { Link Here
2349
        categorycode => $patron_category->{categorycode},
2343
        categorycode => $patron_category->{categorycode},
2350
        branchcode => $branch,
2344
        branchcode => $branch,
2351
    );
2345
    );
2352
    my $renewing_borrowernumber = Koha::Patron->new(\%renewing_borrower_data)->store->borrowernumber;
2346
    my $patron = Koha::Patron->new(\%renewing_borrower_data)->store;
2353
    my $renewing_borrower = Koha::Patrons->find( $renewing_borrowernumber )->unblessed;
2347
    my $issue = AddIssue( $patron->unblessed, $item_1->barcode);
2354
    my $issue = AddIssue( $renewing_borrower, $item_1->barcode);
2355
    my $datedue = dt_from_string( $issue->date_due() );
2348
    my $datedue = dt_from_string( $issue->date_due() );
2356
    is (defined $issue->date_due(), 1, "item 1 checked out");
2349
    is (defined $issue->date_due(), 1, "item 1 checked out");
2357
    my $borrowing_borrowernumber = Koha::Checkouts->find({ itemnumber => $item_1->itemnumber })->borrowernumber;
2350
    my $borrowing_borrowernumber = Koha::Checkouts->find({ itemnumber => $item_1->itemnumber })->borrowernumber;
Lines 2399-2405 subtest 'MultipleReserves' => sub { Link Here
2399
    );
2392
    );
2400
2393
2401
    {
2394
    {
2402
        my ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber, 1);
2395
        my ( $renewokay, $error ) = CanBookBeRenewed($patron, $issue, 1);
2403
        is($renewokay, 0, 'Bug 17941 - should cover the case where 2 books are both reserved, so failing');
2396
        is($renewokay, 0, 'Bug 17941 - should cover the case where 2 books are both reserved, so failing');
2404
    }
2397
    }
2405
2398
Lines 2413-2419 subtest 'MultipleReserves' => sub { Link Here
2413
    );
2406
    );
2414
2407
2415
    {
2408
    {
2416
        my ( $renewokay, $error ) = CanBookBeRenewed($renewing_borrowernumber, $item_1->itemnumber, 1);
2409
        my ( $renewokay, $error ) = CanBookBeRenewed($patron, $issue, 1);
2417
        is($renewokay, 1, 'Bug 17941 - should cover the case where 2 books are reserved, but a third one is available');
2410
        is($renewokay, 1, 'Bug 17941 - should cover the case where 2 books are reserved, but a third one is available');
2418
    }
2411
    }
2419
};
2412
};
Lines 4015-4021 subtest 'Set waiting flag' => sub { Link Here
4015
    my $hold = Koha::Holds->find( $reserve_id );
4008
    my $hold = Koha::Holds->find( $reserve_id );
4016
    is( $hold->found, 'T', 'Hold is in transit' );
4009
    is( $hold->found, 'T', 'Hold is in transit' );
4017
4010
4018
    my ( $status ) = CheckReserves($item->itemnumber);
4011
    my ( $status ) = CheckReserves($item);
4019
    is( $status, 'Transferred', 'Hold is not waiting yet');
4012
    is( $status, 'Transferred', 'Hold is not waiting yet');
4020
4013
4021
    set_userenv( $library_2 );
4014
    set_userenv( $library_2 );
Lines 4024-4030 subtest 'Set waiting flag' => sub { Link Here
4024
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
4017
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
4025
    $hold = Koha::Holds->find( $reserve_id );
4018
    $hold = Koha::Holds->find( $reserve_id );
4026
    is( $hold->found, 'W', 'Hold is waiting' );
4019
    is( $hold->found, 'W', 'Hold is waiting' );
4027
    ( $status ) = CheckReserves($item->itemnumber);
4020
    ( $status ) = CheckReserves($item);
4028
    is( $status, 'Waiting', 'Now the hold is waiting');
4021
    is( $status, 'Waiting', 'Now the hold is waiting');
4029
4022
4030
    #Bug 21944 - Waiting transfer checked in at branch other than pickup location
4023
    #Bug 21944 - Waiting transfer checked in at branch other than pickup location
Lines 4209-4222 subtest 'ItemsDeniedRenewal rules are checked' => sub { Link Here
4209
    my $mock_item_class = Test::MockModule->new("Koha::Item");
4202
    my $mock_item_class = Test::MockModule->new("Koha::Item");
4210
    $mock_item_class->mock( 'is_denied_renewal', sub { return 1; } );
4203
    $mock_item_class->mock( 'is_denied_renewal', sub { return 1; } );
4211
4204
4212
    my ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower->borrowernumber, $issue->itemnumber );
4205
    my ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower, $issue );
4213
    is( $mayrenew, 0, 'Renewal blocked when $item->is_denied_renewal returns true' );
4206
    is( $mayrenew, 0, 'Renewal blocked when $item->is_denied_renewal returns true' );
4214
    is( $error, 'item_denied_renewal', 'Renewal blocked when $item->is_denied_renewal returns true' );
4207
    is( $error, 'item_denied_renewal', 'Renewal blocked when $item->is_denied_renewal returns true' );
4215
4208
4216
    $mock_item_class->unmock( 'is_denied_renewal' );
4209
    $mock_item_class->unmock( 'is_denied_renewal' );
4217
    $mock_item_class->mock( 'is_denied_renewal', sub { return 0; } );
4210
    $mock_item_class->mock( 'is_denied_renewal', sub { return 0; } );
4218
4211
4219
    ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower->borrowernumber, $issue->itemnumber );
4212
    ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower, $issue );
4220
    is( $mayrenew, 1, 'Renewal allowed when $item->is_denied_renewal returns false' );
4213
    is( $mayrenew, 1, 'Renewal allowed when $item->is_denied_renewal returns false' );
4221
    is( $error, undef, 'Renewal allowed when $item->is_denied_renewal returns false' );
4214
    is( $error, undef, 'Renewal allowed when $item->is_denied_renewal returns false' );
4222
4215
Lines 5704-5710 subtest "GetSoonestRenewDate tests" => sub { Link Here
5704
    # Test 'exact time' setting for syspref NoRenewalBeforePrecision
5697
    # Test 'exact time' setting for syspref NoRenewalBeforePrecision
5705
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact_time' );
5698
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact_time' );
5706
    is(
5699
    is(
5707
        GetSoonestRenewDate( $issue ),
5700
        GetSoonestRenewDate( $patron, $issue ),
5708
        $datedue->clone->add( days => -7 ),
5701
        $datedue->clone->add( days => -7 ),
5709
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5702
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5710
    );
5703
    );
Lines 5713-5719 subtest "GetSoonestRenewDate tests" => sub { Link Here
5713
    # Test 'date' setting for syspref NoRenewalBeforePrecision
5706
    # Test 'date' setting for syspref NoRenewalBeforePrecision
5714
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5707
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5715
    is(
5708
    is(
5716
        GetSoonestRenewDate( $issue ),
5709
        GetSoonestRenewDate( $patron, $issue ),
5717
        $datedue->clone->add( days => -7 )->truncate( to => 'day' ),
5710
        $datedue->clone->add( days => -7 )->truncate( to => 'day' ),
5718
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5711
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5719
    );
5712
    );
Lines 5730-5736 subtest "GetSoonestRenewDate tests" => sub { Link Here
5730
    );
5723
    );
5731
5724
5732
    is(
5725
    is(
5733
        GetSoonestRenewDate( $issue ),
5726
        GetSoonestRenewDate( $patron, $issue ),
5734
        dt_from_string,
5727
        dt_from_string,
5735
        'Checkouts without auto-renewal can be renewed immediately if no norenewalbefore'
5728
        'Checkouts without auto-renewal can be renewed immediately if no norenewalbefore'
5736
    );
5729
    );
Lines 5738-5750 subtest "GetSoonestRenewDate tests" => sub { Link Here
5738
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5731
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5739
    $issue->auto_renew(1)->store;
5732
    $issue->auto_renew(1)->store;
5740
    is(
5733
    is(
5741
        GetSoonestRenewDate( $issue ),
5734
        GetSoonestRenewDate( $patron, $issue ),
5742
        $datedue->clone->truncate( to => 'day' ),
5735
        $datedue->clone->truncate( to => 'day' ),
5743
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5736
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5744
    );
5737
    );
5745
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact' );
5738
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact' );
5746
    is(
5739
    is(
5747
        GetSoonestRenewDate( $issue ),
5740
        GetSoonestRenewDate( $patron, $issue ),
5748
        $datedue,
5741
        $datedue,
5749
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5742
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5750
    );
5743
    );
Lines 5757-5763 subtest "CanBookBeIssued + needsconfirmation message" => sub { Link Here
5757
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
5750
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
5758
    my $biblio = $builder->build_object({ class => 'Koha::Biblios' });
5751
    my $biblio = $builder->build_object({ class => 'Koha::Biblios' });
5759
    my $biblioitem = $builder->build_object({ class => 'Koha::Biblioitems', value => { biblionumber => $biblio->biblionumber }});
5752
    my $biblioitem = $builder->build_object({ class => 'Koha::Biblioitems', value => { biblionumber => $biblio->biblionumber }});
5760
    my $item = $builder->build_object({ class => 'Koha::Items' , value => { biblionumber => $biblio->biblionumber }});
5753
    my $item = $builder->build_object({ class => 'Koha::Items' , value => { itype => $itemtype, biblionumber => $biblio->biblionumber }});
5761
5754
5762
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
5755
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
5763
        biblionumber => $item->biblionumber,
5756
        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