Bug 13889: Add information about cron jobs to system log
[srvgit] / misc / cronjobs / longoverdue.pl
1 #!/usr/bin/perl
2 #-----------------------------------
3 # Copyright 2008 LibLime
4 #
5 # This file is part of Koha.
6 #
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.
11 #
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.
16 #
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>.
19 #-----------------------------------
20
21 =head1 NAME
22
23 longoverdue.pl  cron script to set lost statuses on overdue materials.
24                 Execute without options for help.
25
26 =cut
27
28 use strict;
29 use warnings;
30 BEGIN {
31     # find Koha's Perl modules
32     # test carefully before changing this
33     use FindBin;
34     eval { require "$FindBin::Bin/../kohalib.pl" };
35 }
36 use C4::Context;
37 use C4::Items;
38 use C4::Circulation qw/LostItem/;
39 use Getopt::Long;
40 use C4::Log;
41
42 my  $lost;  #  key=lost value,  value=num days.
43 my ($charge, $verbose, $confirm, $quiet);
44 my $endrange = 366;
45 my $mark_returned = 0;
46
47 GetOptions( 
48     'lost=s%'       => \$lost,
49     'c|charge=s'    => \$charge,
50     'confirm'       => \$confirm,
51     'verbose'       => \$verbose,
52     'quiet'         => \$quiet,
53     'maxdays=s'     => \$endrange,
54     'mark-returned' => \$mark_returned,
55 );
56
57 my $usage = << 'ENDUSAGE';
58 longoverdue.pl : This cron script set lost values on overdue items and optionally sets charges the patron's account
59 for the item's replacement price.  It is designed to be run as a nightly job.  The command line options that globally
60 define this behavior for this script  will likely be moved into Koha's core circulation / issuing rules code in a 
61 near-term release, so this script is not intended to have a long lifetime.  
62
63 This script takes the following parameters :
64
65     --lost | -l         This option takes the form of n=lv,
66                         where n is num days overdue, and lv is the lost value.  See warning below.
67
68     --charge | -c       This specifies what lost value triggers Koha to charge the account for the
69                         lost item.  Replacement costs are not charged if this is not specified.
70
71     --verbose | v       verbose.
72
73     --confirm           confirm.  without this option, the script will report the number of affected items and
74                         return without modifying any records.
75
76     --quiet             suppress summary output.
77
78     --maxdays           Specifies the end of the range of overdue days to deal with (defaults to 366).  This
79                         value is universal to all lost num days overdue passed.
80
81     --mark-returned     When an item is marked lost, remove it from the borrowers issued items.
82
83   examples :
84   $PERL5LIB/misc/cronjobs/longoverdue.pl --lost 30=1
85     Would set LOST=1 after 30 days (up to one year), but not charge the account.
86     This would be suitable for the Koha default LOST authorized value of 1 -> 'Lost'.
87
88   $PERL5LIB/misc/cronjobs/longoverdue.pl --lost 60=2 --charge 2
89     Would set LOST=2 after 60 days (up to one year), and charge the account when setting LOST=2.
90     This would be suitable for the Koha default LOST authorized value of 2 -> 'Long Overdue' 
91
92 WARNING:  Flippant use of this script could set all or most of the items in your catalog to Lost and charge your
93 patrons for them!
94
95 WARNING:  This script is known to be faulty.  It is NOT recommended to use multiple --lost options.
96           See http://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=2883
97
98 ENDUSAGE
99
100 # FIXME: We need three pieces of data to operate:
101 #         ~ lower bound (number of days),
102 #         ~ upper bound (number of days),
103 #         ~ new lost value.
104 #        Right now we get only two, causing the endrange hack.  This is a design-level failure.
105 # FIXME: do checks on --lost ranges to make sure they are exclusive.
106 # FIXME: do checks on --lost ranges to make sure the authorized values exist.
107 # FIXME: do checks on --lost ranges to make sure don't go past endrange.
108 # FIXME: convert to using pod2usage
109 # FIXME: allow --help or -h
110
111 if ( ! defined($lost) ) {
112     my $longoverdue_value = C4::Context->preference('DefaultLongOverdueLostValue');
113     my $longoverdue_days = C4::Context->preference('DefaultLongOverdueDays');
114     if(defined($longoverdue_value) and defined($longoverdue_days) and $longoverdue_value ne '' and $longoverdue_days ne '' and $longoverdue_days >= 0) {
115         $lost->{$longoverdue_days} = $longoverdue_value;
116     }
117     else {
118         print $usage;
119         die "ERROR: No --lost (-l) option defined";
120     }
121 }
122 if ( ! defined($charge) ) {
123     my $charge_value = C4::Context->preference('DefaultLongOverdueChargeValue');
124     if(defined($charge_value) and $charge_value ne '') {
125         $charge = $charge_value;
126     }
127 }
128 unless ($confirm) {
129     $verbose = 1;     # If you're not running it for real, then the whole point is the print output.
130     print "### TEST MODE -- NO ACTIONS TAKEN ###\n";
131 }
132
133 cronlogaction();
134
135 # In my opinion, this line is safe SQL to have outside the API. --atz
136 our $bounds_sth = C4::Context->dbh->prepare("SELECT DATE_SUB(CURDATE(), INTERVAL ? DAY)");
137
138 sub bounds ($) {
139     $bounds_sth->execute(shift);
140     return $bounds_sth->fetchrow;
141 }
142
143 # FIXME - This sql should be inside the API.
144 sub longoverdue_sth {
145     my $query = "
146     SELECT items.itemnumber, borrowernumber, date_due
147       FROM issues, items
148      WHERE items.itemnumber = issues.itemnumber
149       AND  DATE_SUB(CURDATE(), INTERVAL ? DAY)  > date_due
150       AND  DATE_SUB(CURDATE(), INTERVAL ? DAY) <= date_due
151       AND  itemlost <> ?
152      ORDER BY date_due
153     ";
154     return C4::Context->dbh->prepare($query);
155 }
156
157 #FIXME - Should add a 'system' user and get suitable userenv for it for logging, etc.
158
159 my $count;
160 # my @ranges = map { 
161 my @report;
162 my $total = 0;
163 my $i = 0;
164
165 # FIXME - The item is only marked returned if you supply --charge .
166 #         We need a better way to handle this.
167 #
168 my $sth_items = longoverdue_sth();
169
170 foreach my $startrange (sort keys %$lost) {
171     if( my $lostvalue = $lost->{$startrange} ) {
172         my ($date1) = bounds($startrange);
173         my ($date2) = bounds(  $endrange);
174         # print "\nRange ", ++$i, "\nDue $startrange - $endrange days ago ($date2 to $date1), lost => $lostvalue\n" if($verbose);
175         $verbose and 
176             printf "\nRange %s\nDue %3s - %3s days ago (%s to %s), lost => %s\n", ++$i,
177             $startrange, $endrange, $date2, $date1, $lostvalue;
178         $sth_items->execute($startrange, $endrange, $lostvalue);
179         $count=0;
180         while (my $row=$sth_items->fetchrow_hashref) {
181             printf ("Due %s: item %5s from borrower %5s to lost: %s\n", $row->{date_due}, $row->{itemnumber}, $row->{borrowernumber}, $lostvalue) if($verbose);
182             if($confirm) {
183                 ModItem({ itemlost => $lostvalue }, $row->{'biblionumber'}, $row->{'itemnumber'});
184                 LostItem($row->{'itemnumber'}, $mark_returned) if( $charge && $charge eq $lostvalue);
185             }
186             $count++;
187         }
188         push @report, {
189            startrange => $startrange,
190              endrange => $endrange,
191                 range => "$startrange - $endrange",
192                 date1 => $date1,
193                 date2 => $date2,
194             lostvalue => $lostvalue,
195                 count => $count,
196         };
197         $total += $count;
198     }
199     $endrange = $startrange;
200 }
201
202 sub summarize ($$) {
203     my $arg = shift;    # ref to array
204     my $got_items = shift || 0;     # print "count" line for items
205     my @report = @$arg or return undef;
206     my $i = 0;
207     for my $range (@report) {
208         printf "\nRange %s\nDue %3s - %3s days ago (%s to %s), lost => %s\n", ++$i,
209             map {$range->{$_}} qw(startrange endrange date2 date1 lostvalue);
210         $got_items and printf "  %4s items\n", $range->{count};
211     }
212 }
213
214 if (!$quiet){
215     print "\n### LONGOVERDUE SUMMARY ###";
216     summarize (\@report, 1);
217     print "\nTOTAL: $total items\n";
218 }