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 2561-2567 sub MarkIssueReturned { Link Here
2561
        my $overdue_restrictions = $patron->restrictions->search({ type => 'OVERDUES' });
2560
        my $overdue_restrictions = $patron->restrictions->search({ type => 'OVERDUES' });
2562
        if ( C4::Context->preference('AutoRemoveOverduesRestrictions')
2561
        if ( C4::Context->preference('AutoRemoveOverduesRestrictions')
2563
          && $patron->debarred
2562
          && $patron->debarred
2564
          && !$patron->has_overdues
2563
          && !$patron->has_overdues({ cache => 1 })
2565
          && $overdue_restrictions->count
2564
          && $overdue_restrictions->count
2566
        ) {
2565
        ) {
2567
            DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
2566
            DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
Lines 2918-2924 sub CanBookBeRenewed { Link Here
2918
        my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
2917
        my $restrictionblockrenewing = C4::Context->preference('RestrictionBlockRenewing');
2919
        $patron         = Koha::Patrons->find($borrowernumber); # FIXME Is this really useful?
2918
        $patron         = Koha::Patrons->find($borrowernumber); # FIXME Is this really useful?
2920
        my $restricted  = $patron->is_debarred;
2919
        my $restricted  = $patron->is_debarred;
2921
        my $hasoverdues = $patron->has_overdues;
2920
        my $hasoverdues = $patron->has_overdues({ cache => 1 });
2922
2921
2923
        if ( $restricted and $restrictionblockrenewing ) {
2922
        if ( $restricted and $restrictionblockrenewing ) {
2924
            return ( 0, 'restriction');
2923
            return ( 0, 'restriction');
Lines 3199-3205 sub AddRenewal { Link Here
3199
        my $overdue_restrictions = $patron->restrictions->search({ type => 'OVERDUES' });
3198
        my $overdue_restrictions = $patron->restrictions->search({ type => 'OVERDUES' });
3200
        if ( $patron
3199
        if ( $patron
3201
          && $patron->is_debarred
3200
          && $patron->is_debarred
3202
          && ! $patron->has_overdues
3201
          && !$patron->has_overdues({ cache => 1 })
3203
          && $overdue_restrictions->count
3202
          && $overdue_restrictions->count
3204
        ) {
3203
        ) {
3205
            DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
3204
            DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' });
Lines 4412-4418 sub _CanBookBeAutoRenewed { Link Here
4412
        }
4411
        }
4413
    );
4412
    );
4414
4413
4415
    if ( $patron->category->effective_BlockExpiredPatronOpacActions and $patron->is_expired ) {
4414
    if ( $patron->is_expired({ cache => 1 }) && $patron->category->effective_BlockExpiredPatronOpacActions ) {
4416
        return 'auto_account_expired';
4415
        return 'auto_account_expired';
4417
    }
4416
    }
4418
4417
(-)a/Koha/Object.pm (+59 lines)
Lines 80-85 sub new { Link Here
80
    }
80
    }
81
81
82
    $self->{_messages} = [];
82
    $self->{_messages} = [];
83
    $self->{_cache} = {};
83
84
84
    croak("No _type found! Koha::Object must be subclassed!")
85
    croak("No _type found! Koha::Object must be subclassed!")
85
      unless $class->_type();
86
      unless $class->_type();
Lines 88-93 sub new { Link Here
88
89
89
}
90
}
90
91
92
=head3 Koha::Object->_cache_get();
93
94
my $value = Koha::Object->_cache_get($cache_key);
95
96
=cut
97
98
sub _cache_get {
99
    my ($self, $key) = @_;
100
    return $self->{_cache}->{$key};
101
}
102
103
=head3 Koha::Object->_cache_set();
104
105
Koha::Object->_cache_set($cache_key, $value);
106
107
=cut
108
109
sub _cache_set {
110
    my ($self, $key, $value) = @_;
111
    $self->{_cache}->{$key} = $value;
112
}
113
114
=head3 Koha::Object->_cache_clear($cache_key);
115
116
Koha::Object->_cache_clear($cache_key);
117
Koha::Object->_cache_clear();
118
119
=cut
120
121
sub _cache_clear {
122
    my ($self, $key) = @_;
123
    if (defined $key) {
124
        delete $self->{_cache}->{$key};
125
    }
126
    else {
127
        $self->{_cache} = {};
128
    }
129
}
130
131
=head3 Koha::Object->_accessor_cache($method_name);
132
133
my $value = Koha::Object->_accessor_cache($method_name);
134
135
=cut
136
137
sub _accessor_cache {
138
    my ($self, $method_name) = @_;
139
140
    my $value = $self->_cache_get($method_name);
141
142
    return $value if defined $value;
143
144
    $value = $self->$method_name();
145
    $self->_cache_set($method_name, $value);
146
147
    return $value;
148
}
149
91
=head3 Koha::Object->_new_from_dbic();
150
=head3 Koha::Object->_new_from_dbic();
92
151
93
my $object = Koha::Object->_new_from_dbic($dbic_row);
152
my $object = Koha::Object->_new_from_dbic($dbic_row);
(-)a/Koha/Patron.pm (-6 / +44 lines)
Lines 763-782 sub is_debarred { Link Here
763
    return;
763
    return;
764
}
764
}
765
765
766
=head3 dateexpiry
767
768
Override Patron::dateexpiry to invalidate Patron::is_expired cache.
769
770
=cut
771
772
sub dateexpiry {
773
    my $self = shift @_;
774
    if (@_) {
775
        $self->_cache_clear('is_expired');
776
    }
777
    return $self->SUPER::dateexpiry(@_);
778
}
779
780
=head3 set
781
782
Override Patron::set to invalidate Patron::is_expired cache if dateexpiry is set.
783
784
=cut
785
786
sub set {
787
    my $self = shift @_;
788
    my ($properties) = @_;
789
    if (exists $properties->{dateexpiry}) {
790
        $self->_cache_clear('is_expired');
791
    }
792
    return $self->SUPER::set(@_);
793
}
794
766
=head3 is_expired
795
=head3 is_expired
767
796
768
my $is_expired = $patron->is_expired;
797
my $is_expired = $patron->is_expired;
798
my $is_expired = $patron->is_expired({ cache => 1});
769
799
770
Returns 1 if the patron is expired or 0;
800
Returns 1 if the patron is expired or 0;
771
801
772
=cut
802
=cut
773
803
774
sub is_expired {
804
sub is_expired {
775
    my ($self) = @_;
805
    my ($self, $params) = @_;
776
    return 0 unless $self->dateexpiry;
806
    $params //= {};
777
    return 0 if $self->dateexpiry =~ '^9999';
807
    return $self->_accessor_cache('is_expired') if $params->{cache};
778
    return 1 if dt_from_string( $self->dateexpiry ) < dt_from_string->truncate( to => 'day' );
808
779
    return 0;
809
    $self->_cache_clear('is_expired');
810
    return $self->dateexpiry &&
811
        $self->dateexpiry !~ '^9999' &&
812
        dt_from_string( $self->dateexpiry ) < dt_from_string->truncate( to => 'day' ) ? 1 : 0;
780
}
813
}
781
814
782
=head3 password_expired
815
=head3 password_expired
Lines 974-986 sub renew_account { Link Here
974
=head3 has_overdues
1007
=head3 has_overdues
975
1008
976
my $has_overdues = $patron->has_overdues;
1009
my $has_overdues = $patron->has_overdues;
1010
my $has_overdues = $patron->has_overdues({ cache => 1 });
977
1011
978
Returns the number of patron's overdues
1012
Returns the number of patron's overdues
979
1013
980
=cut
1014
=cut
981
1015
982
sub has_overdues {
1016
sub has_overdues {
983
    my ($self) = @_;
1017
    my ($self, $params) = @_;
1018
    $params //= {};
1019
    return $self->_accessor_cache('has_overdues') if $params->{cache};
1020
1021
    $self->_cache_clear('has_overdues');
984
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
1022
    my $dtf = Koha::Database->new->schema->storage->datetime_parser;
985
    return $self->_result->issues->search({ date_due => { '<' => $dtf->format_datetime( dt_from_string() ) } })->count;
1023
    return $self->_result->issues->search({ date_due => { '<' => $dtf->format_datetime( dt_from_string() ) } })->count;
986
}
1024
}
(-)a/t/db_dependent/Koha/Patrons.t (-7 / +50 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
    # Cache is set
278
    is( $retrieved_patron->has_overdues({ cache => 1}), 0, );
279
    is( $retrieved_patron->_cache_get('has_overdues'), 0, 'has_overdues cache has been set');
280
    # Cache is used
281
    is( $retrieved_patron->has_overdues({ cache => 1}), 0, );
282
276
    $issue->delete();
283
    $issue->delete();
277
    my $yesterday = DateTime->today(time_zone => C4::Context->tz())->add( days => -1 );
284
    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();
285
    $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 );
286
    $retrieved_patron = Koha::Patrons->find( $new_patron_1->borrowernumber );
280
    is( $retrieved_patron->has_overdues, 1, );
287
    is( $retrieved_patron->has_overdues, 1, );
288
    is( $retrieved_patron->_cache_get('has_overdues'),, undef, 'has_overdues cache has been invalidated' );
289
    # Cache is set
290
    is( $retrieved_patron->has_overdues({ cache => 1}), 1, );
291
    is ( $retrieved_patron->_cache_get('has_overdues'),, 1, 'has_overdues cache has been set' );
292
    # Cache is used
293
    is( $retrieved_patron->has_overdues({ cache => 1}), 1, );
294
281
    $issue->delete();
295
    $issue->delete();
296
297
    # Cache is used (with stale entry, flushing cache must be handled manually as automatic invalidation is
298
    # complex and probably not worth the effort)
299
    is( $retrieved_patron->has_overdues({ cache => 1}), 1, );
300
301
    # Cache has been invalidated
302
    is( $retrieved_patron->has_overdues, 0, );
282
};
303
};
283
304
284
subtest 'is_expired' => sub {
305
subtest 'is_expired' => sub {
285
    plan tests => 4;
306
    plan tests => 14;
286
    my $patron = $builder->build({ source => 'Borrower' });
307
    my $patron = $builder->build({ source => 'Borrower' });
287
    $patron = Koha::Patrons->find( $patron->{borrowernumber} );
308
    $patron = Koha::Patrons->find( $patron->{borrowernumber} );
288
    $patron->dateexpiry( undef )->store->discard_changes;
309
    $patron->dateexpiry( undef )->store->discard_changes;
289
    is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is not set');
310
    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;
311
    $patron->dateexpiry( dt_from_string )->store->discard_changes;
291
    is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is today');
312
    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;
313
    $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');
314
    is( $patron->is_expired, 0, 'Patron should not be considered expired if dateexpiry is tomorrow' );
294
    $patron->dateexpiry( dt_from_string->add( days => -1 ) )->store->discard_changes;
315
    $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');
316
    is( $patron->is_expired, 1, 'Patron should be considered expired if dateexpiry is yesterday' );
317
318
319
    # Test is_expired cache
320
    $patron->dateexpiry( undef )->store->discard_changes;
321
    # Set cache
322
    is( $patron->is_expired({ cache => 1 }), 0, 'Patron should not be considered expired if dateexpiry is not set, with caching enabled' );
323
    is( $patron->_cache_get('is_expired'), 0, 'is_expired cache has been set');
324
    is( $patron->is_expired({ cache => 1 }), 0, 'Patron should not be considered expired if dateexpiry is not set, with caching enabled and cache hit' );
325
    $patron->dateexpiry( dt_from_string->add( days => -1 ) )->store->discard_changes;
326
    is( $patron->is_expired({ cache => 1 }), 1, 'Patron should be considered expired if dateexpiry is yesterday, cache has been invalidated' );
327
    is( $patron->_cache_get('is_expired'), 1, 'is_expired cache has been set');
328
    is( $patron->is_expired({ cache => 1 }), 1, 'Patron should be considered expired if dateexpiry is yesterday, on cache hit' );
329
330
    $patron->{dateexpiry} = undef;
331
    # Checking cache is really utilized by setting dateexpiry property without using accessor method
332
    is( $patron->is_expired({ cache => 1 }), 1, 'Cache is used with stale value' );
333
334
    $patron->set({ dateexpiry => undef })->store->discard_changes;
335
    is( $patron->is_expired({ cache => 1 }), 0, 'Patron should not be considered expired if dateexpiry is not set, cache has been invalidated' );
336
    is( $patron->is_expired({ cache => 1 }), 0, 'Patron should not be considered expired if dateexpiry is not set, on cache hit' );
337
338
    $patron->is_expired;
339
    is( $patron->_cache_get('is_expired'), undef , 'Cache has been invalidated after calling is_expired without caching enabled' );
296
340
297
    $patron->delete;
341
    $patron->delete;
298
};
342
};
299
- 

Return to bug 32476