A new script to check URLs in 856$u field
[koha.git] / misc / cronjobs / advance_notices.pl
1 #!/usr/bin/perl -w
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 with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA  02111-1307 USA
19
20 =head1 NAME
21
22 advance_notices.pl - cron script to put item due reminders into message queue
23
24 =head1 SYNOPSIS
25
26 ./advance_notices.pl -c
27
28 or, in crontab:
29 0 1 * * * advance_notices.pl -c
30
31 =head1 DESCRIPTION
32
33 This script prepares pre-due and item due reminders to be sent to
34 patrons. It queues them in the message queue, which is processed by
35 the process_message_queue.pl cronjob. The type and timing of the
36 messages can be configured by the patrons in their "My Alerts" tab in
37 the OPAC.
38
39 =cut
40
41 use strict;
42 use warnings;
43 use Getopt::Long;
44 use Data::Dumper;
45 BEGIN {
46     # find Koha's Perl modules
47     # test carefully before changing this
48     use FindBin;
49     eval { require "$FindBin::Bin/../kohalib.pl" };
50 }
51 use C4::Biblio;
52 use C4::Context;
53 use C4::Letters;
54 use C4::Members;
55 use C4::Members::Messaging;
56 use C4::Overdues;
57
58
59 # These are defaults for command line options.
60 my $confirm;                                                        # -c: Confirm that the user has read and configured this script.
61 # my $confirm     = 1;                                                # -c: Confirm that the user has read and configured this script.
62 my $nomail;                                                         # -n: No mail. Will not send any emails.
63 my $mindays     = 0;                                                # -m: Maximum number of days in advance to send notices
64 my $maxdays     = 30;                                               # -e: the End of the time period
65 my $fromaddress = C4::Context->preference('KohaAdminEmailAddress'); # -f: From address for the emails
66 my $verbose     = 0;                                                # -v: verbose
67
68 GetOptions( 'c'    => \$confirm,
69             'n'    => \$nomail,
70             'm:i'  => \$maxdays,
71             'f:s'  => \$fromaddress,
72             'v'    => \$verbose,
73        );
74 my $usage = << 'ENDUSAGE';
75
76 This script prepares pre-due and item due reminders to be sent to
77 patrons. It queues them in the message queue, which is processed by
78 the process_message_queue.pl cronjob.
79 See the comments in the script for directions on changing the script.
80 This script has the following parameters :
81         -c Confirm and remove this help & warning
82         -m maximum number of days in advance to send advance notices.
83         -f from address for the emails. Defaults to KohaAdminEmailAddress system preference
84         -n send No mail. Instead, all mail messages are printed on screen. Usefull for testing purposes.
85         -v verbose
86
87 ENDUSAGE
88
89 # Since advance notice options are not visible in the web-interface
90 # unless EnhancedMessagingPreferences is on, let the user know that
91 # this script probably isn't going to do much
92 if ( ! C4::Context->preference('EnhancedMessagingPreferences') ) {
93     warn <<'END_WARN';
94
95 The "EnhancedMessagingPreferences" syspref is off.
96 Therefore, it is unlikely that this script will actually produce any messages to be sent.
97 To change this, edit the "EnhancedMessagingPreferences" syspref.
98
99 END_WARN
100 }
101
102 unless ($confirm) {
103     print $usage;
104     print "Do you wish to continue? (y/n)";
105     chomp($_ = <STDIN>);
106     exit unless (/^y/i);
107         
108 }
109
110
111 warn 'getting upcoming due issues' if $verbose;
112 my $upcoming_dues = C4::Circulation::GetUpcomingDueIssues( { days_in_advance => $maxdays } );
113 warn 'found ' . scalar( @$upcoming_dues ) . ' issues' if $verbose;
114
115 # hash of borrowernumber to number of items upcoming
116 # for patrons wishing digests only.
117 my $upcoming_digest;
118 my $due_digest;
119
120 UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) {
121     warn 'examining ' . $upcoming->{'itemnumber'} . ' upcoming due items' if $verbose;
122     # warn( Data::Dumper->Dump( [ $upcoming ], [ 'overdue' ] ) );
123     
124     my $letter;
125     my $borrower_preferences;
126     if ( 0 == $upcoming->{'days_until_due'} ) {
127         # This item is due today. Send an 'item due' message.
128         $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $upcoming->{'borrowernumber'},
129                                                                                    message_name   => 'item due' } );
130         # warn( Data::Dumper->Dump( [ $borrower_preferences ], [ 'borrower_preferences' ] ) );
131         next DUEITEM unless $borrower_preferences;
132         
133         if ( $borrower_preferences->{'wants_digest'} ) {
134             # cache this one to process after we've run through all of the items.
135             $due_digest->{$upcoming->{'borrowernumber'}}++;
136         } else {
137             my $biblio = C4::Biblio::GetBiblioFromItemNumber( $upcoming->{'itemnumber'} );
138             my $letter_type = 'DUE';
139             $letter = C4::Letters::getletter( 'circulation', $letter_type );
140             die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter;
141         
142             $letter = parse_letter( { letter         => $letter,
143                                       borrowernumber => $upcoming->{'borrowernumber'},
144                                       branchchode    => $upcoming->{'branchcode'},
145                                       biblionumber   => $biblio->{'biblionumber'} } );
146         }
147     } else {
148         $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $upcoming->{'borrowernumber'},
149                                                                                    message_name   => 'advance notice' } );
150         # warn( Data::Dumper->Dump( [ $borrower_preferences ], [ 'borrower_preferences' ] ) );
151         next UPCOMINGITEM unless $borrower_preferences && exists $borrower_preferences->{'days_in_advance'};
152         next UPCOMINGITEM unless $borrower_preferences->{'days_in_advance'} == $upcoming->{'days_until_due'};
153         
154         if ( $borrower_preferences->{'wants_digest'} ) {
155             # cache this one to process after we've run through all of the items.
156             $upcoming_digest->{$upcoming->{'borrowernumber'}}++;
157         } else {
158             my $biblio = C4::Biblio::GetBiblioFromItemNumber( $upcoming->{'itemnumber'} );
159             my $letter_type = 'PREDUE';
160             $letter = C4::Letters::getletter( 'circulation', $letter_type );
161             die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter;
162         
163             $letter = parse_letter( { letter         => $letter,
164                                       borrowernumber => $upcoming->{'borrowernumber'},
165                                       branchchode    => $upcoming->{'branchcode'},
166                                       biblionumber   => $biblio->{'biblionumber'} } );
167         }
168     }
169
170     # If we have prepared a letter, send it.
171     if ( $letter ) {
172         foreach my $transport ( @{$borrower_preferences->{'transports'}} ) {
173             C4::Letters::EnqueueLetter( { letter                 => $letter,
174                                           borrowernumber         => $upcoming->{'borrowernumber'},
175                                           message_transport_type => $transport } );
176         }
177     }
178     
179 }
180
181
182 # warn( Data::Dumper->Dump( [ $upcoming_digest ], [ 'upcoming_digest' ] ) );
183
184 # Now, run through all the people that want digests and send them
185 PATRON: while ( my ( $borrowernumber, $count ) = each %$upcoming_digest ) {
186     my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $borrowernumber,
187                                                                                   message_name   => 'advance notice' } );
188     # warn( Data::Dumper->Dump( [ $borrower_preferences ], [ 'borrower_preferences' ] ) );
189     next PATRON unless $borrower_preferences; # how could this happen?
190
191
192     my $letter_type = 'PREDUEDGST';
193     my $letter = C4::Letters::getletter( 'circulation', $letter_type );
194     die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter;
195     $letter = parse_letter( { letter         => $letter,
196                               borrowernumber => $borrowernumber,
197                               substitute     => { count => $count }
198                          } );
199
200     foreach my $transport ( @{$borrower_preferences->{'transports'}} ) {
201         C4::Letters::EnqueueLetter( { letter                 => $letter,
202                                       borrowernumber         => $borrowernumber,
203                                       message_transport_type => $transport } );
204     }
205 }
206
207 # Now, run through all the people that want digests and send them
208 PATRON: while ( my ( $borrowernumber, $count ) = each %$due_digest ) {
209     my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $borrowernumber,
210                                                                                   message_name   => 'item due' } );
211     # warn( Data::Dumper->Dump( [ $borrower_preferences ], [ 'borrower_preferences' ] ) );
212     next PATRON unless $borrower_preferences; # how could this happen?
213
214     my $letter_type = 'DUEDGST';
215     my $letter = C4::Letters::getletter( 'circulation', $letter_type );
216     die "no letter of type '$letter_type' found. Please see sample_notices.sql" unless $letter;
217     $letter = parse_letter( { letter         => $letter,
218                               borrowernumber => $borrowernumber,
219                               substitute     => { count => $count }
220                          } );
221
222     foreach my $transport ( @{$borrower_preferences->{'transports'}} ) {
223         C4::Letters::EnqueueLetter( { letter                 => $letter,
224                                       borrowernumber         => $borrowernumber,
225                                       message_transport_type => $transport } );
226     }
227 }
228
229 =head1 METHODS
230
231 =head2 parse_letter
232
233
234
235 =cut
236
237 sub parse_letter {
238     my $params = shift;
239     foreach my $required ( qw( letter borrowernumber ) ) {
240         return unless exists $params->{$required};
241     }
242
243     if ( $params->{'substitute'} ) {
244         while ( my ($key, $replacedby) = each %{$params->{'substitute'}} ) {
245             my $replacefield = "<<$key>>";
246             
247             $params->{'letter'}->{title}   =~ s/$replacefield/$replacedby/g;
248             $params->{'letter'}->{content} =~ s/$replacefield/$replacedby/g;
249         }
250     }
251
252     C4::Letters::parseletter( $params->{'letter'}, 'borrowers',   $params->{'borrowernumber'} );
253
254     if ( $params->{'branchcode'} ) {
255         C4::Letters::parseletter( $params->{'letter'}, 'branches',    $params->{'branchcode'} );
256     }
257     
258     if ( $params->{'biblionumber'} ) {
259         C4::Letters::parseletter( $params->{'letter'}, 'biblio',      $params->{'biblionumber'} );
260         C4::Letters::parseletter( $params->{'letter'}, 'biblioitems', $params->{'biblionumber'} );
261     }
262
263     return $params->{'letter'};
264 }
265
266 1;
267
268 __END__