From 15c8a453fc938410c66e3c0074f55da22395c560 Mon Sep 17 00:00:00 2001 From: Matthias Meusburger Date: Wed, 23 Mar 2011 16:19:07 +0100 Subject: [PATCH] Bug 6858: Adds staticfines.pl for static fines processing MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Add a tool to calculate static fine. For example, 7 days left = 1€ fixed fine Signed-off-by: Delaye Stephane Signed-off-by: Paul Poulain --- misc/cronjobs/staticfines.pl | 237 +++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100755 misc/cronjobs/staticfines.pl diff --git a/misc/cronjobs/staticfines.pl b/misc/cronjobs/staticfines.pl new file mode 100755 index 0000000000..5d6e25cc8b --- /dev/null +++ b/misc/cronjobs/staticfines.pl @@ -0,0 +1,237 @@ +#!/usr/bin/perl + +# 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/ +# It creates the fines file +# +# This script is meant to be run nightly out of cron. + +# Copyright 2000-2002 Katipo Communications +# +# 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 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. + +# FIXME: use FinesMode as described or change syspref description +use strict; + +#use warnings; FIXME - Bug 2505 + +BEGIN { + + # find Koha's Perl modules + # test carefully before changing this + use FindBin; + eval { require "$FindBin::Bin/kohalib.pl" }; +} + +use Date::Calc qw/Date_to_Days/; + +use C4::Context; +use C4::Circulation; +use C4::Overdues; +use C4::Calendar qw(); # don't need any exports from Calendar +use C4::Biblio; +use C4::Debug; # supplying $debug and $cgi_debug +use Getopt::Long; +use List::MoreUtils qw/none/; + +my $help = 0; +my $verbose = 0; +my $output_dir; +my @pcategories; +my @categories; +my %catamounts; +my @libraries; +my $delay; +my $useborrowerlibrary; +my $borrowersalreadyapplied; # hashref of borrowers for whom we already applied the fine, so it's only applied once +my $debug = $ENV{'DEBUG'} || 0; +my $bigdebug = 0; + +GetOptions( + 'h|help' => \$help, + 'v|verbose' => \$verbose, + 'o|out:s' => \$output_dir, + 'c|category:s'=> \@pcategories, + 'l|library:s' => \@libraries, + 'd|delay:i' => \$delay, + 'u|use-borrower-library' => \$useborrowerlibrary +); +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. + +Please note that the fines won't be applied on a holiday. + +This script has the following parameters : + -h --help: this message + -o --out: ouput directory for logs (defaults to env or /tmp if !exist) + -v --verbose + -c --category borrower_category,amount (repeatable) + -l --library (repeatable) + -d --delay + -u --use-borrower-library: use borrower's library, regardless of the CircControl syspref + +ENDUSAGE +die $usage if $help; + +# Processing categories +foreach (@pcategories) { + my ($category, $amount) = split(',', $_); + push @categories, $category; + $catamounts{$category} = $amount; +} + +use vars qw(@borrower_fields @item_fields @other_fields); +use vars qw($fldir $libname $control $mode $delim $dbname $today $today_iso $today_days); +use vars qw($filename); + +CHECK { + @borrower_fields = qw(cardnumber categorycode surname firstname email phone address citystate); + @item_fields = qw(itemnumber barcode date_due); + @other_fields = qw(type days_overdue fine); + $libname = C4::Context->preference('LibraryName'); + $control = C4::Context->preference('CircControl'); + $mode = C4::Context->preference('finesMode'); + $dbname = C4::Context->config('database'); + $delim = "\t"; # ? C4::Context->preference('delimiter') || "\t"; + +} + +INIT { + $debug and print "Each line will contain the following fields:\n", + "From borrowers : ", join( ', ', @borrower_fields ), "\n", + "From items : ", join( ', ', @item_fields ), "\n", + "Per overdue: ", join( ', ', @other_fields ), "\n", + "Delimiter: '$delim'\n"; +} + +my $data = Getoverdues(); +my $overdueItemsCounted = 0; +my %calendars = (); +$today = C4::Dates->new(); +$today_iso = $today->output('iso'); +$today_days = Date_to_Days( split( /-/, $today_iso ) ); + + + +if ($output_dir) { + $fldir = $output_dir if ( -d $output_dir ); +} else { + $fldir = $ENV{TMPDIR} || "/tmp"; +} +if ( !-d $fldir ) { + warn "Could not write to $fldir ... does not exist!"; +} +$filename = $dbname; +$filename =~ s/\W//; +$filename = $fldir . '/' . $filename . '_' . $today_iso . ".log"; +print "writing to $filename\n" if $verbose; +open my $FILE, ">", $filename or die "Cannot write file $filename: $!"; +print $FILE join $delim, ( @borrower_fields, @item_fields, @other_fields ); +print $FILE "\n"; + +for ( my $i = 0 ; $i < scalar(@$data) ; $i++ ) { + my $datedue; + my $datedue_days; + eval { + $datedue = C4::Dates->new( $data->[$i]->{'date_due'}, 'iso' ); + $datedue_days = Date_to_Days( split( /-/, $datedue->output('iso') ) ); + }; + if ($@) { + warn "Error on date for borrower " . $data->[$i]->{'borrowernumber'} . ": $@date_due: " . $data->[$i]->{'date_due'} . "\ndatedue_days: " . $datedue_days . "\nSkipping"; + next; + } + my $due_str = $datedue->output(); + unless ( defined $data->[$i]->{'borrowernumber'} ) { + print STDERR "ERROR in Getoverdues line $i: issues.borrowernumber IS NULL. Repair 'issues' table now! Skipping record.\n"; + next; # Note: this doesn't solve everything. After NULL borrowernumber, multiple issues w/ real borrowernumbers can pile up. + } + my $borrower = BorType( $data->[$i]->{'borrowernumber'} ); + + # Skipping borrowers that are not in @categories + $bigdebug and warn "Skipping borrower from category " . $borrower->{categorycode} if none { $borrower->{categorycode} eq $_ } @categories; + next if none { $borrower->{categorycode} eq $_ } @categories; + + my $branchcode = + ( $useborrowerlibrary ) ? $borrower->{branchcode} + : ( $control eq 'ItemHomeLibrary' ) ? $data->[$i]->{homebranch} + : ( $control eq 'PatronLibrary' ) ? $borrower->{branchcode} + : $data->[$i]->{branchcode}; + # In final case, CircControl must be PickupLibrary. (branchcode comes from issues table here). + + # Skipping branchcodes that are not in @libraries + $bigdebug and warn "Skipping library $branchcode" if none { $branchcode eq $_ } @libraries; + next if none { $branchcode eq $_ } @libraries; + + my $calendar; + unless ( defined( $calendars{$branchcode} ) ) { + $calendars{$branchcode} = C4::Calendar->new( branchcode => $branchcode ); + } + $calendar = $calendars{$branchcode}; + my $isHoliday = $calendar->isHoliday( split '/', $today->output('metric') ); + + # Reassing datedue_days if -delay specified in commandline + $bigdebug and warn "Using commandline supplied delay : $delay" if ($delay); + $datedue_days += $delay if ($delay); + + ( $datedue_days <= $today_days ) or next; # or it's not overdue, right? + + $overdueItemsCounted++; + my ( $amount, $type, $daycounttotal, $daycount ) = CalcFine( $data->[$i], $borrower->{'categorycode'}, $branchcode, undef, undef, $datedue, $today ); + + # Reassign fine's amount if specified in command-line + $amount = $catamounts{$borrower->{'categorycode'}} if (defined $catamounts{$borrower->{'categorycode'}}); + + # FIXME: $type NEVER gets populated by anything. + ( defined $type ) or $type = ''; + + + # 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' and !$borrowersalreadyapplied->{$data->[$i]->{'borrowernumber'}}) { + # If we're on a holiday, warn the user (if debug) that no fine will be applied + if($isHoliday) { + $debug and warn "Today is a holiday. The fine for borrower " . $data->[$i]->{'borrowernumber'} . " will not be applied"; + } else { + $debug and warn "Updating fine for borrower " . $data->[$i]->{'borrowernumber'} . " with amount : $amount"; + UpdateFine( $data->[$i]->{'itemnumber'}, $data->[$i]->{'borrowernumber'}, $amount, $type, $due_str ) if ( $amount > 0 ); + $borrowersalreadyapplied->{$data->[$i]->{'borrowernumber'}} = 1; + } + } + my @cells = (); + push @cells, map { $borrower->{$_} } @borrower_fields; + push @cells, map { $data->[$i]->{$_} } @item_fields; + push @cells, $type, $daycounttotal, $amount; + print FILE join( $delim, @cells ), "\n"; +} + +my $numOverdueItems = scalar(@$data); +if ($verbose) { + print <