Bug 5370: Fix references to koha.org and other old websites
[koha.git] / 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 under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
10 # version.
11 #
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License along
17 # with Koha; if not, write to the Free Software Foundation, Inc.,
18 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
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::Accounts;
39 use Getopt::Long;
40
41 my  $lost;  #  key=lost value,  value=num days.
42 my ($charge, $verbose, $confirm);
43 my $endrange = 366;  # FIXME hardcoded - don't deal with anything overdue by more than this num days.
44
45 GetOptions( 
46     'lost=s%'    => \$lost,
47     'c|charge=s' => \$charge,
48     'confirm'    => \$confirm,
49     'verbose'    => \$verbose,
50 );
51
52 my $usage = << 'ENDUSAGE';
53 longoverdue.pl : This cron script set lost values on overdue items and optionally sets charges the patron's account
54 for the item's replacement price.  It is designed to be run as a nightly job.  The command line options that globally
55 define this behavior for this script  will likely be moved into Koha's core circulation / issuing rules code in a 
56 near-term release, so this script is not intended to have a long lifetime.  
57
58 This script takes the following parameters :
59
60     --lost | -l         This option takes the form of n=lv,
61                         where n is num days overdue, and lv is the lost value.  See warning below.
62
63     --charge | -c       This specifies what lost value triggers Koha to charge the account for the
64                         lost item.  Replacement costs are not charged if this is not specified.
65
66     --verbose | v       verbose.
67
68     --confirm           confirm.  without this option, the script will report the number of affected items and
69                         return without modifying any records.
70
71   examples :
72   $PERL5LIB/misc/cronjobs/longoverdue.pl --lost 30=1
73     Would set LOST=1 after 30 days (up to one year), but not charge the account.
74     This would be suitable for the Koha default LOST authorized value of 1 -> 'Lost'.
75
76   $PERL5LIB/misc/cronjobs/longoverdue.pl --lost 60=2 --charge 1
77     Would set LOST=2 after 60 days (up to one year), and charge the account when setting LOST=2.
78     This would be suitable for the Koha default LOST authorized value of 2 -> 'Long Overdue' 
79
80 WARNING:  Flippant use of this script could set all or most of the items in your catalog to Lost and charge your
81 patrons for them!
82
83 WARNING:  This script is known to be faulty.  It is NOT recommended to use multiple --lost options.
84           See http://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=2883
85
86 ENDUSAGE
87
88 # FIXME: We need three pieces of data to operate:
89 #         ~ lower bound (number of days),
90 #         ~ upper bound (number of days),
91 #         ~ new lost value.
92 #        Right now we get only two, causing the endrange hack.  This is a design-level failure.
93 # FIXME: do checks on --lost ranges to make sure they are exclusive.
94 # FIXME: do checks on --lost ranges to make sure the authorized values exist.
95 # FIXME: do checks on --lost ranges to make sure don't go past endrange.
96 # FIXME: convert to using pod2usage
97 # FIXME: allow --help or -h
98
99 if ( ! defined($lost) ) {
100     print $usage;
101     die "ERROR: No --lost (-l) option defined";
102 }
103 unless ($confirm) {
104     $verbose = 1;     # If you're not running it for real, then the whole point is the print output.
105     print "### TEST MODE -- NO ACTIONS TAKEN ###\n";
106 }
107
108 # In my opinion, this line is safe SQL to have outside the API. --atz
109 our $bounds_sth = C4::Context->dbh->prepare("SELECT DATE_SUB(CURDATE(), INTERVAL ? DAY)");
110
111 sub bounds ($) {
112     $bounds_sth->execute(shift);
113     return $bounds_sth->fetchrow;
114 }
115
116 # FIXME - This sql should be inside the API.
117 sub longoverdue_sth {
118     my $query = "
119     SELECT items.itemnumber, borrowernumber, date_due
120       FROM issues, items
121      WHERE items.itemnumber = issues.itemnumber
122       AND  DATE_SUB(CURDATE(), INTERVAL ? DAY)  > date_due
123       AND  DATE_SUB(CURDATE(), INTERVAL ? DAY) <= date_due
124       AND  itemlost <> ?
125      ORDER BY date_due
126     ";
127     return C4::Context->dbh->prepare($query);
128 }
129
130 #FIXME - Should add a 'system' user and get suitable userenv for it for logging, etc.
131
132 my $count;
133 # my @ranges = map { 
134 my @report;
135 my $total = 0;
136 my $i = 0;
137
138 # FIXME - The item is only marked returned if you supply --charge .
139 #         We need a better way to handle this.
140 #
141 my $sth_items = longoverdue_sth();
142
143 foreach my $startrange (sort keys %$lost) {
144     if( my $lostvalue = $lost->{$startrange} ) {
145         my ($date1) = bounds($startrange);
146         my ($date2) = bounds(  $endrange);
147         # print "\nRange ", ++$i, "\nDue $startrange - $endrange days ago ($date2 to $date1), lost => $lostvalue\n" if($verbose);
148         $verbose and 
149             printf "\nRange %s\nDue %3s - %3s days ago (%s to %s), lost => %s\n", ++$i,
150             $startrange, $endrange, $date2, $date1, $lostvalue;
151         $sth_items->execute($startrange, $endrange, $lostvalue);
152         $count=0;
153         while (my $row=$sth_items->fetchrow_hashref) {
154             printf ("Due %s: item %5s from borrower %5s to lost: %s\n", $row->{date_due}, $row->{itemnumber}, $row->{borrowernumber}, $lostvalue) if($verbose);
155             if($confirm) {
156                 ModItem({ itemlost => $lostvalue }, $row->{'biblionumber'}, $row->{'itemnumber'});
157                 chargelostitem($row->{'itemnumber'}) if( $charge && $charge eq $lostvalue);
158             }
159             $count++;
160         }
161         push @report, {
162            startrange => $startrange,
163              endrange => $endrange,
164                 range => "$startrange - $endrange",
165                 date1 => $date1,
166                 date2 => $date2,
167             lostvalue => $lostvalue,
168                 count => $count,
169         };
170         $total += $count;
171     }
172     $endrange = $startrange;
173 }
174
175 sub summarize ($$) {
176     my $arg = shift;    # ref to array
177     my $got_items = shift || 0;     # print "count" line for items
178     my @report = @$arg or return undef;
179     my $i = 0;
180     for my $range (@report) {
181         printf "\nRange %s\nDue %3s - %3s days ago (%s to %s), lost => %s\n", ++$i,
182             map {$range->{$_}} qw(startrange endrange date2 date1 lostvalue);
183         $got_items and printf "  %4s items\n", $range->{count};
184     }
185 }
186
187 print "\n### LONGOVERDUE SUMMARY ###";
188 summarize (\@report, 1);
189 print "\nTOTAL: $total items\n";