Bug 16699: Move Swagger-related files to api/v1/swagger
[koha.git] / misc / cronjobs / thirdparty / TalkingTech_itiva_outbound.pl
blob1299b7d91b211831dbf1ffcfae046757685c4ff4
1 #!/usr/bin/perl
3 # Copyright (C) 2011 ByWater Solutions
5 # This file is part of Koha.
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.
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.
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>.
20 use strict;
21 use warnings;
23 BEGIN {
25 # find Koha's Perl modules
26 # test carefully before changing this
27 use FindBin;
28 eval { require "$FindBin::Bin/../kohalib.pl" };
31 use Getopt::Long;
32 use Pod::Usage;
34 use C4::Context;
35 use C4::Items;
36 use C4::Letters;
37 use C4::Overdues;
38 use Koha::Calendar;
39 use Koha::DateUtils;
41 sub usage {
42 pod2usage( -verbose => 2 );
43 exit;
46 die "TalkingTechItivaPhoneNotification system preference not activated... dying\n"
47 unless ( C4::Context->preference("TalkingTechItivaPhoneNotification") );
49 # Database handle
50 my $dbh = C4::Context->dbh;
52 # Options
53 my $verbose;
54 my $language = "EN";
55 my @types;
56 my @holds_waiting_days_to_call;
57 my $library_code;
58 my $help;
59 my $outfile;
61 # maps to convert I-tiva terms to Koha terms
62 my $type_module_map = {
63 'PREOVERDUE' => 'circulation',
64 'OVERDUE' => 'circulation',
65 'RESERVE' => 'reserves',
68 my $type_notice_map = {
69 'PREOVERDUE' => 'PREDUE',
70 'OVERDUE' => 'OVERDUE',
71 'RESERVE' => 'HOLD',
74 GetOptions(
75 'o|output:s' => \$outfile,
76 'v' => \$verbose,
77 'lang:s' => \$language,
78 'type:s' => \@types,
79 'w|waiting-hold-day:s' => \@holds_waiting_days_to_call,
80 'c|code|library-code:s' => \$library_code,
81 'help|h' => \$help,
84 $language = uc($language);
85 $library_code ||= '';
87 pod2usage( -verbose => 1 ) if $help;
89 # output log or STDOUT
90 my $OUT;
91 if ( defined $outfile ) {
92 open( $OUT, '>', "$outfile" ) || die("Cannot open output file");
93 } else {
94 print "No output file defined; printing to STDOUT\n"
95 if ( defined $verbose );
96 open( $OUT, '>', "&STDOUT" ) || die("Couldn't duplicate STDOUT: $!");
99 my $format = 'V'; # format for phone notifications
101 foreach my $type (@types) {
102 $type = uc($type); #just in case lower or mixed-case was supplied
103 my $module = $type_module_map->{$type}; #since the module is required to get the letter
104 my $code = $type_notice_map->{$type}; #to get the Koha name of the notice
106 my @loop;
107 if ( $type eq 'OVERDUE' ) {
108 @loop = GetOverdueIssues();
109 } elsif ( $type eq 'PREOVERDUE' ) {
110 @loop = GetPredueIssues();
111 } elsif ( $type eq 'RESERVE' ) {
112 @loop = GetWaitingHolds();
113 } else {
114 print "Unknown or unsupported message type $type; skipping...\n"
115 if ( defined $verbose );
116 next;
119 foreach my $issues (@loop) {
120 my $date_dt = dt_from_string ( $issues->{'date_due'} );
121 my $due_date = output_pref( { dt => $date_dt, dateonly => 1, dateformat =>'metric' } );
123 my $letter = C4::Letters::GetPreparedLetter(
124 module => $module,
125 letter_code => $code,
126 tables => {
127 borrowers => $issues->{'borrowernumber'},
128 biblio => $issues->{'biblionumber'},
129 biblioitems => $issues->{'biblionumber'},
131 message_transport_type => 'phone',
134 die "No letter found for type $type!... dying\n" unless $letter;
136 my $message_id = 0;
137 if ($outfile) {
138 $message_id = C4::Letters::EnqueueLetter(
139 { letter => $letter,
140 borrowernumber => $issues->{'borrowernumber'},
141 message_transport_type => 'phone',
146 print $OUT "\"$format\",\"$language\",\"$type\",\"$issues->{level}\",\"$issues->{cardnumber}\",\"$issues->{patron_title}\",\"$issues->{firstname}\",";
147 print $OUT "\"$issues->{surname}\",\"$issues->{phone}\",\"$issues->{email}\",\"$library_code\",";
148 print $OUT "\"$issues->{site}\",\"$issues->{site_name}\",\"$issues->{barcode}\",\"$due_date\",\"$issues->{title}\",\"$message_id\"\n";
152 =head1 NAME
154 TalkingTech_itiva_outbound.pl
156 =head1 SYNOPSIS
158 TalkingTech_itiva_outbound.pl
159 TalkingTech_itiva_outbound.pl --type=OVERDUE -w 0 -w 2 -w 6 --output=/tmp/talkingtech/outbound.csv
160 TalkingTech_itiva_outbound.pl --type=RESERVE --type=PREOVERDUE --lang=FR
163 Script to generate Spec C outbound notifications file for Talking Tech i-tiva
164 phone notification system.
166 =over
168 =item B<--help> B<-h>
170 Prints this help
172 =item B<-v>
174 Provide verbose log information.
176 =item B<--output> B<-o>
178 Destination for outbound notifications file (CSV format). If no value is specified,
179 output is dumped to screen.
181 =item B<--lang>
183 Sets the language for all outbound messages. Currently supported values are EN, FR and ES.
184 If no value is specified, EN will be used by default.
186 =item B<--type>
188 REQUIRED. Sets which messaging types are to be used. Can be given multiple times, to
189 specify multiple types in a single output file. Currently supported values are RESERVE, PREOVERDUE
190 and OVERDUE. If no value is given, this script will not produce any outbound notifications.
192 =item B<--waiting-hold-day> B<-w>
194 OPTIONAL for --type=RESERVE. Sets the days after a hold has been set to waiting on which to call. Use
195 switch as many times as desired. For example, passing "-w 0 -w 2 -w 6" will cause calls to be placed
196 on the day the hold was set to waiting, 2 days after the waiting date, and 6 days after. See example above.
197 If this switch is not used with --type=RESERVE, calls will be placed every day until the waiting reserve
198 is picked up or canceled.
200 =item B<--library-code> B<--code> B<-c>
202 OPTIONAL
203 The code of the source library of the message.
204 The library code is used to group notices together for
205 consortium purposes and apply library specific settings, such as
206 prompts, to those notices.
207 This field can be blank if all messages are from a single library.
209 =back
211 =cut
213 sub GetOverdueIssues {
214 my $query = "SELECT borrowers.borrowernumber, borrowers.cardnumber, borrowers.title as patron_title, borrowers.firstname, borrowers.surname,
215 borrowers.phone, borrowers.email, borrowers.branchcode, biblio.biblionumber, biblio.title, items.barcode, issues.date_due,
216 max(overduerules.branchcode) as rulebranch, TO_DAYS(NOW())-TO_DAYS(date_due) as daysoverdue, delay1, delay2, delay3,
217 issues.branchcode as site, branches.branchname as site_name
218 FROM borrowers JOIN issues USING (borrowernumber)
219 JOIN items USING (itemnumber)
220 JOIN biblio USING (biblionumber)
221 JOIN branches ON (issues.branchcode = branches.branchcode)
222 JOIN overduerules USING (categorycode)
223 WHERE ( overduerules.branchcode = borrowers.branchcode or overduerules.branchcode = '')
224 AND ( (TO_DAYS(NOW())-TO_DAYS(date_due) ) = delay1
225 OR (TO_DAYS(NOW())-TO_DAYS(date_due) ) = delay2
226 OR (TO_DAYS(NOW())-TO_DAYS(date_due) ) = delay3 )
227 GROUP BY items.itemnumber
229 my $sth = $dbh->prepare($query);
230 $sth->execute();
231 my @results;
232 while ( my $issue = $sth->fetchrow_hashref() ) {
233 if ( $issue->{'daysoverdue'} == $issue->{'delay1'} ) {
234 $issue->{'level'} = 1;
235 } elsif ( $issue->{'daysoverdue'} == $issue->{'delay2'} ) {
236 $issue->{'level'} = 2;
237 } elsif ( $issue->{'daysoverdue'} == $issue->{'delay3'} ) {
238 $issue->{'level'} = 3;
239 } else {
241 # this shouldn't ever happen, based our SQL criteria
243 push @results, $issue;
245 return @results;
248 sub GetPredueIssues {
249 my $query = "SELECT borrowers.borrowernumber, borrowers.cardnumber, borrowers.title as patron_title, borrowers.firstname, borrowers.surname,
250 borrowers.phone, borrowers.email, borrowers.branchcode, biblio.biblionumber, biblio.title, items.barcode, issues.date_due,
251 issues.branchcode as site, branches.branchname as site_name
252 FROM borrowers JOIN issues USING (borrowernumber)
253 JOIN items USING (itemnumber)
254 JOIN biblio USING (biblionumber)
255 JOIN branches ON (issues.branchcode = branches.branchcode)
256 JOIN borrower_message_preferences USING (borrowernumber)
257 JOIN borrower_message_transport_preferences USING (borrower_message_preference_id)
258 JOIN message_attributes USING (message_attribute_id)
259 WHERE ( TO_DAYS( date_due ) - TO_DAYS( NOW() ) ) = days_in_advance
260 AND message_transport_type = 'phone'
261 AND message_name = 'Advance_Notice'
263 my $sth = $dbh->prepare($query);
264 $sth->execute();
265 my @results;
266 while ( my $issue = $sth->fetchrow_hashref() ) {
267 $issue->{'level'} = 1; # only one level for Predue notifications
268 push @results, $issue;
270 return @results;
273 sub GetWaitingHolds {
274 my $query = "SELECT borrowers.borrowernumber, borrowers.cardnumber, borrowers.title as patron_title, borrowers.firstname, borrowers.surname,
275 borrowers.phone, borrowers.email, borrowers.branchcode, biblio.biblionumber, biblio.title, items.barcode, reserves.waitingdate,
276 reserves.branchcode AS site, branches.branchname AS site_name,
277 TO_DAYS(NOW())-TO_DAYS(reserves.waitingdate) AS days_since_waiting
278 FROM borrowers JOIN reserves USING (borrowernumber)
279 JOIN items USING (itemnumber)
280 JOIN biblio ON (biblio.biblionumber = items.biblionumber)
281 JOIN branches ON (reserves.branchcode = branches.branchcode)
282 JOIN borrower_message_preferences USING (borrowernumber)
283 JOIN borrower_message_transport_preferences USING (borrower_message_preference_id)
284 JOIN message_attributes USING (message_attribute_id)
285 WHERE ( reserves.found = 'W' )
286 AND message_transport_type = 'phone'
287 AND message_name = 'Hold_Filled'
289 my $pickupdelay = C4::Context->preference("ReservesMaxPickUpDelay");
290 my $sth = $dbh->prepare($query);
291 $sth->execute();
292 my @results;
293 while ( my $issue = $sth->fetchrow_hashref() ) {
294 my $calendar = Koha::Calendar->new( branchcode => $issue->{'site'} );
296 my $waiting_date = dt_from_string( $issue->{waitingdate}, 'sql' );
297 my $pickup_date = $waiting_date->clone->add( days => $pickupdelay );
298 if ( $calendar->is_holiday($pickup_date) ) {
299 $pickup_date = $calendar->next_open_day( $pickup_date );
302 $issue->{'date_due'} = output_pref({dt => $pickup_date, dateformat => 'iso' });
303 $issue->{'level'} = 1; # only one level for Hold Waiting notifications
305 my $days_to_subtract = 0;
306 if ( $calendar->is_holiday($waiting_date) ) {
307 my $next_open_day = $calendar->next_open_day( $waiting_date );
308 $days_to_subtract = $calendar->days_between($waiting_date, $next_open_day)->days;
311 $issue->{'days_since_waiting'} = $issue->{'days_since_waiting'} - $days_to_subtract;
313 if ( ( grep $_ eq $issue->{'days_since_waiting'}, @holds_waiting_days_to_call )
314 || !scalar(@holds_waiting_days_to_call) ) {
315 push @results, $issue;
318 return @results;