Bug 17600: Standardize our EXPORT_OK
[srvgit] / misc / cronjobs / fines.pl
index 5124f3c..3edf6ed 100755 (executable)
@@ -3,7 +3,7 @@
 #  This script loops through each overdue item, determines the fine,
 #  and updates the total amount of fines due by each user.  It relies on
 #  the existence of /tmp/fines, which is created by ???
-# Doesnt really rely on it, it relys on being able to write to /tmp/
+# Doesn't really rely on it, it relys on being able to write to /tmp/
 # It creates the fines file
 #
 #  This script is meant to be run nightly out of cron.
 #
 # This file is part of Koha.
 #
-# Koha is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
 #
-# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
 #
-# You should have received a copy of the GNU General Public License along
-# with Koha; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
 
 use strict;
 use warnings;
 use 5.010;
 
+use Koha::Script -cron;
 use C4::Context;
-use C4::Overdues;
-use Getopt::Long;
-use Carp;
+use C4::Overdues qw( Getoverdues CalcFine UpdateFine );
+use Getopt::Long qw( GetOptions );
+use Carp qw( carp croak );
 use File::Spec;
+use Try::Tiny qw( catch try );
 
 use Koha::Calendar;
-use Koha::DateUtils;
+use Koha::DateUtils qw( dt_from_string output_pref );
+use Koha::Patrons;
+use C4::Log qw( cronlogaction );
 
 my $help;
 my $verbose;
 my $output_dir;
+my $log;
+my $maxdays;
 
 GetOptions(
     'h|help'    => \$help,
     'v|verbose' => \$verbose,
+    'l|log'     => \$log,
     'o|out:s'   => \$output_dir,
+    'm|maxdays:i' => \$maxdays,
 );
 my $usage = << 'ENDUSAGE';
 
 This script calculates and charges overdue fines
-to patron accounts.  If the Koha System Preference
-'finesMode' is set to 'production', the fines are charged
-to the patron accounts.  If set to 'test', the fines are
-calculated but not applied.
+to patron accounts.  The Koha system preference 'finesMode' controls
+whether the fines are calculated and charged to the patron accounts ("Calculate and charge");
+or not calculated ("Don't calculate").
 
 This script has the following parameters :
     -h --help: this message
+    -l --log: log the output to a file (optional if the -o parameter is given)
     -o --out:  ouput directory for logs (defaults to env or /tmp if !exist)
     -v --verbose
+    -m --maxdays: how many days back of overdues to process
 
 ENDUSAGE
 
@@ -68,35 +77,60 @@ if ($help) {
     exit;
 }
 
+my $script_handler = Koha::Script->new({ script => $0 });
+
+try {
+    $script_handler->lock_exec;
+}
+catch {
+    my $message = "Skipping execution of $0 ($_)";
+    print STDERR "$message\n"
+        if $verbose;
+    cronlogaction( $message );
+    exit;
+};
+
+cronlogaction();
+
 my @borrower_fields =
   qw(cardnumber categorycode surname firstname email phone address citystate);
 my @item_fields  = qw(itemnumber barcode date_due);
-my @other_fields = qw(type days_overdue fine);
+my @other_fields = qw(days_overdue fine);
 my $libname      = C4::Context->preference('LibraryName');
 my $control      = C4::Context->preference('CircControl');
 my $mode         = C4::Context->preference('finesMode');
-my $delim = "\t";    # ?  C4::Context->preference('delimiter') || "\t";
+my $delim = "\t";    # ?  C4::Context->preference('CSVDelimiter') || "\t";
 
 my %is_holiday;
-my $today = DateTime->now( time_zone => C4::Context->tz() );
-my $filename = get_filename($output_dir);
-
-open my $fh, '>>', $filename or croak "Cannot write file $filename: $!";
-print {$fh} join $delim, ( @borrower_fields, @item_fields, @other_fields );
-print {$fh} "\n";
+my $today = dt_from_string();
+my $filename;
+if ($log or $output_dir) {
+    $filename = get_filename($output_dir);
+}
 
-my $counted  = 0;
-my $overdues = Getoverdues();
+my $fh;
+if ($filename) {
+    open $fh, '>>', $filename or croak "Cannot write file $filename: $!";
+    print {$fh} join $delim, ( @borrower_fields, @item_fields, @other_fields );
+    print {$fh} "\n";
+}
+my $counted = 0;
+my $updated = 0;
+my $params;
+$params->{maximumdays} = $maxdays if $maxdays;
+my $overdues = Getoverdues($params);
 for my $overdue ( @{$overdues} ) {
+    next if $overdue->{itemlost};
+
     if ( !defined $overdue->{borrowernumber} ) {
         carp
 "ERROR in Getoverdues : issues.borrowernumber IS NULL.  Repair 'issues' table now!  Skipping record.\n";
         next;
     }
-    my $borrower = BorType( $overdue->{borrowernumber} );
+    my $patron = Koha::Patrons->find( $overdue->{borrowernumber} );
     my $branchcode =
         ( $control eq 'ItemHomeLibrary' ) ? $overdue->{homebranch}
-      : ( $control eq 'PatronLibrary' )   ? $borrower->{branchcode}
+      : ( $control eq 'PatronLibrary' )   ? $patron->branchcode
       :                                     $overdue->{branchcode};
 
 # In final case, CircControl must be PickupLibrary. (branchcode comes from issues table here).
@@ -110,39 +144,58 @@ for my $overdue ( @{$overdues} ) {
     }
     ++$counted;
 
-    my ( $amount, $type, $daycounttotal ) =
-      CalcFine( $overdue, $borrower->{categorycode},
+    my ( $amount, $unitcounttotal, $unitcount ) =
+      CalcFine( $overdue, $patron->categorycode,
         $branchcode, $datedue, $today );
 
-    $type ||= q{};
-
     # Don't update the fine if today is a holiday.
     # This ensures that dropbox mode will remove the correct amount of fine.
-    if ( $mode eq 'production' && !$is_holiday{$branchcode} ) {
-        if ( $amount > 0 ) {
-            UpdateFine(
-                $overdue->{itemnumber},
-                $overdue->{borrowernumber},
-                $amount, $type, output_pref($datedue)
-            );
-        }
+    if (
+        $mode eq 'production'
+        && ( !$is_holiday{$branchcode}
+            || C4::Context->preference('ChargeFinesOnClosedDays') )
+        && ( $amount && $amount > 0 )
+      )
+    {
+        UpdateFine(
+            {
+                issue_id       => $overdue->{issue_id},
+                itemnumber     => $overdue->{itemnumber},
+                borrowernumber => $overdue->{borrowernumber},
+                amount         => $amount,
+                due            => output_pref($datedue),
+            }
+        );
+        $updated++;
+    }
+    my $borrower = $patron->unblessed;
+    if ($filename) {
+        my @cells;
+        push @cells,
+          map { defined $borrower->{$_} ? $borrower->{$_} : q{} }
+          @borrower_fields;
+        push @cells, map { $overdue->{$_} } @item_fields;
+        push @cells, $unitcounttotal, $amount;
+        say {$fh} join $delim, @cells;
     }
-    my @cells;
-    push @cells,
-      map { defined $borrower->{$_} ? $borrower->{$_} : q{} } @borrower_fields;
-    push @cells, map { $overdue->{$_} } @item_fields;
-    push @cells, $type, $daycounttotal, $amount;
-    say {$fh} join $delim, @cells;
 }
-close $fh;
+if ($filename){
+    close $fh;
+}
 
 if ($verbose) {
     my $overdue_items = @{$overdues};
-    print <<'EOM';
-Fines assessment -- $today->ymd() -- Saved to $filename
+    print <<"EOM";
+Fines assessment -- $today
+EOM
+    if ($filename) {
+        say "Saved to $filename";
+    }
+    print <<"EOM";
 Number of Overdue Items:
      counted $overdue_items
     reported $counted
+     updated $updated
 
 EOM
 }
@@ -157,7 +210,7 @@ sub set_holiday {
 sub get_filename {
     my $directory = shift;
     if ( !$directory ) {
-        $directory = File::Spec->tmpdir();
+        $directory = C4::Context::temporary_directory;
     }
     if ( !-d $directory ) {
         carp "Could not write to $directory ... does not exist!";
@@ -166,7 +219,7 @@ sub get_filename {
     $name =~ s/\W//;
     $name .= join q{}, q{_}, $today->ymd(), '.log';
     $name = File::Spec->catfile( $directory, $name );
-    if ($verbose) {
+    if ($verbose && $log) {
         say "writing to $name";
     }
     return $name;