3 # Copyright 2009 PTFS, Inc.
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
22 use constant DEFAULT_ZEBRAQ_PURGEDAYS => 30;
23 use constant DEFAULT_MAIL_PURGEDAYS => 30;
24 use constant DEFAULT_IMPORT_PURGEDAYS => 60;
25 use constant DEFAULT_LOGS_PURGEDAYS => 180;
26 use constant DEFAULT_MESSAGES_PURGEDAYS => 365;
27 use constant DEFAULT_SEARCHHISTORY_PURGEDAYS => 30;
28 use constant DEFAULT_SHARE_INVITATION_EXPIRY_DAYS => 14;
29 use constant DEFAULT_DEBARMENTS_PURGEDAYS => 30;
31 use Koha::Script -cron;
34 use C4::Search::History;
35 use Getopt::Long qw( GetOptions );
36 use C4::Log qw( cronlogaction );
37 use C4::Accounts qw( purge_zero_balance_fees );
38 use Koha::UploadedFiles;
39 use Koha::Old::Biblios;
41 use Koha::Old::Biblioitems;
42 use Koha::Old::Checkouts;
44 use Koha::Old::Patrons;
45 use Koha::Item::Transfers;
46 use Koha::PseudonymizedTransactions;
47 use Koha::Patron::Messages;
48 use Koha::Patron::Debarments qw( DelDebarment );
52 Usage: $0 [-h|--help] [--confirm] [--sessions] [--sessdays DAYS] [-v|--verbose] [--zebraqueue DAYS] [-m|--mail] [--merged] [--import DAYS] [--logs DAYS] [--searchhistory DAYS] [--restrictions DAYS] [--all-restrictions] [--fees DAYS] [--temp-uploads] [--temp-uploads-days DAYS] [--uploads-missing 0|1 ] [--statistics DAYS] [--deleted-catalog DAYS] [--deleted-patrons DAYS] [--old-issues DAYS] [--old-reserves DAYS] [--transfers DAYS] [--labels DAYS] [--cards DAYS]
54 -h --help prints this help message, and exits, ignoring all
56 --confirm Confirmation flag, the script will be running in dry-run mode is not set.
57 --sessions purge the sessions table. If you use this while users
58 are logged into Koha, they will have to reconnect.
59 --sessdays DAYS purge only sessions older than DAYS days.
60 -v --verbose will cause the script to give you a bit more information
62 --zebraqueue DAYS purge completed zebraqueue entries older than DAYS days.
63 Defaults to 30 days if no days specified.
64 -m --mail DAYS purge items from the mail queue that are older than DAYS days.
65 Defaults to 30 days if no days specified.
66 --merged purged completed entries from need_merge_authorities.
67 --messages DAYS purge entries from messages table older than DAYS days.
68 Defaults to 365 days if no days specified.
69 --import DAYS purge records from import tables older than DAYS days.
70 Defaults to 60 days if no days specified.
71 --z3950 purge records from import tables that are the result
73 --fees DAYS purge entries accountlines older than DAYS days, where
74 amountoutstanding is 0 or NULL.
75 In the case of --fees, DAYS must be greater than
77 --log-modules Specify which action log modules to trim. Repeatable.
78 --preserve-logs Specify which action logs to exclude. Repeatable.
79 --logs DAYS purge entries from action_logs older than DAYS days.
80 Defaults to 180 days if no days specified.
81 --searchhistory DAYS purge entries from search_history older than DAYS days.
82 Defaults to 30 days if no days specified
83 --list-invites DAYS purge (unaccepted) list share invites older than DAYS
84 days. Defaults to 14 days if no days specified.
85 --restrictions DAYS purge patrons restrictions expired since more than DAYS days.
86 Defaults to 30 days if no days specified.
87 --all-restrictions purge all expired patrons restrictions.
88 --del-exp-selfreg Delete expired self registration accounts
89 --del-unv-selfreg DAYS Delete unverified self registrations older than DAYS
90 --unique-holidays DAYS Delete all unique holidays older than DAYS
91 --temp-uploads Delete temporary uploads.
92 --temp-uploads-days DAYS Override the corresponding preference value.
93 --uploads-missing FLAG Delete upload records for missing files when FLAG is true, count them otherwise
94 --oauth-tokens Delete expired OAuth2 tokens
95 --statistics DAYS Purge statistics entries more than DAYS days old.
96 This table is used to build reports, make sure you are aware of the consequences of this before using it!
97 --deleted-catalog DAYS Purge catalog records deleted more then DAYS days ago
98 (from tables deleteditems, deletedbiblioitems, deletedbiblio_metadata and deletedbiblio).
99 --deleted-patrons DAYS Purge patrons deleted more than DAYS days ago.
100 --old-issues DAYS Purge checkouts (old_issues) returned more than DAYS days ago.
101 --old-reserves DAYS Purge reserves (old_reserves) more than DAYS old.
102 --transfers DAYS Purge transfers completed more than DAYS day ago.
103 --pseudo-transactions DAYS Purge the pseudonymized transactions that have been originally created more than DAYS days ago
104 DAYS is optional and can be replaced by:
105 --pseudo-transactions-from YYYY-MM-DD and/or --pseudo-transactions-to YYYY-MM-DD
106 --labels DAYS Purge item label batches last added to more than DAYS days ago.
107 --cards DAY Purge card creator batches last added to more than DAYS days ago.
108 --return-claims Purge all resolved return claims older than the number of days specified in
109 the system preference CleanUpDatabaseReturnClaims.
126 my $pListShareInvites;
133 my $special_holidays_days;
135 my $temp_uploads_days;
144 my ( $pPseudoTransactions, $pPseudoTransactionsFrom, $pPseudoTransactionsTo );
146 my $lock_days = C4::Context->preference('LockExpiredDelay');
154 'confirm' => \$confirm,
155 'sessions' => \$sessions,
156 'sessdays:i' => \$sess_days,
157 'v|verbose' => \$verbose,
158 'm|mail:i' => \$mail,
159 'zebraqueue:i' => \$zebraqueue_days,
160 'merged' => \$purge_merged,
161 'import:i' => \$pImport,
164 'log-module:s' => \@log_modules,
165 'preserve-log:s' => \@preserve_logs,
166 'messages:i' => \$pMessages,
167 'fees:i' => \$fees_days,
168 'searchhistory:i' => \$pSearchhistory,
169 'list-invites:i' => \$pListShareInvites,
170 'restrictions:i' => \$pDebarments,
171 'all-restrictions' => \$allDebarments,
172 'del-exp-selfreg' => \$pExpSelfReg,
173 'del-unv-selfreg:i' => \$pUnvSelfReg,
174 'unique-holidays:i' => \$special_holidays_days,
175 'temp-uploads' => \$temp_uploads,
176 'temp-uploads-days:i' => \$temp_uploads_days,
177 'uploads-missing:i' => \$uploads_missing,
178 'oauth-tokens' => \$oauth_tokens,
179 'statistics:i' => \$pStatistics,
180 'deleted-catalog:i' => \$pDeletedCatalog,
181 'deleted-patrons:i' => \$pDeletedPatrons,
182 'old-issues:i' => \$pOldIssues,
183 'old-reserves:i' => \$pOldReserves,
184 'transfers:i' => \$pTransfers,
185 'pseudo-transactions:i' => \$pPseudoTransactions,
186 'pseudo-transactions-from:s' => \$pPseudoTransactionsFrom,
187 'pseudo-transactions-to:s' => \$pPseudoTransactionsTo,
188 'labels' => \$labels,
190 'return-claims' => \$return_claims,
194 $sessions = 1 if $sess_days && $sess_days > 0;
195 $pImport = DEFAULT_IMPORT_PURGEDAYS if defined($pImport) && $pImport == 0;
196 $pLogs = DEFAULT_LOGS_PURGEDAYS if defined($pLogs) && $pLogs == 0;
197 $zebraqueue_days = DEFAULT_ZEBRAQ_PURGEDAYS if defined($zebraqueue_days) && $zebraqueue_days == 0;
198 $mail = DEFAULT_MAIL_PURGEDAYS if defined($mail) && $mail == 0;
199 $pSearchhistory = DEFAULT_SEARCHHISTORY_PURGEDAYS if defined($pSearchhistory) && $pSearchhistory == 0;
200 $pListShareInvites = DEFAULT_SHARE_INVITATION_EXPIRY_DAYS if defined($pListShareInvites) && $pListShareInvites == 0;
201 $pDebarments = DEFAULT_DEBARMENTS_PURGEDAYS if defined($pDebarments) && $pDebarments == 0;
202 $pMessages = DEFAULT_MESSAGES_PURGEDAYS if defined($pMessages) && $pMessages == 0;
217 || $pListShareInvites
222 || $special_holidays_days
224 || defined $uploads_missing
232 || defined $pPseudoTransactions
233 || $pPseudoTransactionsFrom
234 || $pPseudoTransactionsTo
236 || defined $lock_days && $lock_days ne q{}
241 print "You did not specify any cleanup work for the script to do.\n\n";
245 if ($pDebarments && $allDebarments) {
246 print "You can not specify both --restrictions and --all-restrictions.\n\n";
250 say "Confirm flag not passed, running in dry-run mode..." unless $confirm;
252 cronlogaction() unless $confirm;
254 my $dbh = C4::Context->dbh();
258 if ( $sessions && !$sess_days ) {
260 say "Session purge triggered.";
261 $sth = $dbh->prepare(q{ SELECT COUNT(*) FROM sessions });
262 $sth->execute() or die $dbh->errstr;
263 my @count_arr = $sth->fetchrow_array;
264 say $confirm ? "$count_arr[0] entries will be deleted." : "$count_arr[0] entries would be deleted.";
267 $sth = $dbh->prepare(q{ TRUNCATE sessions });
268 $sth->execute() or die $dbh->errstr;
271 print "Done with session purge.\n";
274 elsif ( $sessions && $sess_days > 0 ) {
275 print "Session purge triggered with days>$sess_days.\n" if $verbose;
276 RemoveOldSessions() if $confirm;
277 print "Done with session purge with days>$sess_days.\n" if $verbose;
280 if ($zebraqueue_days) {
282 print "Zebraqueue purge triggered for $zebraqueue_days days.\n" if $verbose;
283 $sth = $dbh->prepare(
285 SELECT id,biblio_auth_number,server,time
287 WHERE done=1 AND time < date_sub(curdate(), INTERVAL ? DAY)
290 $sth->execute($zebraqueue_days) or die $dbh->errstr;
291 $sth2 = $dbh->prepare(q{ DELETE FROM zebraqueue WHERE id=? });
292 while ( my $record = $sth->fetchrow_hashref ) {
294 $sth2->execute( $record->{id} ) or die $dbh->errstr;
299 say $confirm ? "$count records were deleted." : "$count records would have been deleted.";
300 say "Done with zebraqueue purge.";
306 print "Mail queue purge triggered for $mail days.\n" if $verbose;
307 $sth = $dbh->prepare(
309 DELETE FROM message_queue
310 WHERE time_queued < date_sub(curdate(), INTERVAL ? DAY)
314 $sth->execute($mail) or die $dbh->errstr;
318 say $confirm ? "$count messages were deleted from the mail queue." : "Message from message_queue would have been deleted";
319 say "Done with message_queue purge.";
324 print "Purging completed entries from need_merge_authorities.\n" if $verbose;
326 $sth = $dbh->prepare(q{ DELETE FROM need_merge_authorities WHERE done=1 });
327 $sth->execute() or die $dbh->errstr;
329 print "Done with purging need_merge_authorities.\n" if $verbose;
333 print "Purging records from import tables.\n" if $verbose;
334 PurgeImportTables() if $confirm;
335 print "Done with purging import tables.\n" if $verbose;
339 print "Purging Z39.50 records from import tables.\n" if $verbose;
340 PurgeZ3950() if $confirm;
341 print "Done with purging Z39.50 records from import tables.\n" if $verbose;
345 print "Purging records from action_logs.\n" if $verbose;
347 DELETE FROM action_logs
348 WHERE timestamp < date_sub(curdate(), INTERVAL ? DAY)
350 my @query_params = ();
351 if( @preserve_logs ){
352 $log_query .= " AND module NOT IN (" . join(',',('?') x @preserve_logs ) . ")";
353 push @query_params, @preserve_logs;
356 $log_query .= " AND module IN (" . join(',',('?') x @log_modules ) . ")";
357 push @query_params, @log_modules;
359 $sth = $dbh->prepare( $log_query );
361 $sth->execute($pLogs, @query_params) or die $dbh->errstr;
363 print "Done with purging action_logs.\n" if $verbose;
367 print "Purging messages older than $pMessages days.\n" if $verbose;
368 my $messages = Koha::Patron::Messages->filter_by_last_update(
369 { timestamp_column_name => 'message_date', days => $pMessages } );
370 my $count = $messages->count;
371 $messages->delete if $confirm;
374 ? sprintf( "Done with purging %d messages", $count )
375 : sprintf( "%d messages would have been removed", $count );
380 print "Purging records from accountlines.\n" if $verbose;
381 purge_zero_balance_fees( $fees_days ) if $confirm;
382 print "Done purging records from accountlines.\n" if $verbose;
385 if ($pSearchhistory) {
386 print "Purging records older than $pSearchhistory from search_history.\n" if $verbose;
387 C4::Search::History::delete({ interval => $pSearchhistory }) if $confirm;
388 print "Done with purging search_history.\n" if $verbose;
391 if ($pListShareInvites) {
392 print "Purging unaccepted list share invites older than $pListShareInvites days.\n" if $verbose;
393 $sth = $dbh->prepare(
395 DELETE FROM virtualshelfshares
396 WHERE invitekey IS NOT NULL
397 AND (sharedate + INTERVAL ? DAY) < NOW()
401 $sth->execute($pListShareInvites);
403 print "Done with purging unaccepted list share invites.\n" if $verbose;
407 print "Expired patrons restrictions purge triggered for $pDebarments days.\n" if $verbose;
408 my $count = PurgeDebarments($pDebarments, $confirm);
410 say $confirm ? "$count restrictions were deleted." : "$count restrictions would have been deleted";
411 say "Done with restrictions purge.";
416 print "All expired patrons restrictions purge triggered.\n" if $verbose;
417 my $count = PurgeDebarments(0, $confirm);
419 say $confirm ? "$count restrictions were deleted." : "$count restrictions would have been deleted";
420 say "Done with all restrictions purge.";
424 # Lock expired patrons?
425 if( defined $lock_days && $lock_days ne q{} ) {
426 say "Start locking expired patrons" if $verbose;
427 my $expired_patrons = Koha::Patrons->filter_by_expiration_date({ days => $lock_days })->search({ login_attempts => { '!=' => -1 } });
428 my $count = $expired_patrons->count;
429 $expired_patrons->lock({ remove => 1 }) if $confirm;
431 say $confirm ? sprintf("Locked %d patrons", $count) : sprintf("Found %d patrons", $count);
435 # Handle unsubscribe requests from GDPR consent form, depends on UnsubscribeReflectionDelay preference
436 say "Start lock unsubscribed, anonymize and delete" if $verbose;
437 my $unsubscribed_patrons = Koha::Patrons->search_unsubscribed;
438 my $count = $unsubscribed_patrons->count;
439 $unsubscribed_patrons->lock( { expire => 1, remove => 1 } ) if $confirm;
440 say $confirm ? sprintf("Locked %d patrons", $count) : sprintf("%d patrons would have been locked", $count) if $verbose;
442 # Anonymize patron data, depending on PatronAnonymizeDelay
443 my $anonymize_candidates = Koha::Patrons->search_anonymize_candidates( { locked => 1 } );
444 $count = $anonymize_candidates->count;
445 $anonymize_candidates->anonymize if $confirm;
446 say $confirm ? sprintf("Anonymized %d patrons", $count) : sprintf("%d patrons would have been anonymized", $count) if $verbose;
448 # Remove patron data, depending on PatronRemovalDelay (will raise an exception if problem encountered
449 my $anonymized_patrons = Koha::Patrons->search_anonymized;
450 $count = $anonymized_patrons->count;
452 $anonymized_patrons->delete( { move => 1 } );
458 say $confirm ? sprintf("Deleted %d patrons", $count) : sprintf("%d patrons would have been deleted", $count);
461 # FIXME The output for dry-run mode needs to be improved
462 # But non trivial changes to C4::Members need to be done before.
465 DeleteExpiredSelfRegs();
466 } elsif ( $verbose ) {
467 say "self-registered borrowers may be deleted";
472 DeleteUnverifiedSelfRegs( $pUnvSelfReg );
473 } elsif ( $verbose ) {
474 say "unverified self-registrations may be deleted";
478 if ($special_holidays_days) {
480 DeleteSpecialHolidays( abs($special_holidays_days) );
481 } elsif ( $verbose ) {
482 say "self-registered borrowers may be deleted";
486 if( $temp_uploads ) {
487 # Delete temporary uploads, governed by a pref (unless you override)
488 print "Purging temporary uploads.\n" if $verbose;
490 Koha::UploadedFiles->delete_temporary({
491 defined($temp_uploads_days)
492 ? ( override_pref => $temp_uploads_days )
496 print "Done purging temporary uploads.\n" if $verbose;
499 if( defined $uploads_missing ) {
500 print "Looking for missing uploads\n" if $verbose;
502 my $keep = $uploads_missing == 1 ? 0 : 1;
503 my $count = Koha::UploadedFiles->delete_missing({ keep_record => $keep });
505 print "Counted $count missing uploaded files\n";
507 print "Removed $count records for missing uploads\n";
510 # FIXME need to create a filter_by_missing method (then call ->delete) instead of delete_missing
511 say "Dry-run mode cannot guess how many uploads would have been deleted";
516 require Koha::OAuthAccessTokens;
518 my $tokens = Koha::OAuthAccessTokens->search({ expires => { '<=', time } });
519 my $count = $tokens->count;
520 $tokens->delete if $confirm;
523 ? sprintf( "Removed %d expired OAuth2 tokens", $count )
524 : sprintf( "%d expired OAuth tokens would have been removed", $count );
529 print "Purging statistics older than $pStatistics days.\n" if $verbose;
530 my $statistics = Koha::Statistics->filter_by_last_update(
531 { timestamp_column_name => 'datetime', days => $pStatistics } );
532 my $count = $statistics->count;
533 $statistics->delete if $confirm;
536 ? sprintf( "Done with purging %d statistics", $count )
537 : sprintf( "%d statistics would have been removed", $count );
541 if( $return_claims && ( my $days = C4::Context->preference('CleanUpDatabaseReturnClaims') )) {
542 print "Purging return claims older than $days days.\n" if $verbose;
544 $return_claims = Koha::Checkouts::ReturnClaims->filter_by_last_update(
546 timestamp_column_name => 'resolved_on',
551 my $count = $return_claims->count;
552 $return_claims->delete if $confirm;
556 ? sprintf "Done with purging %d resolved return claims.", $count
557 : sprintf "%d resolved return claims would have been purged.", $count;
561 if ($pDeletedCatalog) {
562 print "Purging deleted catalog older than $pDeletedCatalog days.\n"
564 my $old_items = Koha::Old::Items->filter_by_last_update( { days => $pDeletedCatalog } );
565 my $old_biblioitems = Koha::Old::Biblioitems->filter_by_last_update( { days => $pDeletedCatalog } );
566 my $old_biblios = Koha::Old::Biblios->filter_by_last_update( { days => $pDeletedCatalog } );
567 my ( $c_i, $c_bi, $c_b ) =
568 ( $old_items->count, $old_biblioitems->count, $old_biblios->count );
571 $old_biblioitems->delete;
572 $old_biblios->delete;
577 ? "Done with purging deleted catalog (%d items, %d biblioitems, %d biblios)."
578 : "Deleted catalog would have been removed (%d items, %d biblioitems, %d biblios).",
583 if ($pDeletedPatrons) {
584 print "Purging deleted patrons older than $pDeletedPatrons days.\n" if $verbose;
585 my $old_patrons = Koha::Old::Patrons->filter_by_last_update(
586 { timestamp_column_name => 'updated_on', days => $pDeletedPatrons } );
587 my $count = $old_patrons->count;
588 $old_patrons->delete if $confirm;
591 ? sprintf "Done with purging %d deleted patrons.", $count
592 : sprintf "%d deleted patrons would have been purged.", $count;
597 print "Purging old checkouts older than $pOldIssues days.\n" if $verbose;
598 my $old_checkouts = Koha::Old::Checkouts->filter_by_last_update( { days => $pOldIssues } );
599 my $count = $old_checkouts->count;
600 $old_checkouts->delete if $confirm;
603 ? sprintf "Done with purging %d old checkouts.", $count
604 : sprintf "%d old checkouts would have been purged.", $count;
609 print "Purging old reserves older than $pOldReserves days.\n" if $verbose;
610 my $old_reserves = Koha::Old::Holds->filter_by_last_update( { days => $pOldReserves } );
611 my $count = $old_reserves->count;
612 $old_reserves->delete if $verbose;
615 ? sprintf "Done with purging %d old reserves.", $count
616 : sprintf "%d old reserves would have been purged.", $count;
621 print "Purging arrived item transfers older than $pTransfers days.\n" if $verbose;
622 my $transfers = Koha::Item::Transfers->filter_by_last_update(
624 timestamp_column_name => 'datearrived',
628 my $count = $transfers->count;
629 $transfers->delete if $verbose;
632 ? sprintf "Done with purging %d transfers.", $count
633 : sprintf "%d transfers would have been purged.", $count;
637 if (defined $pPseudoTransactions or $pPseudoTransactionsFrom or $pPseudoTransactionsTo ) {
638 print "Purging pseudonymized transactions\n" if $verbose;
639 my $anonymized_transactions = Koha::PseudonymizedTransactions->filter_by_last_update(
641 timestamp_column_name => 'datetime',
642 ( defined $pPseudoTransactions ? ( days => $pPseudoTransactions ) : () ),
643 ( $pPseudoTransactionsFrom ? ( from => $pPseudoTransactionsFrom ) : () ),
644 ( $pPseudoTransactionsTo ? ( to => $pPseudoTransactionsTo ) : () ),
647 my $count = $anonymized_transactions->count;
648 $anonymized_transactions->delete if $confirm;
651 ? sprintf "Done with purging %d pseudonymized transactions.", $count
652 : sprintf "%d pseudonymized transactions would have been purged.", $count;
657 print "Purging item label batches last added to more than $labels days ago.\n" if $verbose;
658 my $count = PurgeCreatorBatches($labels, 'labels', $confirm);
661 ? sprintf "Done with purging %d item label batches last added to more than %d days ago.\n", $count, $labels
662 : sprintf "%d item label batches would have been purged.", $count;
667 print "Purging card creator batches last added to more than $cards days ago.\n" if $verbose;
668 my $count = PurgeCreatorBatches($labels, 'patroncards', $confirm);
671 ? sprintf "Done with purging %d card creator batches last added to more than %d days ago.\n", $count, $labels
672 : sprintf "%d card creator batches would have been purged.", $count;
678 sub RemoveOldSessions {
679 my ( $id, $a_session, $limit, $lasttime );
680 $limit = time() - 24 * 3600 * $sess_days;
682 $sth = $dbh->prepare(q{ SELECT id, a_session FROM sessions });
683 $sth->execute or die $dbh->errstr;
684 $sth->bind_columns( \$id, \$a_session );
685 $sth2 = $dbh->prepare(q{ DELETE FROM sessions WHERE id=? });
688 while ( $sth->fetch ) {
690 if ( $a_session =~ /lasttime:\s+'?(\d+)/ ) {
693 elsif ( $a_session =~ /(ATIME|CTIME):\s+'?(\d+)/ ) {
696 if ( $lasttime && $lasttime < $limit ) {
697 $sth2->execute($id) or die $dbh->errstr;
702 print "$count sessions were deleted.\n";
706 sub PurgeImportTables {
708 #First purge import_records
709 #Delete cascades to import_biblios, import_items and import_record_matches
710 $sth = $dbh->prepare(
712 DELETE FROM import_records
713 WHERE upload_timestamp < date_sub(curdate(), INTERVAL ? DAY)
716 $sth->execute($pImport) or die $dbh->errstr;
718 # Now purge import_batches
719 # Timestamp cannot be used here without care, because records are added
720 # continuously to batches without updating timestamp (Z39.50 search).
721 # So we only delete older empty batches.
722 # This delete will therefore not have a cascading effect.
723 $sth = $dbh->prepare(
726 FROM import_batches ba
727 LEFT JOIN import_records re ON re.import_batch_id=ba.import_batch_id
728 WHERE re.import_record_id IS NULL AND
729 ba.upload_timestamp < date_sub(curdate(), INTERVAL ? DAY)
732 $sth->execute($pImport) or die $dbh->errstr;
736 $sth = $dbh->prepare(
738 DELETE FROM import_batches
739 WHERE batch_type = 'z3950'
742 $sth->execute() or die $dbh->errstr;
745 sub PurgeDebarments {
746 require Koha::Patron::Debarments;
747 my ( $days, $doit ) = @_;
749 $sth = $dbh->prepare(
751 SELECT borrower_debarment_id
752 FROM borrower_debarments
753 WHERE expiration < date_sub(curdate(), INTERVAL ? DAY)
756 $sth->execute($days) or die $dbh->errstr;
757 while ( my ($borrower_debarment_id) = $sth->fetchrow_array ) {
758 Koha::Patron::Debarments::DelDebarment($borrower_debarment_id) if $doit;
764 sub PurgeCreatorBatches {
765 require C4::Labels::Batch;
766 my ( $days, $creator, $doit ) = @_;
768 $sth = $dbh->prepare(
770 SELECT batch_id, branch_code FROM creator_batches
773 FROM (SELECT batch_id
777 HAVING max(timestamp) <= date_sub(curdate(),interval ? day)) a)
780 $sth->execute( $creator, $days ) or die $dbh->errstr;
781 while ( my ( $batch_id, $branch_code ) = $sth->fetchrow_array ) {
782 C4::Labels::Batch::delete(
783 batch_id => $batch_id,
784 branch_code => $branch_code
791 sub DeleteExpiredSelfRegs {
792 my $cnt= C4::Members::DeleteExpiredOpacRegistrations();
793 print "Removed $cnt expired self-registered borrowers\n" if $verbose;
796 sub DeleteUnverifiedSelfRegs {
797 my $cnt= C4::Members::DeleteUnverifiedOpacRegistrations( $_[0] );
798 print "Removed $cnt unverified self-registrations\n" if $verbose;
801 sub DeleteSpecialHolidays {
804 my $sth = $dbh->prepare(q{
805 DELETE FROM special_holidays
806 WHERE DATE( CONCAT( year, '-', month, '-', day ) ) < DATE_SUB( CAST(NOW() AS DATE), INTERVAL ? DAY );
808 my $count = $sth->execute( $days ) + 0;
809 print "Removed $count unique holidays\n" if $verbose;