3 # Copyright 2014 ByWater Solutions
4 # Copyright 2016 Koha Development Team
6 # This file is part of Koha.
8 # Koha is free software; you can redistribute it and/or modify it under the
9 # terms of the GNU General Public License as published by the Free Software
10 # Foundation; either version 3 of the License, or (at your option) any later
13 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
14 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License along
18 # with Koha; if not, write to the Free Software Foundation, Inc.,
19 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 use Koha
::ArticleRequests
;
29 use Koha
::ArticleRequest
::Status
;
31 use Koha
::Exceptions
::Patron
;
33 use base
qw(Koha::Objects);
37 Koha::Patron - Koha Patron Object class
47 my $patrons = Koha::Patrons->search_limit( $params, $attributes );
49 Returns all the patrons the logged in user is allowed to see
54 my ( $self, $params, $attributes ) = @_;
56 my $userenv = C4
::Context
->userenv;
57 my @restricted_branchcodes;
58 if ( $userenv and $userenv->{number
} ) {
59 my $logged_in_user = Koha
::Patrons
->find( $userenv->{number
} );
60 @restricted_branchcodes = $logged_in_user->libraries_where_can_see_patrons;
62 $params->{'me.branchcode'} = { -in => \
@restricted_branchcodes } if @restricted_branchcodes;
63 return $self->search( $params, $attributes );
66 =head3 search_housebound_choosers
68 Returns all Patrons which are Housebound choosers.
72 sub search_housebound_choosers
{
74 my $cho = $self->_resultset
75 ->search_related('housebound_role', {
76 housebound_chooser
=> 1,
77 })->search_related('borrowernumber');
78 return Koha
::Patrons
->_new_from_dbic($cho);
81 =head3 search_housebound_deliverers
83 Returns all Patrons which are Housebound deliverers.
87 sub search_housebound_deliverers
{
89 my $del = $self->_resultset
90 ->search_related('housebound_role', {
91 housebound_deliverer
=> 1,
92 })->search_related('borrowernumber');
93 return Koha
::Patrons
->_new_from_dbic($del);
96 =head3 search_upcoming_membership_expires
98 my $patrons = Koha::Patrons->search_upcoming_membership_expires();
100 The 'before' and 'after' represent the number of days before/after the date
101 that is set by the preference MembershipExpiryDaysNotice.
102 If the pref is 14, before 2 and after 3 then you will get all expires
107 sub search_upcoming_membership_expires
{
108 my ( $self, $params ) = @_;
109 my $before = $params->{before
} || 0;
110 my $after = $params->{after
} || 0;
111 delete $params->{before
};
112 delete $params->{after
};
114 my $days = C4
::Context
->preference("MembershipExpiryDaysNotice") || 0;
115 my $date_before = dt_from_string
->add( days
=> $days - $before );
116 my $date_after = dt_from_string
->add( days
=> $days + $after );
117 my $dtf = Koha
::Database
->new->schema->storage->datetime_parser;
119 $params->{dateexpiry
} = {
120 ">=" => $dtf->format_date( $date_before ),
121 "<=" => $dtf->format_date( $date_after ),
123 return $self->SUPER::search
(
124 $params, { join => ['branchcode', 'categorycode'] }
128 =head3 search_patrons_to_anonymise
130 my $patrons = Koha::Patrons->search_patrons_to_anonymise( { before => $older_than_date, [ library => $library ] } );
132 This method returns all patrons who has an issue history older than a given date.
136 sub search_patrons_to_anonymise
{
137 my ( $class, $params ) = @_;
138 my $older_than_date = $params->{before
};
139 my $library = $params->{library
};
140 $older_than_date = $older_than_date ? dt_from_string
($older_than_date) : dt_from_string
;
142 ( C4
::Context
->preference('IndependentBranches') && C4
::Context
->userenv && !C4
::Context
->IsSuperLibrarian() && C4
::Context
->userenv->{branch
} )
143 ? C4
::Context
->userenv->{branch
}
145 my $anonymous_patron = C4
::Context
->preference('AnonymousPatron') || undef;
147 my $dtf = Koha
::Database
->new->schema->storage->datetime_parser;
148 my $rs = $class->_resultset->search(
149 { returndate
=> { '<' => $dtf->format_datetime($older_than_date), },
150 'old_issues.borrowernumber' => { 'not' => undef },
151 privacy
=> { '<>' => 0 }, # Keep forever
152 ( $library ?
( 'old_issues.branchcode' => $library ) : () ),
153 ( $anonymous_patron ?
( 'old_issues.borrowernumber' => { '!=' => $anonymous_patron } ) : () ),
155 { join => ["old_issues"],
159 return Koha
::Patrons
->_new_from_dbic($rs);
162 =head3 anonymise_issue_history
164 Koha::Patrons->search->anonymise_issue_history( { [ before => $older_than_date ] } );
166 Anonymise issue history (old_issues) for all patrons older than the given date (optional).
167 To make sure all the conditions are met, the caller has the responsibility to
168 call search_patrons_to_anonymise to filter the Koha::Patrons set
172 sub anonymise_issue_history
{
173 my ( $self, $params ) = @_;
175 my $older_than_date = $params->{before
};
177 $older_than_date = dt_from_string
$older_than_date if $older_than_date;
179 # The default of 0 does not work due to foreign key constraints
180 # The anonymisation should not fail quietly if AnonymousPatron is not a valid entry
181 # Set it to undef (NULL)
182 my $dtf = Koha
::Database
->new->schema->storage->datetime_parser;
184 while ( my $patron = $self->next ) {
185 my $old_issues_to_anonymise = $patron->old_checkouts->search(
190 { '<' => $dtf->format_datetime($older_than_date) } )
195 my $anonymous_patron = C4
::Context
->preference('AnonymousPatron') || undef;
196 $nb_rows += $old_issues_to_anonymise->update( { 'old_issues.borrowernumber' => $anonymous_patron } );
203 Koha::Patrons->search({ some filters here })->delete({ move => 1, verbose => 1 });
205 Delete passed set of patron objects.
206 Wrapper for Koha::Patron->delete. (We do not want to bypass Koha::Patron
207 and let DBIx do the job without further housekeeping.)
208 Includes a move to deletedborrowers if move flag set.
210 Just like DBIx, the delete will only succeed when all entries could be
211 deleted. Returns true or throws an exception.
216 my ( $self, $params ) = @_;
218 $self->_resultset->result_source->schema->txn_do( sub {
219 my ( $set, $params ) = @_;
220 my $count = $set->count;
221 while( my $patron = $set->next ) {
222 $patron->move_to_deleted if $params->{move
};
223 $patron->delete == 1 || Koha
::Exceptions
::Patron
::FailedDelete
->throw;
226 warn "Deleted $count patrons\n" if $params->{verbose
};
228 return $patrons_deleted;
231 =head3 search_unsubscribed
233 Koha::Patrons->search_unsubscribed;
235 Returns a set of Koha patron objects for patrons that recently
236 unsubscribed and are not locked (candidates for locking).
237 Depends on UnsubscribeReflectionDelay.
241 sub search_unsubscribed
{
244 my $delay = C4
::Context
->preference('UnsubscribeReflectionDelay');
245 if( !defined($delay) || $delay eq q{} ) {
247 return $class->search({ borrowernumber
=> undef });
249 my $parser = Koha
::Database
->new->schema->storage->datetime_parser;
250 my $dt = dt_from_string
()->subtract( days
=> $delay );
251 my $str = $parser->format_datetime($dt);
252 my $fails = C4
::Context
->preference('FailedLoginAttempts') || 0;
253 my $cond = [ undef, 0, 1..$fails-1 ]; # NULL, 0, 1..fails-1 (if fails>0)
254 return $class->search(
256 'patron_consents.refused_on' => { '<=' => $str },
257 'login_attempts' => $cond,
259 { join => 'patron_consents' },
263 =head3 search_anonymize_candidates
265 Koha::Patrons->search_anonymize_candidates({ locked => 1 });
267 Returns a set of Koha patron objects for patrons whose account is expired
268 and locked (if parameter set). These are candidates for anonymizing.
269 Depends on PatronAnonymizeDelay.
273 sub search_anonymize_candidates
{
274 my ( $class, $params ) = @_;
276 my $delay = C4
::Context
->preference('PatronAnonymizeDelay');
277 if( !defined($delay) || $delay eq q{} ) {
279 return $class->search({ borrowernumber
=> undef });
282 my $parser = Koha
::Database
->new->schema->storage->datetime_parser;
283 my $dt = dt_from_string
()->subtract( days
=> $delay );
284 my $str = $parser->format_datetime($dt);
285 $cond->{dateexpiry
} = { '<=' => $str };
286 $cond->{anonymized
} = 0; # not yet done
287 if( $params->{locked
} ) {
288 my $fails = C4
::Context
->preference('FailedLoginAttempts');
289 $cond->{login_attempts
} = [ -and => { '!=' => undef }, { -not_in
=> [0, 1..$fails-1 ] } ]; # -not_in does not like undef
291 return $class->search( $cond );
294 =head3 search_anonymized
296 Koha::Patrons->search_anonymized;
298 Returns a set of Koha patron objects for patron accounts that have been
299 anonymized before and could be removed.
300 Depends on PatronRemovalDelay.
304 sub search_anonymized
{
307 my $delay = C4
::Context
->preference('PatronRemovalDelay');
308 if( !defined($delay) || $delay eq q{} ) {
310 return $class->search({ borrowernumber
=> undef });
313 my $parser = Koha
::Database
->new->schema->storage->datetime_parser;
314 my $dt = dt_from_string
()->subtract( days
=> $delay );
315 my $str = $parser->format_datetime($dt);
316 $cond->{dateexpiry
} = { '<=' => $str };
317 $cond->{anonymized
} = 1;
318 return $class->search( $cond );
323 Koha::Patrons->search({ some filters })->lock({ expire => 1, remove => 1, verbose => 1 })
325 Lock the passed set of patron objects. Optionally expire and remove holds.
326 Optional verbose flag is used in cron job.
327 Wrapper around Koha::Patron->lock.
332 my ( $self, $params ) = @_;
333 my $count = $self->count;
334 while( my $patron = $self->next ) {
335 $patron->lock($params);
337 if( $params->{verbose
} ) {
338 warn "Locked $count patrons\n";
344 Koha::Patrons->search({ some filters })->anonymize({ verbose => 1 });
346 Anonymize passed set of patron objects.
347 Optional verbose flag is used in cron job.
348 Wrapper around Koha::Patron->anonymize.
353 my ( $self, $params ) = @_;
354 my $count = $self->count;
355 while( my $patron = $self->next ) {
358 if( $params->{verbose
} ) {
359 warn "Anonymized $count patrons\n";
376 return 'Koha::Patron';
381 Kyle M Hall <kyle@bywatersolutions.com>