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

(-)a/C4/Circulation.pm (-7 / +6 lines)
Lines 841-847 sub CanBookBeIssued { Link Here
841
        $issuingimpossible{DEBARRED} = 1;
841
        $issuingimpossible{DEBARRED} = 1;
842
    }
842
    }
843
843
844
    if ( $patron->is_expired ) {
844
    if ( $patron->is_expired({ cache => 1 }) ) {
845
        $issuingimpossible{EXPIRED} = 1;
845
        $issuingimpossible{EXPIRED} = 1;
846
    }
846
    }
847
847
Lines 927-933 sub CanBookBeIssued { Link Here
927
        else {
927
        else {
928
            $issuingimpossible{USERBLOCKEDWITHENDDATE} = $debarred_date;
928
            $issuingimpossible{USERBLOCKEDWITHENDDATE} = $debarred_date;
929
        }
929
        }
930
    } elsif ( my $num_overdues = $patron->has_overdues ) {
930
    } elsif ( my $num_overdues = $patron->has_overdues({ cache => 1 }) ) {
931
        ## patron has outstanding overdue loans
931
        ## patron has outstanding overdue loans
932
        if ( C4::Context->preference("OverduesBlockCirc") eq 'block'){
932
        if ( C4::Context->preference("OverduesBlockCirc") eq 'block'){
933
            $issuingimpossible{USERBLOCKEDOVERDUE} = $num_overdues;
933
            $issuingimpossible{USERBLOCKEDOVERDUE} = $num_overdues;
Lines 1737-1743 sub AddIssue { Link Here
1737
                if ( $accumulate_charge > 0 ) {
1737
                if ( $accumulate_charge > 0 ) {
1738
                    AddIssuingCharge( $issue, $accumulate_charge, 'RENT_DAILY' );
1738
                    AddIssuingCharge( $issue, $accumulate_charge, 'RENT_DAILY' );
1739
                    $charge += $accumulate_charge;
1739
                    $charge += $accumulate_charge;
1740
                    $item_unblessed->{charge} = $charge;
1741
                }
1740
                }
1742
            }
1741
            }
1743
1742
Lines 2542-2548 sub MarkIssueReturned { Link Here
2542
        # Remove any OVERDUES related debarment if the borrower has no overdues
2541
        # Remove any OVERDUES related debarment if the borrower has no overdues
2543
        if ( C4::Context->preference('AutoRemoveOverduesRestrictions')
2542
        if ( C4::Context->preference('AutoRemoveOverduesRestrictions')
2544
          && $patron->debarred
2543
          && $patron->debarred
2545
          && !$patron->has_overdues
2544
          && !$patron->has_overdues({ cache => 1 })
2546
          && @{ GetDebarments({ borrowernumber => $borrowernumber, type => 'OVERDUES' }) }
2545
          && @{ GetDebarments({ borrowernumber => $borrowernumber, type => 'OVERDUES' }) }
2547
        ) {
2546
        ) {
2548
            DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
2547
            DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
Lines 2898-2904 sub CanBookBeRenewed { Link Here
2898
        my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
2897
        my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
2899
        $patron         = Koha::Patrons->find($borrowernumber); # FIXME Is this really useful?
2898
        $patron         = Koha::Patrons->find($borrowernumber); # FIXME Is this really useful?
2900
        my $restricted  = $patron->is_debarred;
2899
        my $restricted  = $patron->is_debarred;
2901
        my $hasoverdues = $patron->has_overdues;
2900
        my $hasoverdues = $patron->has_overdues({ cache => 1 });
2902
2901
2903
        if ( $restricted and $restrictionblockrenewing ) {
2902
        if ( $restricted and $restrictionblockrenewing ) {
2904
            return ( 0, 'restriction');
2903
            return ( 0, 'restriction');
Lines 3173-3179 sub AddRenewal { Link Here
3173
        # Remove any OVERDUES related debarment if the borrower has no overdues
3172
        # Remove any OVERDUES related debarment if the borrower has no overdues
3174
        if ( $patron
3173
        if ( $patron
3175
          && $patron->is_debarred
3174
          && $patron->is_debarred
3176
          && ! $patron->has_overdues
3175
          && ! $patron->has_overdues({ cache => 1 })
3177
          && @{ GetDebarments({ borrowernumber => $borrowernumber, type => 'OVERDUES' }) }
3176
          && @{ GetDebarments({ borrowernumber => $borrowernumber, type => 'OVERDUES' }) }
3178
        ) {
3177
        ) {
3179
            DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
3178
            DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
Lines 4385-4391 sub _CanBookBeAutoRenewed { Link Here
4385
        }
4384
        }
4386
    );
4385
    );
4387
4386
4388
    if ( $patron->category->effective_BlockExpiredPatronOpacActions and $patron->is_expired ) {
4387
    if ( $patron->is_expired({ cache => 1 }) && $patron->category->effective_BlockExpiredPatronOpacActions ) {
4389
        return 'auto_account_expired';
4388
        return 'auto_account_expired';
4390
    }
4389
    }
4391
4390
(-)a/Koha/Patron.pm (-7 / +71 lines)
Lines 762-767 sub is_debarred { Link Here
762
    return;
762
    return;
763
}
763
}
764
764
765
=head3 dateexpiry
766
767
Override Patron::dateexpiry to invalidate Patron::is_expired cache.
768
769
=cut
770
771
sub dateexpiry {
772
    my $self = shift @_;
773
    if (@_) {
774
        my $cache = Koha::Cache::Memory::Lite->get_instance;
775
        my $cache_key = 'Patron_is_expired:' . $self->borrowernumber;
776
        $cache->clear_from_cache($cache_key);
777
    }
778
    return $self->SUPER::dateexpiry(@_);
779
}
780
781
=head3 set
782
783
Override Patron::set to invalidate Patron::is_expired cache if dateexpiry is set.
784
785
=cut
786
787
sub set {
788
    my $self = shift @_;
789
    my ($properties) = @_;
790
    if (exists $properties->{dateexpiry}) {
791
        my $cache = Koha::Cache::Memory::Lite->get_instance;
792
        my $cache_key = 'Patron_is_expired:' . $self->borrowernumber;
793
        $cache->clear_from_cache($cache_key);
794
    }
795
    return $self->SUPER::set(@_);
796
}
797
765
=head3 is_expired
798
=head3 is_expired
766
799
767
my $is_expired = $patron->is_expired;
800
my $is_expired = $patron->is_expired;
Lines 771-781 Returns 1 if the patron is expired or 0; Link Here
771
=cut
804
=cut
772
805
773
sub is_expired {
806
sub is_expired {
774
    my ($self) = @_;
807
    my ($self, $params) = @_;
775
    return 0 unless $self->dateexpiry;
808
    $params //= {};
776
    return 0 if $self->dateexpiry =~ '^9999';
809
    my $cache = Koha::Cache::Memory::Lite->get_instance;
777
    return 1 if dt_from_string( $self->dateexpiry ) < dt_from_string->truncate( to => 'day' );
810
    my $cache_key = 'Patron_is_expired:' . $self->borrowernumber;
778
    return 0;
811
812
    if ($params->{cache}) {
813
        my $is_expired = $cache->get_from_cache($cache_key);
814
        return $is_expired if defined $is_expired;
815
    }
816
    my $is_expired =
817
        $self->dateexpiry &&
818
        $self->dateexpiry !~ '^9999' &&
819
        dt_from_string( $self->dateexpiry ) < dt_from_string->truncate( to => 'day' );
820
    $is_expired = $is_expired ? 1 : 0;
821
    if ($params->{cache}) {
822
        $cache->set_in_cache($cache_key, $is_expired)
823
    }
824
    else {
825
        $cache->clear_from_cache($cache_key);
826
    }
827
    return $is_expired;
779
}
828
}
780
829
781
=head3 password_expired
830
=head3 password_expired
Lines 979-987 Returns the number of patron's overdues Link Here
979
=cut
1028
=cut
980
1029
981
sub has_overdues {
1030
sub has_overdues {
982
    my ($self) = @_;
1031
    my ($self, $params) = @_;
1032
    $params //= {};
1033
    my $cache = Koha::Cache::Memory::Lite->get_instance;
1034
    my $cache_key = 'Patron_has_overdues:' . $self->borrowernumber;
1035
1036
    if ($params->{cache}) {
1037
        my $has_overdues = $cache->get_from_cache($cache_key);
1038
        return $has_overdues if defined $has_overdues;
1039
    }
983
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
1040
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
984
    return $self->_result->issues->search({ date_due => { '<' => $dtf->format_datetime( dt_from_string() ) } })->count;
1041
    my $has_overdues = $self->_result->issues->search({ date_due => { '<' => $dtf->format_datetime( dt_from_string() ) } })->count;
1042
    if ($params->{cache}) {
1043
        $cache->set_in_cache($cache_key, $has_overdues);
1044
    }
1045
    else {
1046
        $cache->clear_from_cache($cache_key);
1047
    }
1048
    return $has_overdues;
985
}
1049
}
986
1050
987
=head3 track_login
1051
=head3 track_login
(-)a/t/db_dependent/Koha/Patrons.t (-7 / +55 lines)
Lines 264-270 subtest 'siblings' => sub { Link Here
264
};
264
};
265
265
266
subtest 'has_overdues' => sub {
266
subtest 'has_overdues' => sub {
267
    plan tests => 3;
267
    plan tests => 12;
268
268
269
    my $item_1 = $builder->build_sample_item;
269
    my $item_1 = $builder->build_sample_item;
270
    my $retrieved_patron = Koha::Patrons->find( $new_patron_1->borrowernumber );
270
    my $retrieved_patron = Koha::Patrons->find( $new_patron_1->borrowernumber );
Lines 273-298 subtest 'has_overdues' => sub { Link Here
273
    my $tomorrow = DateTime->today( time_zone => C4::Context->tz() )->add( days => 1 );
273
    my $tomorrow = DateTime->today( time_zone => C4::Context->tz() )->add( days => 1 );
274
    my $issue = Koha::Checkout->new({ borrowernumber => $new_patron_1->id, itemnumber => $item_1->itemnumber, date_due => $tomorrow, branchcode => $library->{branchcode} })->store();
274
    my $issue = Koha::Checkout->new({ borrowernumber => $new_patron_1->id, itemnumber => $item_1->itemnumber, date_due => $tomorrow, branchcode => $library->{branchcode} })->store();
275
    is( $retrieved_patron->has_overdues, 0, );
275
    is( $retrieved_patron->has_overdues, 0, );
276
277
    my $cache_key = 'Patron_has_overdues:' . $retrieved_patron->borrowernumber;
278
    my $cache = Koha::Cache::Memory::Lite->get_instance;
279
280
    # Cache is set
281
    is( $retrieved_patron->has_overdues({ cache => 1}), 0, );
282
    is ( $cache->get_from_cache($cache_key), 0, 'has_overdues cache has been set');
283
    # Cache is used
284
    is( $retrieved_patron->has_overdues({ cache => 1}), 0, );
285
276
    $issue->delete();
286
    $issue->delete();
277
    my $yesterday = DateTime->today(time_zone => C4::Context->tz())->add( days => -1 );
287
    my $yesterday = DateTime->today(time_zone => C4::Context->tz())->add( days => -1 );
278
    $issue = Koha::Checkout->new({ borrowernumber => $new_patron_1->id, itemnumber => $item_1->itemnumber, date_due => $yesterday, branchcode => $library->{branchcode} })->store();
288
    $issue = Koha::Checkout->new({ borrowernumber => $new_patron_1->id, itemnumber => $item_1->itemnumber, date_due => $yesterday, branchcode => $library->{branchcode} })->store();
279
    $retrieved_patron = Koha::Patrons->find( $new_patron_1->borrowernumber );
289
    $retrieved_patron = Koha::Patrons->find( $new_patron_1->borrowernumber );
280
    is( $retrieved_patron->has_overdues, 1, );
290
    is( $retrieved_patron->has_overdues, 1, );
291
    is( $cache->get_from_cache($cache_key), undef, 'has_overdues cache has been invalidated' );
292
    # Cache is set
293
    is( $retrieved_patron->has_overdues({ cache => 1}), 1, );
294
    is ( $cache->get_from_cache($cache_key), 1, 'has_overdues cache has been set' );
295
    # Cache is used
296
    is( $retrieved_patron->has_overdues({ cache => 1}), 1, );
297
281
    $issue->delete();
298
    $issue->delete();
299
300
    # Cache is used (with stale entry, flushing cache must be handled manually as automatic invalidation is
301
    # complex and probably not worth the effort)
302
    is( $retrieved_patron->has_overdues({ cache => 1}), 1, );
303
304
    # Cache has been invalidated
305
    is( $retrieved_patron->has_overdues, 0, );
282
};
306
};
283
307
284
subtest 'is_expired' => sub {
308
subtest 'is_expired' => sub {
285
    plan tests => 4;
309
    plan tests => 14;
286
    my $patron = $builder->build({ source => 'Borrower' });
310
    my $patron = $builder->build({ source => 'Borrower' });
287
    $patron = Koha::Patrons->find( $patron->{borrowernumber} );
311
    $patron = Koha::Patrons->find( $patron->{borrowernumber} );
288
    $patron->dateexpiry( undef )->store->discard_changes;
312
    $patron->dateexpiry( undef )->store->discard_changes;
289
    is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is not set');
313
    is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is not set' );
290
    $patron->dateexpiry( dt_from_string )->store->discard_changes;
314
    $patron->dateexpiry( dt_from_string )->store->discard_changes;
291
    is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is today');
315
    is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is today' );
292
    $patron->dateexpiry( dt_from_string->add( days => 1 ) )->store->discard_changes;
316
    $patron->dateexpiry( dt_from_string->add( days => 1 ) )->store->discard_changes;
293
    is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is tomorrow');
317
    is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is tomorrow' );
318
    $patron->dateexpiry( dt_from_string->add( days => -1 ) )->store->discard_changes;
319
    is( $patron->is_expired, 1, 'Patron should be considered expired if dateexpiry is yesterday' );
320
321
322
    my $cache_key = 'Patron_is_expired:' . $patron->borrowernumber;
323
    my $cache = Koha::Cache::Memory::Lite->get_instance;
324
    # Test is_expired cache
325
    $patron->dateexpiry( undef )->store->discard_changes;
326
    # Set cache
327
    is( $patron->is_expired({ cache => 1 }), 0, 'Patron should not be considered expired if dateexpiry is not set, with caching enabled' );
328
    is( $cache->get_from_cache($cache_key), 0, 'is_expired cache has been set');
329
    is( $patron->is_expired({ cache => 1 }), 0, 'Patron should not be considered expired if dateexpiry is not set, with caching enabled and cache hit' );
294
    $patron->dateexpiry( dt_from_string->add( days => -1 ) )->store->discard_changes;
330
    $patron->dateexpiry( dt_from_string->add( days => -1 ) )->store->discard_changes;
295
    is( $patron->is_expired, 1, 'Patron should be considered expired if dateexpiry is yesterday');
331
    is( $patron->is_expired({ cache => 1 }), 1, 'Patron should be considered expired if dateexpiry is yesterday, cache has been invalidated' );
332
    is( $cache->get_from_cache($cache_key), 1, 'is_expired cache has been set');
333
    is( $patron->is_expired({ cache => 1 }), 1, 'Patron should be considered expired if dateexpiry is yesterday, on cache hit' );
334
335
    $patron->{dateexpiry} = undef;
336
    # Checking cache is really utilized by setting dateexpiry property without using accessor method
337
    is( $patron->is_expired({ cache => 1 }), 1, 'Cache is used with stale value' );
338
339
    $patron->set({ dateexpiry => undef })->store->discard_changes;
340
    is( $patron->is_expired({ cache => 1 }), 0, 'Patron should not be considered expired if dateexpiry is not set, cache has been invalidated' );
341
    is( $patron->is_expired({ cache => 1 }), 0, 'Patron should not be considered expired if dateexpiry is not set, on cache hit' );
342
343
    $patron->is_expired;
344
    is( $cache->get_from_cache($cache_key), undef , 'Cache has been invalidated after calling is_expired without caching enabled' );
296
345
297
    $patron->delete;
346
    $patron->delete;
298
};
347
};
299
- 

Return to bug 32476