Prevent fines failure on NULL borrowernumber.
[koha.git] / misc / cronjobs / fines.pl
1 #!/usr/bin/perl
2
3 #  This script loops through each overdue item, determines the fine,
4 #  and updates the total amount of fines due by each user.  It relies on
5 #  the existence of /tmp/fines, which is created by ???
6 # Doesnt really rely on it, it relys on being able to write to /tmp/
7 # It creates the fines file
8 #
9 #  This script is meant to be run nightly out of cron.
10
11 # Copyright 2000-2002 Katipo Communications
12 #
13 # This file is part of Koha.
14 #
15 # Koha is free software; you can redistribute it and/or modify it under the
16 # terms of the GNU General Public License as published by the Free Software
17 # Foundation; either version 2 of the License, or (at your option) any later
18 # version.
19 #
20 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
21 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
22 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
23 #
24 # You should have received a copy of the GNU General Public License along with
25 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
26 # Suite 330, Boston, MA  02111-1307 USA
27
28
29 # FIXME: use FinesMode as described or change syspref description
30 use strict;
31
32 BEGIN {
33     # find Koha's Perl modules
34     # test carefully before changing this
35     use FindBin;
36     eval { require "$FindBin::Bin/kohalib.pl" };
37 }
38
39 use Date::Calc qw/Date_to_Days/;
40
41 use C4::Context;
42 use C4::Circulation;
43 use C4::Overdues;
44 use C4::Calendar qw();  # don't need any exports from Calendar
45 use C4::Biblio;
46 use C4::Debug;  # supplying $debug and $cgi_debug
47
48 use vars qw(@borrower_fields @item_fields @other_fields);
49 use vars qw($fldir $libname $control $mode $delim $dbname $today $today_iso $today_days);
50 use vars qw($filename $summary);
51
52 CHECK {
53     @borrower_fields = qw(cardnumber categorycode surname firstname email phone address citystate);
54         @item_fields = qw(itemnumber barcode date_due);
55        @other_fields = qw(type days_overdue fine);
56     $libname = C4::Context->preference('LibraryName');
57     $control = C4::Context->preference('CircControl');
58     $mode    = C4::Context->preference('finesMode');
59     $dbname  = C4::Context->config('database');
60     $delim   = "\t"; # ?  C4::Context->preference('delimiter') || "\t";
61
62     $today = C4::Dates->new();
63     $today_iso = $today->output('iso');
64     $today_days = Date_to_Days(split(/-/,$today_iso));
65     $fldir = $ENV{TMPDIR} || "/tmp"; # TODO: use GetOpt
66     $filename = $dbname;
67     $filename =~ s/\W//;
68     $filename = $fldir . '/'. $filename . '_' .  $today_iso . ".log";
69     $summary = 1;  # TODO: use GetOpt
70 }
71
72 INIT {
73     $debug and print "Each line will contain the following fields:\n",
74         "From borrowers : ", join(', ', @borrower_fields), "\n",
75         "From items : ", join(', ', @item_fields), "\n",
76         "Per overdue: ", join(', ', @other_fields), "\n",
77         "Delimiter: '$delim'\n";
78 }
79
80 open (FILE, ">$filename") or die "Cannot write file $filename: $!";
81 print FILE join $delim, (@borrower_fields, @item_fields, @other_fields);
82 print FILE "\n";
83
84 my $data = Getoverdues();
85 my $overdueItemsCounted = 0;
86 my %calendars = ();
87
88 for (my $i=0; $i<scalar(@$data); $i++) {
89     my $datedue = C4::Dates->new($data->[$i]->{'date_due'},'iso');
90     my $datedue_days = Date_to_Days(split(/-/,$datedue->output('iso')));
91     my $due_str = $datedue->output();
92     unless (defined $data->[$i]->{'borrowernumber'}) {
93         print STDERR "ERROR in Getoverdues line $i: issues.borrowernumber IS NULL.  Repair 'issues' table now!  Skipping record.\n";
94         next;   # Note: this doesn't solve everything.  After NULL borrowernumber, multiple issues w/ real borrowernumbers can pile up.
95     }
96     my $borrower = BorType($data->[$i]->{'borrowernumber'});
97     my $branchcode = ($control eq 'ItemHomeLibrary') ? $data->[$i]->{homebranch} :
98                      ($control eq 'PatronLibrary'  ) ?   $borrower->{branchcode} :
99                                                        $data->[$i]->{branchcode} ;
100     # In final case, CircControl must be PickupLibrary. (branchcode comes from issues table here).
101     my $calendar;
102     unless (defined ($calendars{$branchcode})) {
103         $calendars{$branchcode} = C4::Calendar->new(branchcode => $branchcode);
104     }
105     $calendar = $calendars{$branchcode};
106     my $isHoliday = $calendar->isHoliday(split '/', $today->output('metric'));
107       
108     ($datedue_days <= $today_days) or next; # or it's not overdue, right?
109
110     $overdueItemsCounted++;
111     my ($amount,$type,$daycounttotal,$daycount)=
112                 CalcFine($data->[$i], $borrower->{'categorycode'}, $branchcode,undef,undef, $datedue, $today);
113         # FIXME: $type NEVER gets populated by anything.
114     (defined $type) or $type = '';
115         # Don't update the fine if today is a holiday.  
116         # This ensures that dropbox mode will remove the correct amount of fine.
117         if ($mode eq 'production' and  ! $isHoliday) {
118                 UpdateFine($data->[$i]->{'itemnumber'},$data->[$i]->{'borrowernumber'},$amount,$type,$due_str) if( $amount > 0 ) ;
119         }
120     my @cells = ();
121     push @cells, map {$borrower->{$_}} @borrower_fields;
122     push @cells, map {$data->[$i]->{$_}} @item_fields;
123     push @cells, $type, $daycounttotal, $amount;
124     print FILE join($delim, @cells), "\n";
125 }
126
127 my $numOverdueItems = scalar(@$data);
128 if ($summary) {
129    print <<EOM;
130 Fines assessment -- $today_iso -- Saved to $filename
131 Number of Overdue Items:
132      counted $overdueItemsCounted
133     reported $numOverdueItems
134
135 EOM
136 }
137
138 close FILE;