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 2338-2344 sub AddReturn { Link Here
2338
    # launch the Checkreserves routine to find any holds
2336
    # launch the Checkreserves routine to find any holds
2339
    my ($resfound, $resrec);
2337
    my ($resfound, $resrec);
2340
    my $lookahead= C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2338
    my $lookahead= C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds
2341
    ($resfound, $resrec, undef) = C4::Reserves::CheckReserves( $item->itemnumber, undef, $lookahead ) unless ( $item->withdrawn );
2339
    ($resfound, $resrec, undef) = CheckReserves( $item, $lookahead ) unless ( $item->withdrawn );
2342
    # 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)
2340
    # 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)
2343
    if ( $resfound and $resfound eq "Waiting" and $branch ne $resrec->{branchcode} ) {
2341
    if ( $resfound and $resfound eq "Waiting" and $branch ne $resrec->{branchcode} ) {
2344
        my $hold = C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
2342
        my $hold = C4::Reserves::RevertWaitingStatus( { itemnumber => $item->itemnumber } );
Lines 2832-2845 sub GetUpcomingDueIssues { Link Here
2832
2830
2833
=head2 CanBookBeRenewed
2831
=head2 CanBookBeRenewed
2834
2832
2835
  ($ok,$error,$info) = &CanBookBeRenewed($borrowernumber, $itemnumber[, $override_limit]);
2833
  ($ok,$error,$info) = &CanBookBeRenewed($patron, $issue, $override_limit);
2836
2834
2837
Find out whether a borrowed item may be renewed.
2835
Find out whether a borrowed item may be renewed.
2838
2836
2839
C<$borrowernumber> is the borrower number of the patron who currently
2837
C<$patron> is the patron who currently has the issue.
2840
has the item on loan.
2841
2838
2842
C<$itemnumber> is the number of the item to renew.
2839
C<$issue> is the checkout to renew.
2843
2840
2844
C<$override_limit>, if supplied with a true value, causes
2841
C<$override_limit>, if supplied with a true value, causes
2845
the limit on the number of times that the loan can be renewed
2842
the limit on the number of times that the loan can be renewed
Lines 2858-2876 already renewed the loan. Link Here
2858
=cut
2855
=cut
2859
2856
2860
sub CanBookBeRenewed {
2857
sub CanBookBeRenewed {
2861
    my ( $borrowernumber, $itemnumber, $override_limit, $cron ) = @_;
2858
    my ( $patron, $issue, $override_limit, $cron ) = @_;
2862
2859
2863
    my $auto_renew = "no";
2860
    my $auto_renew = "no";
2864
    my $soonest;
2861
    my $soonest;
2862
    my $item = $issue->item;
2865
2863
2866
    my $item      = Koha::Items->find($itemnumber)      or return ( 0, 'no_item' );
2864
    return ( 0, 'no_item' ) unless $item;
2867
    my $issue = $item->checkout or return ( 0, 'no_checkout' );
2865
    return ( 0, 'no_checkout' ) unless $issue;
2868
    return ( 0, 'onsite_checkout' ) if $issue->onsite_checkout;
2866
    return ( 0, 'onsite_checkout' ) if $issue->onsite_checkout;
2867
    return ( 0, 'item_issued_to_other_patron') if $issue->borrowernumber != $patron->borrowernumber;
2869
    return ( 0, 'item_denied_renewal') if $item->is_denied_renewal;
2868
    return ( 0, 'item_denied_renewal') if $item->is_denied_renewal;
2870
2869
2871
    my $patron = $issue->patron or return;
2870
       # override_limit will override anything else except on_reserve
2872
2873
    # override_limit will override anything else except on_reserve
2874
    unless ( $override_limit ){
2871
    unless ( $override_limit ){
2875
        my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
2872
        my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
2876
        my $issuing_rule = Koha::CirculationRules->get_effective_rules(
2873
        my $issuing_rule = Koha::CirculationRules->get_effective_rules(
Lines 2896-2902 sub CanBookBeRenewed { Link Here
2896
2893
2897
        my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing');
2894
        my $overduesblockrenewing = C4::Context->preference('OverduesBlockRenewing');
2898
        my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
2895
        my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
2899
        $patron         = Koha::Patrons->find($borrowernumber); # FIXME Is this really useful?
2900
        my $restricted  = $patron->is_debarred;
2896
        my $restricted  = $patron->is_debarred;
2901
        my $hasoverdues = $patron->has_overdues;
2897
        my $hasoverdues = $patron->has_overdues;
2902
2898
Lines 2940-2948 sub CanBookBeRenewed { Link Here
2940
            non_priority => 0,
2936
            non_priority => 0,
2941
            found        => undef,
2937
            found        => undef,
2942
            reservedate  => { '<=' => \'NOW()' },
2938
            reservedate  => { '<=' => \'NOW()' },
2943
            suspend      => 0,
2939
            suspend      => 0
2944
        },
2940
        }
2945
        { prefetch => 'patron' }
2946
    );
2941
    );
2947
    if ( $fillable_holds->count ) {
2942
    if ( $fillable_holds->count ) {
2948
        if ( C4::Context->preference('AllowRenewalIfOtherItemsAvailable') ) {
2943
        if ( C4::Context->preference('AllowRenewalIfOtherItemsAvailable') ) {
Lines 2954-2960 sub CanBookBeRenewed { Link Here
2954
                biblionumber => $item->biblionumber,
2949
                biblionumber => $item->biblionumber,
2955
                onloan       => undef,
2950
                onloan       => undef,
2956
                notforloan   => 0,
2951
                notforloan   => 0,
2957
                -not         => { itemnumber => $itemnumber } })->as_list;
2952
                -not         => { itemnumber => $item->itemnumber } })->as_list;
2958
2953
2959
            return ( 0, "on_reserve" ) if @possible_holds && (scalar @other_items < scalar @possible_holds);
2954
            return ( 0, "on_reserve" ) if @possible_holds && (scalar @other_items < scalar @possible_holds);
2960
2955
Lines 2962-2968 sub CanBookBeRenewed { Link Here
2962
            foreach my $possible_hold (@possible_holds) {
2957
            foreach my $possible_hold (@possible_holds) {
2963
                my $fillable = 0;
2958
                my $fillable = 0;
2964
                my $patron_with_reserve = Koha::Patrons->find($possible_hold->borrowernumber);
2959
                my $patron_with_reserve = Koha::Patrons->find($possible_hold->borrowernumber);
2965
                my $items_any_available = ItemsAnyAvailableAndNotRestricted( { biblionumber => $item->biblionumber, patron => $patron_with_reserve });
2960
                my $items_any_available = ItemsAnyAvailableAndNotRestricted({
2961
                    biblionumber => $item->biblionumber,
2962
                    patron => $patron_with_reserve
2963
                });
2966
2964
2967
                # FIXME: We are not checking whether the item we are renewing can fill the hold
2965
                # FIXME: We are not checking whether the item we are renewing can fill the hold
2968
2966
Lines 2980-2994 sub CanBookBeRenewed { Link Here
2980
                }
2978
                }
2981
                return ( 0, "on_reserve" ) unless $fillable;
2979
                return ( 0, "on_reserve" ) unless $fillable;
2982
            }
2980
            }
2983
2981
        }
2984
        } else {
2982
        else {
2985
            my ($status, $matched_reserve, $possible_reserves) = CheckReserves($itemnumber);
2983
            my ($status, $matched_reserve, $possible_reserves) = CheckReserves($item);
2986
            return ( 0, "on_reserve" ) if $status;
2984
            return ( 0, "on_reserve" ) if $status;
2987
        }
2985
        }
2988
    }
2986
    }
2989
2987
2990
    return ( 0, $auto_renew, { soonest_renew_date => $soonest } ) if $auto_renew =~ 'too_soon';#$auto_renew ne "no" && $auto_renew ne "ok";
2988
    return ( 0, $auto_renew, { soonest_renew_date => $soonest } ) if $auto_renew =~ 'too_soon';#$auto_renew ne "no" && $auto_renew ne "ok";
2991
    $soonest = GetSoonestRenewDate($issue);
2989
    $soonest = GetSoonestRenewDate($patron, $issue);
2992
    if ( $soonest > dt_from_string() ){
2990
    if ( $soonest > dt_from_string() ){
2993
        return (0, "too_soon", { soonest_renew_date => $soonest } ) unless $override_limit;
2991
        return (0, "too_soon", { soonest_renew_date => $soonest } ) unless $override_limit;
2994
    }
2992
    }
Lines 3220-3226 sub AddRenewal { Link Here
3220
3218
3221
sub GetRenewCount {
3219
sub GetRenewCount {
3222
    # check renewal status
3220
    # check renewal status
3223
    my ( $bornum, $itemno ) = @_;
3221
    my ( $borrowernumber_or_patron, $itemnumber_or_item ) = @_;
3222
3224
    my $dbh           = C4::Context->dbh;
3223
    my $dbh           = C4::Context->dbh;
3225
    my $renewcount    = 0;
3224
    my $renewcount    = 0;
3226
    my $unseencount    = 0;
3225
    my $unseencount    = 0;
Lines 3228-3236 sub GetRenewCount { Link Here
3228
    my $unseenallowed = 0;
3227
    my $unseenallowed = 0;
3229
    my $renewsleft    = 0;
3228
    my $renewsleft    = 0;
3230
    my $unseenleft    = 0;
3229
    my $unseenleft    = 0;
3231
3230
    my $patron = blessed $borrowernumber_or_patron ?
3232
    my $patron = Koha::Patrons->find( $bornum );
3231
        $borrowernumber_or_patron : Koha::Patrons->find($borrowernumber_or_patron);
3233
    my $item   = Koha::Items->find($itemno);
3232
    my $item = blessed $itemnumber_or_item ?
3233
        $itemnumber_or_item : Koha::Items->find($itemnumber_or_item);
3234
3234
3235
    return (0, 0, 0, 0, 0, 0) unless $patron or $item; # Wrong call, no renewal allowed
3235
    return (0, 0, 0, 0, 0, 0) unless $patron or $item; # Wrong call, no renewal allowed
3236
3236
Lines 3238-3249 sub GetRenewCount { Link Here
3238
    # and not yet returned.
3238
    # and not yet returned.
3239
3239
3240
    # FIXME - I think this function could be redone to use only one SQL call.
3240
    # FIXME - I think this function could be redone to use only one SQL call.
3241
    my $sth = $dbh->prepare(
3241
    my $sth = $dbh->prepare(q{
3242
        "select * from issues
3242
        SELECT * FROM issues
3243
                                where (borrowernumber = ?)
3243
        WHERE  (borrowernumber = ?) AND (itemnumber = ?)
3244
                                and (itemnumber = ?)"
3244
    });
3245
    );
3245
    $sth->execute( $patron->borrowernumber, $item->itemnumber );
3246
    $sth->execute( $bornum, $itemno );
3247
    my $data = $sth->fetchrow_hashref;
3246
    my $data = $sth->fetchrow_hashref;
3248
    $renewcount = $data->{'renewals_count'} if $data->{'renewals_count'};
3247
    $renewcount = $data->{'renewals_count'} if $data->{'renewals_count'};
3249
    $unseencount = $data->{'unseen_renewals'} if $data->{'unseen_renewals'};
3248
    $unseencount = $data->{'unseen_renewals'} if $data->{'unseen_renewals'};
Lines 3278-3288 sub GetRenewCount { Link Here
3278
3277
3279
=head2 GetSoonestRenewDate
3278
=head2 GetSoonestRenewDate
3280
3279
3281
  $NoRenewalBeforeThisDate = &GetSoonestRenewDate($checkout);
3280
  $NoRenewalBeforeThisDate = &GetSoonestRenewDate($patron, $issue);
3282
3281
3283
Find out the soonest possible renew date of a borrowed item.
3282
Find out the soonest possible renew date of a borrowed item.
3284
3283
3285
C<$checkout> is the checkout object to renew.
3284
C<$patron> is the patron who currently has the item on loan.
3285
3286
C<$issue> is the the item issue.
3286
3287
3287
C<$GetSoonestRenewDate> returns the DateTime of the soonest possible
3288
C<$GetSoonestRenewDate> returns the DateTime of the soonest possible
3288
renew date, based on the value "No renewal before" of the applicable
3289
renew date, based on the value "No renewal before" of the applicable
Lines 3293-3302 cannot be found. Link Here
3293
=cut
3294
=cut
3294
3295
3295
sub GetSoonestRenewDate {
3296
sub GetSoonestRenewDate {
3296
    my ( $checkout ) = @_;
3297
    my ( $patron, $issue ) = @_;
3298
    return unless $issue;
3299
    return unless $patron;
3297
3300
3298
    my $item   = $checkout->item or return;
3301
    my $item = $issue->item;
3299
    my $patron = $checkout->patron or return;
3302
    return unless $item;
3303
3304
    my $dbh = C4::Context->dbh;
3300
3305
3301
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3306
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3302
    my $issuing_rule = Koha::CirculationRules->get_effective_rules(
3307
    my $issuing_rule = Koha::CirculationRules->get_effective_rules(
Lines 3316-3322 sub GetSoonestRenewDate { Link Here
3316
        and $issuing_rule->{norenewalbefore} ne "" )
3321
        and $issuing_rule->{norenewalbefore} ne "" )
3317
    {
3322
    {
3318
        my $soonestrenewal =
3323
        my $soonestrenewal =
3319
          dt_from_string( $checkout->date_due )->subtract(
3324
          dt_from_string( $issue->date_due )->subtract(
3320
            $issuing_rule->{lengthunit} => $issuing_rule->{norenewalbefore} );
3325
            $issuing_rule->{lengthunit} => $issuing_rule->{norenewalbefore} );
3321
3326
3322
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
3327
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
Lines 3325-3333 sub GetSoonestRenewDate { Link Here
3325
            $soonestrenewal->truncate( to => 'day' );
3330
            $soonestrenewal->truncate( to => 'day' );
3326
        }
3331
        }
3327
        return $soonestrenewal if $now < $soonestrenewal;
3332
        return $soonestrenewal if $now < $soonestrenewal;
3328
    } elsif ( $checkout->auto_renew && $patron->autorenew_checkouts ) {
3333
    } elsif ( $issue->auto_renew && $patron->autorenew_checkouts ) {
3329
        # Checkouts with auto-renewing fall back to due date
3334
        # Checkouts with auto-renewing fall back to due date
3330
        my $soonestrenewal = dt_from_string( $checkout->date_due );
3335
        my $soonestrenewal = dt_from_string( $issue->date_due );
3331
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
3336
        if ( C4::Context->preference('NoRenewalBeforePrecision') eq 'date'
3332
            and $issuing_rule->{lengthunit} eq 'days' )
3337
            and $issuing_rule->{lengthunit} eq 'days' )
3333
        {
3338
        {
Lines 3340-3353 sub GetSoonestRenewDate { Link Here
3340
3345
3341
=head2 GetLatestAutoRenewDate
3346
=head2 GetLatestAutoRenewDate
3342
3347
3343
  $NoAutoRenewalAfterThisDate = &GetLatestAutoRenewDate($borrowernumber, $itemnumber);
3348
  $NoAutoRenewalAfterThisDate = &GetLatestAutoRenewDate($patron, $issue);
3344
3349
3345
Find out the latest possible auto renew date of a borrowed item.
3350
Find out the latest possible auto renew date of a borrowed item.
3346
3351
3347
C<$borrowernumber> is the borrower number of the patron who currently
3352
C<$patron> is the patron who currently has the item on loan.
3348
has the item on loan.
3349
3353
3350
C<$itemnumber> is the number of the item to renew.
3354
C<$issue> is the item issue.
3351
3355
3352
C<$GetLatestAutoRenewDate> returns the DateTime of the latest possible
3356
C<$GetLatestAutoRenewDate> returns the DateTime of the latest possible
3353
auto renew date, based on the value "No auto renewal after" and the "No auto
3357
auto renew date, based on the value "No auto renewal after" and the "No auto
Lines 3358-3373 or item cannot be found. Link Here
3358
=cut
3362
=cut
3359
3363
3360
sub GetLatestAutoRenewDate {
3364
sub GetLatestAutoRenewDate {
3361
    my ( $borrowernumber, $itemnumber ) = @_;
3365
    my ( $patron, $issue ) = @_;
3362
3366
    return unless $issue;
3363
    my $dbh = C4::Context->dbh;
3367
    return unless $patron;
3364
3368
3365
    my $item      = Koha::Items->find($itemnumber)  or return;
3369
    my $item = $issue->item;
3366
    my $itemissue = $item->checkout                 or return;
3370
    return unless $item;
3367
3371
3368
    $borrowernumber ||= $itemissue->borrowernumber;
3372
    my $dbh = C4::Context->dbh;
3369
    my $patron = Koha::Patrons->find( $borrowernumber )
3370
      or return;
3371
3373
3372
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3374
    my $branchcode = _GetCircControlBranch( $item->unblessed, $patron->unblessed );
3373
    my $circulation_rules = Koha::CirculationRules->get_effective_rules(
3375
    my $circulation_rules = Koha::CirculationRules->get_effective_rules(
Lines 3392-3398 sub GetLatestAutoRenewDate { Link Here
3392
3394
3393
    my $maximum_renewal_date;
3395
    my $maximum_renewal_date;
3394
    if ( $circulation_rules->{no_auto_renewal_after} ) {
3396
    if ( $circulation_rules->{no_auto_renewal_after} ) {
3395
        $maximum_renewal_date = dt_from_string($itemissue->issuedate);
3397
        $maximum_renewal_date = dt_from_string($issue->issuedate);
3396
        $maximum_renewal_date->add(
3398
        $maximum_renewal_date->add(
3397
            $circulation_rules->{lengthunit} => $circulation_rules->{no_auto_renewal_after}
3399
            $circulation_rules->{lengthunit} => $circulation_rules->{no_auto_renewal_after}
3398
        );
3400
        );
Lines 3442-3454 sub GetIssuingCharges { Link Here
3442
3444
3443
    my $sth = $dbh->prepare($charge_query);
3445
    my $sth = $dbh->prepare($charge_query);
3444
    $sth->execute($itemnumber);
3446
    $sth->execute($itemnumber);
3447
    my $patron;
3445
    if ( my $item_data = $sth->fetchrow_hashref ) {
3448
    if ( my $item_data = $sth->fetchrow_hashref ) {
3446
        $item_type = $item_data->{itemtype};
3449
        $item_type = $item_data->{itemtype};
3447
        $charge    = $item_data->{rentalcharge};
3450
        $charge    = $item_data->{rentalcharge};
3448
        if ($charge) {
3451
        if ($charge) {
3449
            # FIXME This should follow CircControl
3452
            # FIXME This should follow CircControl
3450
            my $branch = C4::Context::mybranch();
3453
            my $branch = C4::Context::mybranch();
3451
            my $patron = Koha::Patrons->find( $borrowernumber );
3454
            $patron //= Koha::Patrons->find( $borrowernumber );
3452
            my $discount = Koha::CirculationRules->get_effective_rule({
3455
            my $discount = Koha::CirculationRules->get_effective_rule({
3453
                categorycode => $patron->categorycode,
3456
                categorycode => $patron->categorycode,
3454
                branchcode   => $branch,
3457
                branchcode   => $branch,
Lines 4385-4391 sub _CanBookBeAutoRenewed { Link Here
4385
        }
4388
        }
4386
    );
4389
    );
4387
4390
4388
    if ( $patron->category->effective_BlockExpiredPatronOpacActions and $patron->is_expired ) {
4391
    if ( $patron->is_expired && $patron->category->effective_BlockExpiredPatronOpacActions ) {
4389
        return 'auto_account_expired';
4392
        return 'auto_account_expired';
4390
    }
4393
    }
4391
4394
Lines 4421-4427 sub _CanBookBeAutoRenewed { Link Here
4421
        }
4424
        }
4422
    }
4425
    }
4423
4426
4424
    my $soonest = GetSoonestRenewDate($issue);
4427
    my $soonest = GetSoonestRenewDate($patron, $issue);
4425
    if ( $soonest > dt_from_string() )
4428
    if ( $soonest > dt_from_string() )
4426
    {
4429
    {
4427
        return ( "auto_too_soon", $soonest );
4430
        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 1163-1169 sub handle_fee_paid { Link Here
1163
        "on_reserve" => "On hold for another patron",
1163
        "on_reserve" => "On hold for another patron",
1164
        "patron_restricted" => "Patron is currently restricted",
1164
        "patron_restricted" => "Patron is currently restricted",
1165
        "item_denied_renewal" => "Item is not allowed renewal",
1165
        "item_denied_renewal" => "Item is not allowed renewal",
1166
        "onsite_checkout" => "Item is an onsite checkout"
1166
        "onsite_checkout" => "Item is an onsite checkout",
1167
        "item_issued_to_other_patron" => "Item already issued to other borrower"
1167
    };
1168
    };
1168
    my @success = ();
1169
    my @success = ();
1169
    my @fail = ();
1170
    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/CirculationRules.pm (-1 / +1 lines)
Lines 301-307 sub get_effective_rule_value { Link Here
301
      $categorycode // q{}, $branchcode // q{}, $itemtype // q{};
301
      $categorycode // q{}, $branchcode // q{}, $itemtype // q{};
302
302
303
    my $cached       = $memory_cache->get_from_cache($cache_key);
303
    my $cached       = $memory_cache->get_from_cache($cache_key);
304
    return $cached if $cached;
304
    return $cached if defined($cached);
305
305
306
    my $rule = $self->get_effective_rule($params);
306
    my $rule = $self->get_effective_rule($params);
307
307
(-)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 187-193 my $overdues_count = 0; Link Here
187
my @overdues;
187
my @overdues;
188
my @issuedat;
188
my @issuedat;
189
my $itemtypes = { map { $_->{itemtype} => $_ } @{ Koha::ItemTypes->search_with_localization->unblessed } };
189
my $itemtypes = { map { $_->{itemtype} => $_ } @{ Koha::ItemTypes->search_with_localization->unblessed } };
190
my $pending_checkouts = $patron->pending_checkouts->search({}, { order_by => [ { -desc => 'date_due' }, { -asc => 'issue_id' } ] });
190
my $pending_checkouts = $patron->pending_checkouts->search(
191
    {},
192
    {
193
        order_by => [ { -desc => 'date_due' }, { -asc => 'issue_id' } ],
194
        prefetch => 'item'
195
    }
196
);
191
my $are_renewable_items = 0;
197
my $are_renewable_items = 0;
192
if ( $pending_checkouts->count ) { # Useless test
198
if ( $pending_checkouts->count ) { # Useless test
193
    while ( my $c = $pending_checkouts->next ) {
199
    while ( my $c = $pending_checkouts->next ) {
Lines 220-226 if ( $pending_checkouts->count ) { # Useless test Link Here
220
        $issue->{rentalfines} = $rental_fines->total_outstanding;
226
        $issue->{rentalfines} = $rental_fines->total_outstanding;
221
227
222
        # check if item is renewable
228
        # check if item is renewable
223
        my ($status,$renewerror,$info) = CanBookBeRenewed( $borrowernumber, $issue->{'itemnumber'} );
229
        my ($status, $renewerror, $info) = CanBookBeRenewed( $patron, $c );
224
        (
230
        (
225
            $issue->{'renewcount'},
231
            $issue->{'renewcount'},
226
            $issue->{'renewsallowed'},
232
            $issue->{'renewsallowed'},
Lines 230-236 if ( $pending_checkouts->count ) { # Useless test Link Here
230
            $issue->{'unseenleft'}
236
            $issue->{'unseenleft'}
231
        ) = GetRenewCount($borrowernumber, $issue->{'itemnumber'});
237
        ) = GetRenewCount($borrowernumber, $issue->{'itemnumber'});
232
        ( $issue->{'renewalfee'}, $issue->{'renewalitemtype'} ) = GetIssuingCharges( $issue->{'itemnumber'}, $borrowernumber );
238
        ( $issue->{'renewalfee'}, $issue->{'renewalitemtype'} ) = GetIssuingCharges( $issue->{'itemnumber'}, $borrowernumber );
233
        $issue->{itemtype_object} = Koha::ItemTypes->find( Koha::Items->find( $issue->{itemnumber} )->effective_itemtype );
239
        $issue->{itemtype_object} = Koha::ItemTypes->find( $c->item->effective_itemtype );
234
        if($status && C4::Context->preference("OpacRenewalAllowed")){
240
        if($status && C4::Context->preference("OpacRenewalAllowed")){
235
            $are_renewable_items = 1;
241
            $are_renewable_items = 1;
236
            $issue->{'status'} = $status;
242
            $issue->{'status'} = $status;
Lines 248-253 if ( $pending_checkouts->count ) { # Useless test Link Here
248
            $issue->{'auto_too_late'}  = 1 if $renewerror eq 'auto_too_late';
254
            $issue->{'auto_too_late'}  = 1 if $renewerror eq 'auto_too_late';
249
            $issue->{'auto_too_much_oweing'}  = 1 if $renewerror eq 'auto_too_much_oweing';
255
            $issue->{'auto_too_much_oweing'}  = 1 if $renewerror eq 'auto_too_much_oweing';
250
            $issue->{'item_denied_renewal'}  = 1 if $renewerror eq 'item_denied_renewal';
256
            $issue->{'item_denied_renewal'}  = 1 if $renewerror eq 'item_denied_renewal';
257
            $issue->{'item_issued_to_other_patron'} = 1 if $renewerror eq 'item_issued_to_other_patron';
251
258
252
            if ( $renewerror eq 'too_soon' ) {
259
            if ( $renewerror eq 'too_soon' ) {
253
                $issue->{'too_soon'}         = 1;
260
                $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
1732
    my $issue = AddIssue( $borrower1, $item_1->barcode );
1733
1730
1734
    my ( $renewokay, $error ) = CanBookBeRenewed( $borrowernumber1, $item_1->itemnumber );
1731
    my ( $renewokay, $error ) = CanBookBeRenewed( $borrower1, $issue );
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 3966-3972 subtest 'Set waiting flag' => sub { Link Here
3966
    my $hold = Koha::Holds->find( $reserve_id );
3959
    my $hold = Koha::Holds->find( $reserve_id );
3967
    is( $hold->found, 'T', 'Hold is in transit' );
3960
    is( $hold->found, 'T', 'Hold is in transit' );
3968
3961
3969
    my ( $status ) = CheckReserves($item->itemnumber);
3962
    my ( $status ) = CheckReserves($item);
3970
    is( $status, 'Transferred', 'Hold is not waiting yet');
3963
    is( $status, 'Transferred', 'Hold is not waiting yet');
3971
3964
3972
    set_userenv( $library_2 );
3965
    set_userenv( $library_2 );
Lines 3975-3981 subtest 'Set waiting flag' => sub { Link Here
3975
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3968
    ModReserveAffect( $item->itemnumber, undef, $do_transfer, $reserve_id );
3976
    $hold = Koha::Holds->find( $reserve_id );
3969
    $hold = Koha::Holds->find( $reserve_id );
3977
    is( $hold->found, 'W', 'Hold is waiting' );
3970
    is( $hold->found, 'W', 'Hold is waiting' );
3978
    ( $status ) = CheckReserves($item->itemnumber);
3971
    ( $status ) = CheckReserves($item);
3979
    is( $status, 'Waiting', 'Now the hold is waiting');
3972
    is( $status, 'Waiting', 'Now the hold is waiting');
3980
3973
3981
    #Bug 21944 - Waiting transfer checked in at branch other than pickup location
3974
    #Bug 21944 - Waiting transfer checked in at branch other than pickup location
Lines 4160-4173 subtest 'ItemsDeniedRenewal rules are checked' => sub { Link Here
4160
    my $mock_item_class = Test::MockModule->new("Koha::Item");
4153
    my $mock_item_class = Test::MockModule->new("Koha::Item");
4161
    $mock_item_class->mock( 'is_denied_renewal', sub { return 1; } );
4154
    $mock_item_class->mock( 'is_denied_renewal', sub { return 1; } );
4162
4155
4163
    my ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower->borrowernumber, $issue->itemnumber );
4156
    my ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower, $issue );
4164
    is( $mayrenew, 0, 'Renewal blocked when $item->is_denied_renewal returns true' );
4157
    is( $mayrenew, 0, 'Renewal blocked when $item->is_denied_renewal returns true' );
4165
    is( $error, 'item_denied_renewal', 'Renewal blocked when $item->is_denied_renewal returns true' );
4158
    is( $error, 'item_denied_renewal', 'Renewal blocked when $item->is_denied_renewal returns true' );
4166
4159
4167
    $mock_item_class->unmock( 'is_denied_renewal' );
4160
    $mock_item_class->unmock( 'is_denied_renewal' );
4168
    $mock_item_class->mock( 'is_denied_renewal', sub { return 0; } );
4161
    $mock_item_class->mock( 'is_denied_renewal', sub { return 0; } );
4169
4162
4170
    ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower->borrowernumber, $issue->itemnumber );
4163
    ( $mayrenew, $error ) = CanBookBeRenewed( $idr_borrower, $issue );
4171
    is( $mayrenew, 1, 'Renewal allowed when $item->is_denied_renewal returns false' );
4164
    is( $mayrenew, 1, 'Renewal allowed when $item->is_denied_renewal returns false' );
4172
    is( $error, undef, 'Renewal allowed when $item->is_denied_renewal returns false' );
4165
    is( $error, undef, 'Renewal allowed when $item->is_denied_renewal returns false' );
4173
4166
Lines 5654-5660 subtest "GetSoonestRenewDate tests" => sub { Link Here
5654
    # Test 'exact time' setting for syspref NoRenewalBeforePrecision
5647
    # Test 'exact time' setting for syspref NoRenewalBeforePrecision
5655
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact_time' );
5648
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact_time' );
5656
    is(
5649
    is(
5657
        GetSoonestRenewDate( $issue ),
5650
        GetSoonestRenewDate( $patron, $issue ),
5658
        $datedue->clone->add( days => -7 ),
5651
        $datedue->clone->add( days => -7 ),
5659
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5652
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5660
    );
5653
    );
Lines 5663-5669 subtest "GetSoonestRenewDate tests" => sub { Link Here
5663
    # Test 'date' setting for syspref NoRenewalBeforePrecision
5656
    # Test 'date' setting for syspref NoRenewalBeforePrecision
5664
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5657
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5665
    is(
5658
    is(
5666
        GetSoonestRenewDate( $issue ),
5659
        GetSoonestRenewDate( $patron, $issue ),
5667
        $datedue->clone->add( days => -7 )->truncate( to => 'day' ),
5660
        $datedue->clone->add( days => -7 )->truncate( to => 'day' ),
5668
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5661
        'Bug 14395: Renewals permitted 7 days before due date, as expected'
5669
    );
5662
    );
Lines 5680-5686 subtest "GetSoonestRenewDate tests" => sub { Link Here
5680
    );
5673
    );
5681
5674
5682
    is(
5675
    is(
5683
        GetSoonestRenewDate( $issue ),
5676
        GetSoonestRenewDate( $patron, $issue ),
5684
        dt_from_string,
5677
        dt_from_string,
5685
        'Checkouts without auto-renewal can be renewed immediately if no norenewalbefore'
5678
        'Checkouts without auto-renewal can be renewed immediately if no norenewalbefore'
5686
    );
5679
    );
Lines 5688-5700 subtest "GetSoonestRenewDate tests" => sub { Link Here
5688
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5681
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'date' );
5689
    $issue->auto_renew(1)->store;
5682
    $issue->auto_renew(1)->store;
5690
    is(
5683
    is(
5691
        GetSoonestRenewDate( $issue ),
5684
        GetSoonestRenewDate( $patron, $issue ),
5692
        $datedue->clone->truncate( to => 'day' ),
5685
        $datedue->clone->truncate( to => 'day' ),
5693
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5686
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5694
    );
5687
    );
5695
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact' );
5688
    t::lib::Mocks::mock_preference( 'NoRenewalBeforePrecision', 'exact' );
5696
    is(
5689
    is(
5697
        GetSoonestRenewDate( $issue ),
5690
        GetSoonestRenewDate( $patron, $issue ),
5698
        $datedue,
5691
        $datedue,
5699
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5692
        'Checkouts with auto-renewal can be renewed earliest on due date if no renewalbefore'
5700
    );
5693
    );
Lines 5707-5713 subtest "CanBookBeIssued + needsconfirmation message" => sub { Link Here
5707
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
5700
    my $library = $builder->build_object( { class => 'Koha::Libraries' } );
5708
    my $biblio = $builder->build_object({ class => 'Koha::Biblios' });
5701
    my $biblio = $builder->build_object({ class => 'Koha::Biblios' });
5709
    my $biblioitem = $builder->build_object({ class => 'Koha::Biblioitems', value => { biblionumber => $biblio->biblionumber }});
5702
    my $biblioitem = $builder->build_object({ class => 'Koha::Biblioitems', value => { biblionumber => $biblio->biblionumber }});
5710
    my $item = $builder->build_object({ class => 'Koha::Items' , value => { biblionumber => $biblio->biblionumber }});
5703
    my $item = $builder->build_object({ class => 'Koha::Items' , value => { itype => $itemtype, biblionumber => $biblio->biblionumber }});
5711
5704
5712
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
5705
    my $hold = $builder->build_object({ class => 'Koha::Holds', value => {
5713
        biblionumber => $item->biblionumber,
5706
        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 1225-1231 subtest 'CheckReserves additional tests' => sub { Link Here
1225
    ModReserveAffect( $item->itemnumber, $reserve1->borrowernumber, 1,
1222
    ModReserveAffect( $item->itemnumber, $reserve1->borrowernumber, 1,
1226
        $reserve1->reserve_id );
1223
        $reserve1->reserve_id );
1227
    my ( $status, $matched_reserve, $possible_reserves ) =
1224
    my ( $status, $matched_reserve, $possible_reserves ) =
1228
      CheckReserves( $item->itemnumber );
1225
      CheckReserves( $item );
1229
1226
1230
    is( $status, 'Transferred', "We found a reserve" );
1227
    is( $status, 'Transferred', "We found a reserve" );
1231
    is( $matched_reserve->{reserve_id},
1228
    is( $matched_reserve->{reserve_id},
Lines 1268-1274 subtest 'CheckReserves additional tests' => sub { Link Here
1268
1265
1269
    ok( $reserve_id, "We can place a record level hold because one item is owned by patron's home library");
1266
    ok( $reserve_id, "We can place a record level hold because one item is owned by patron's home library");
1270
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
1267
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'ItemHomeLibrary');
1271
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A->itemnumber );
1268
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A );
1272
    is( $status, "", "We do not fill the hold with item A because it is not from the patron's homebranch");
1269
    is( $status, "", "We do not fill the hold with item A because it is not from the patron's homebranch");
1273
    Koha::CirculationRules->set_rule({
1270
    Koha::CirculationRules->set_rule({
1274
        branchcode => $item_A->homebranch,
1271
        branchcode => $item_A->homebranch,
Lines 1276-1288 subtest 'CheckReserves additional tests' => sub { Link Here
1276
        rule_name  => 'holdallowed',
1273
        rule_name  => 'holdallowed',
1277
        rule_value => 'from_any_library'
1274
        rule_value => 'from_any_library'
1278
    });
1275
    });
1279
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A->itemnumber );
1276
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A );
1280
    is( $status, "Reserved", "We fill the hold with item A because item's branch rule says allow any");
1277
    is( $status, "Reserved", "We fill the hold with item A because item's branch rule says allow any");
1281
1278
1282
1279
1283
    # Changing the control branch should change only the rule we get
1280
    # Changing the control branch should change only the rule we get
1284
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
1281
    t::lib::Mocks::mock_preference('ReservesControlBranch', 'PatronLibrary');
1285
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A->itemnumber );
1282
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A );
1286
    is( $status, "", "We do not fill the hold with item A because it is not from the patron's homebranch");
1283
    is( $status, "", "We do not fill the hold with item A because it is not from the patron's homebranch");
1287
    Koha::CirculationRules->set_rule({
1284
    Koha::CirculationRules->set_rule({
1288
        branchcode   => $patron_B->branchcode,
1285
        branchcode   => $patron_B->branchcode,
Lines 1290-1296 subtest 'CheckReserves additional tests' => sub { Link Here
1290
        rule_name  => 'holdallowed',
1287
        rule_name  => 'holdallowed',
1291
        rule_value => 'from_any_library'
1288
        rule_value => 'from_any_library'
1292
    });
1289
    });
1293
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A->itemnumber );
1290
    ( $status, $matched_reserve, $possible_reserves ) = CheckReserves( $item_A );
1294
    is( $status, "Reserved", "We fill the hold with item A because patron's branch rule says allow any");
1291
    is( $status, "Reserved", "We fill the hold with item A because patron's branch rule says allow any");
1295
1292
1296
};
1293
};
1297
- 

Return to bug 31735