Bug 17600: Standardize our EXPORT_OK
[srvgit] / misc / cronjobs / automatic_renewals.pl
index 1906301..cb45e68 100755 (executable)
@@ -2,7 +2,7 @@
 
 # This file is part of Koha.
 #
-# Copyright (C) 2014 Hochschule für Gesundheit (hsg), Germany
+# Copyright (C) 2014 Hochschule für Gesundheit (hsg), Germany
 #
 # Koha is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -23,10 +23,13 @@ automatic_renewals.pl - cron script to renew loans
 
 =head1 SYNOPSIS
 
-./automatic_renewals.pl [--send-notices]
+./automatic_renewals.pl [-c|--confirm] [-s|--send-notices] [-d|--digest] [-b|--digest-per-branch] [-v|--verbose]
 
 or, in crontab:
-0 3 * * * automatic_renewals.pl
+# Once every day for digest messages
+0 3 * * * automatic_renewals.pl -c -d
+# Three times a day for non digest messages
+0 0,8,16 * * * automatic_renewals.pl -c
 
 =head1 DESCRIPTION
 
@@ -38,65 +41,160 @@ and the renewal isn't premature (No Renewal before) the issue is renewed.
 
 =over
 
-=item B<--send-notices>
+=item B<-s|--send-notices>
 
+DEPRECATED: The system preference AutoRenewalNotices should be used to determine
+whether notices are sent or not
 Send AUTO_RENEWALS notices to patrons if the auto renewal has been done.
 
-Note that this option does not support digest yet.
+=item B<-v|--verbose>
+
+Print report to standard out.
+
+=item B<-c|--confirm>
+
+Without this parameter no changes will be made
+
+=item B<-b|--digest-per-branch>
+
+Flag to indicate that generation of message digests should be
+performed separately for each branch.
+
+A patron could potentially have loans at several different branches
+There is no natural branch to set as the sender on the aggregated
+message in this situation so the default behavior is to use the
+borrowers home branch.  This could surprise to the borrower when
+message sender is a library where they have not borrowed anything.
+
+Enabling this flag ensures that the issuing library is the sender of
+the digested message.  It has no effect unless the borrower has
+chosen 'Digests only' on the advance messages.
 
 =back
 
 =cut
 
 use Modern::Perl;
-use Pod::Usage;
-use Getopt::Long;
+use Pod::Usage qw( pod2usage );
+use Getopt::Long qw( GetOptions );
 
-use C4::Circulation;
+use Koha::Script -cron;
+use C4::Circulation qw( CanBookBeRenewed AddRenewal );
 use C4::Context;
-use C4::Log;
+use C4::Log qw( cronlogaction );
 use C4::Letters;
 use Koha::Checkouts;
 use Koha::Libraries;
 use Koha::Patrons;
 
-my ( $help, $send_notices );
+my ( $help, $send_notices, $verbose, $confirm, $digest_per_branch );
 GetOptions(
     'h|help' => \$help,
-    'send-notices' => \$send_notices,
+    's|send-notices' => \$send_notices,
+    'v|verbose'    => \$verbose,
+    'c|confirm'     => \$confirm,
+    'b|digest-per-branch' => \$digest_per_branch,
 ) || pod2usage(1);
 
 pod2usage(0) if $help;
 
+my $send_notices_pref = C4::Context->preference('AutoRenewalNotices');
+if ( $send_notices_pref eq 'cron' ) {
+    warn <<'END_WARN';
+
+The "AutoRenewalNotices" syspref is set to 'Follow the cron switch'.
+The send_notices switch for this script is deprecated, you should either set the preference
+to 'Never send emails' or 'Follow patron messaging preferences'
+
+END_WARN
+} else {
+    # If not following cron then we should not send if set to never
+    # and always send any generated according to preferences if following those
+    $send_notices = $send_notices_pref eq 'never' ? 0 : 1;
+}
+
+# Since advance notice options are not visible in the web-interface
+# unless EnhancedMessagingPreferences is on, let the user know that
+# this script probably isn't going to do much
+if ( ! C4::Context->preference('EnhancedMessagingPreferences') ) {
+    warn <<'END_WARN';
+
+The "EnhancedMessagingPreferences" syspref is off.
+Therefore, it is unlikely that this script will actually produce any messages to be sent.
+To change this, edit the "EnhancedMessagingPreferences" syspref.
+
+END_WARN
+}
+
 cronlogaction();
 
-my $auto_renews = Koha::Checkouts->search({ auto_renew => 1 });
+$verbose = 1 unless $verbose or $confirm;
+print "Test run only\n" unless $confirm;
 
+print "getting auto renewals\n" if $verbose;
+my $auto_renews = Koha::Checkouts->search({ auto_renew => 1, 'borrower.autorenew_checkouts' => 1 },{ join => 'borrower'});
+print "found " . $auto_renews->count . " auto renewals\n" if $verbose;
+
+my $renew_digest = {};
 my %report;
 while ( my $auto_renew = $auto_renews->next ) {
+    print "examining item '" . $auto_renew->itemnumber . "' to auto renew\n" if $verbose;
+
+    my $borrower_preferences;
+    $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $auto_renew->borrowernumber,
+                                                                                   message_name   => 'auto_renewals' } ) if $send_notices_pref eq 'preferences';
+
+    $send_notices = 1 if !$send_notices && $send_notices_pref eq 'preferences' && $borrower_preferences && $borrower_preferences->{transports} && $borrower_preferences->{transports}->{email};
 
     # CanBookBeRenewed returns 'auto_renew' when the renewal should be done by this script
-    my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->borrowernumber, $auto_renew->itemnumber );
+    my ( $ok, $error ) = CanBookBeRenewed( $auto_renew->borrowernumber, $auto_renew->itemnumber, undef, 1 );
     if ( $error eq 'auto_renew' ) {
-        my $date_due = AddRenewal( $auto_renew->borrowernumber, $auto_renew->itemnumber, $auto_renew->branchcode );
-        $auto_renew->auto_renew_error(undef)->store;
-        push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew;
+        if ($verbose) {
+            say sprintf "Issue id: %s for borrower: %s and item: %s %s be renewed.",
+              $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $confirm ? 'will' : 'would';
+        }
+        if ($confirm){
+            my $date_due = AddRenewal( $auto_renew->borrowernumber, $auto_renew->itemnumber, $auto_renew->branchcode, undef, undef, undef, 0 );
+            $auto_renew->auto_renew_error(undef)->store;
+        }
+        push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew unless $send_notices_pref ne 'cron' && (!$borrower_preferences || !$borrower_preferences->{transports} || !$borrower_preferences->{transports}->{email} || $borrower_preferences->{'wants_digest'});
     } elsif ( $error eq 'too_many'
         or $error eq 'on_reserve'
         or $error eq 'restriction'
         or $error eq 'overdue'
+        or $error eq 'too_unseen'
+        or $error eq 'auto_account_expired'
         or $error eq 'auto_too_late'
         or $error eq 'auto_too_much_oweing'
-        or $error eq 'auto_too_soon' ) {
+        or $error eq 'auto_too_soon'
+        or $error eq 'item_denied_renewal' ) {
+        if ( $verbose ) {
+            say sprintf "Issue id: %s for borrower: %s and item: %s %s not be renewed. (%s)",
+              $auto_renew->issue_id, $auto_renew->borrowernumber, $auto_renew->itemnumber, $confirm ? 'will' : 'would', $error;
+        }
         if ( not $auto_renew->auto_renew_error or $error ne $auto_renew->auto_renew_error ) {
-            $auto_renew->auto_renew_error($error)->store;
+            $auto_renew->auto_renew_error($error)->store if $confirm;
             push @{ $report{ $auto_renew->borrowernumber } }, $auto_renew
-              if $error ne 'auto_too_soon';    # Do not notify if it's too soon
+              if $error ne 'auto_too_soon' && ($send_notices_pref eq 'cron' || ($borrower_preferences && $borrower_preferences->{transports} && $borrower_preferences->{transports}->{email} && !$borrower_preferences->{'wants_digest'}));    # Do not notify if it's too soon
+        }
+    }
+
+    if ( $borrower_preferences && $borrower_preferences->{transports} && $borrower_preferences->{transports}->{email} && $borrower_preferences->{'wants_digest'} ) {
+        # cache this one to process after we've run through all of the items.
+        if ($digest_per_branch) {
+            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{success}++ if $error eq 'auto_renew';
+            $renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew' || $error eq 'auto_too_soon' ;
+            push @{$renew_digest->{ $auto_renew->branchcode }->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
+        } else {
+            $renew_digest->{ $auto_renew->borrowernumber }->{success} ++ if $error eq 'auto_renew';
+            $renew_digest->{ $auto_renew->borrowernumber }->{error}++ unless $error eq 'auto_renew' || $error eq 'auto_too_soon' ;
+            push @{$renew_digest->{ $auto_renew->borrowernumber }->{issues}}, $auto_renew->itemnumber;
         }
     }
+
 }
 
-if ( $send_notices ) {
+if ( $send_notices && $confirm ) {
     for my $borrowernumber ( keys %report ) {
         my $patron = Koha::Patrons->find($borrowernumber);
         for my $issue ( @{ $report{$borrowernumber} } ) {
@@ -110,10 +208,11 @@ if ( $send_notices ) {
                     items     => $issue->itemnumber,
                     biblio    => $item->biblionumber,
                 },
+                lang => $patron->lang,
             );
 
             my $library = Koha::Libraries->find( $patron->branchcode );
-            my $admin_email_address = $library->branchemail || C4::Context->preference('KohaAdminEmailAddress');
+            my $admin_email_address = $library->from_email_address;
 
             C4::Letters::EnqueueLetter(
                 {   letter                 => $letter,
@@ -124,4 +223,93 @@ if ( $send_notices ) {
             );
         }
     }
+
+    if ($digest_per_branch) {
+        while (my ($branchcode, $digests) = each %$renew_digest) {
+            send_digests({
+                digests => $digests,
+                branchcode => $branchcode,
+                letter_code => 'AUTO_RENEWALS_DGST',
+            });
+        }
+    } else {
+        send_digests({
+            digests => $renew_digest,
+            letter_code => 'AUTO_RENEWALS_DGST',
+        });
+    }
+}
+
+=head1 METHODS
+
+=head2 send_digests
+
+    send_digests({
+        digests => ...,
+        letter_code => ...,
+    })
+
+Enqueue digested letters.
+
+Parameters:
+
+=over 4
+
+=item C<$digests>
+
+Reference to the array of digested messages.
+
+=item C<$letter_code>
+
+String that denote the letter code.
+
+=back
+
+=cut
+
+sub send_digests {
+    my $params = shift;
+
+    PATRON: while ( my ( $borrowernumber, $digest ) = each %{$params->{digests}} ) {
+        my $borrower_preferences =
+            C4::Members::Messaging::GetMessagingPreferences(
+                {
+                    borrowernumber => $borrowernumber,
+                    message_name   => 'auto_renewals'
+                }
+            );
+
+        next PATRON unless $borrower_preferences; # how could this happen?
+
+        my $patron = Koha::Patrons->find( $borrowernumber );
+        my $library = Koha::Libraries->find( $params->{branchcode} );
+        my $from_address = $library->from_email_address;
+
+        foreach my $transport ( keys %{ $borrower_preferences->{'transports'} } ) {
+            my $letter = C4::Letters::GetPreparedLetter (
+                module => 'circulation',
+                letter_code => $params->{letter_code},
+                branchcode => $params->{branchcode},
+                lang => $patron->lang,
+                substitute => {
+                    error => $digest->{error}||0,
+                    success => $digest->{success}||0,
+                },
+                loops => { issues => \@{$digest->{issues}} },
+                tables      => {
+                    borrowers => $patron->borrowernumber,
+                },
+                message_transport_type => $transport,
+            ) || warn "no letter of type '$params->{letter_code}' found for borrowernumber $borrowernumber. Please see sample_notices.sql";
+
+            next unless $letter;
+
+            C4::Letters::EnqueueLetter({
+                letter                 => $letter,
+                borrowernumber         => $borrowernumber,
+                from_address           => $from_address,
+                message_transport_type => $transport
+            });
+        }
+    }
 }