3 # Copyright 2008 LibLime
5 # This file is part of Koha.
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
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.
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
22 advance_notices.pl - cron script to put item due reminders into message queue
26 ./advance_notices.pl -c
29 0 1 * * * advance_notices.pl -c
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
46 # find Koha's Perl modules
47 # test carefully before changing this
49 eval { require "$FindBin::Bin/../kohalib.pl" };
55 use C4::Members::Messaging;
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
68 GetOptions( 'c' => \$confirm,
71 'f:s' => \$fromaddress,
74 my $usage = << 'ENDUSAGE';
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.
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') ) {
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.
104 print "Do you wish to continue? (y/n)";
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;
115 # hash of borrowernumber to number of items upcoming
116 # for patrons wishing digests only.
120 UPCOMINGITEM: foreach my $upcoming ( @$upcoming_dues ) {
121 warn 'examining ' . $upcoming->{'itemnumber'} . ' upcoming due items' if $verbose;
122 # warn( Data::Dumper->Dump( [ $upcoming ], [ 'overdue' ] ) );
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;
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'}}++;
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;
142 $letter = parse_letter( { letter => $letter,
143 borrowernumber => $upcoming->{'borrowernumber'},
144 branchcode => $upcoming->{'branchcode'},
145 biblionumber => $biblio->{'biblionumber'} } );
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'};
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'}}++;
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;
163 $letter = parse_letter( { letter => $letter,
164 borrowernumber => $upcoming->{'borrowernumber'},
165 branchcode => $upcoming->{'branchcode'},
166 biblionumber => $biblio->{'biblionumber'} } );
170 # If we have prepared a letter, send it.
172 foreach my $transport ( @{$borrower_preferences->{'transports'}} ) {
173 C4::Letters::EnqueueLetter( { letter => $letter,
174 borrowernumber => $upcoming->{'borrowernumber'},
175 message_transport_type => $transport } );
182 # warn( Data::Dumper->Dump( [ $upcoming_digest ], [ 'upcoming_digest' ] ) );
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?
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 }
200 foreach my $transport ( @{$borrower_preferences->{'transports'}} ) {
201 C4::Letters::EnqueueLetter( { letter => $letter,
202 borrowernumber => $borrowernumber,
203 message_transport_type => $transport } );
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?
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 }
222 foreach my $transport ( @{$borrower_preferences->{'transports'}} ) {
223 C4::Letters::EnqueueLetter( { letter => $letter,
224 borrowernumber => $borrowernumber,
225 message_transport_type => $transport } );
239 foreach my $required ( qw( letter borrowernumber ) ) {
240 return unless exists $params->{$required};
243 if ( $params->{'substitute'} ) {
244 while ( my ($key, $replacedby) = each %{$params->{'substitute'}} ) {
245 my $replacefield = "<<$key>>";
247 $params->{'letter'}->{title} =~ s/$replacefield/$replacedby/g;
248 $params->{'letter'}->{content} =~ s/$replacefield/$replacedby/g;
252 C4::Letters::parseletter( $params->{'letter'}, 'borrowers', $params->{'borrowernumber'} );
254 if ( $params->{'branchcode'} ) {
255 C4::Letters::parseletter( $params->{'letter'}, 'branches', $params->{'branchcode'} );
258 if ( $params->{'biblionumber'} ) {
259 C4::Letters::parseletter( $params->{'letter'}, 'biblio', $params->{'biblionumber'} );
260 C4::Letters::parseletter( $params->{'letter'}, 'biblioitems', $params->{'biblionumber'} );
263 return $params->{'letter'};