[open-ils-commits] r351 - in grpl/trunk: . patron_notifications patron_notifications/tadl-egnotify-scripts_20090306 patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var/lib patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var/lib/asterisk patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var/lib/asterisk/agi-bin patron_notifications/tadl-egnotify-scripts_20090306/evergreen-server patron_notifications/tadl-egnotify-scripts_20090306/notify-box patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin patron_notifications/tadl-egnotify-scripts_20090306/notify-box/root patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk (dkyle)
svn at svn.open-ils.org
svn at svn.open-ils.org
Fri Apr 17 15:42:06 EDT 2009
Author: dkyle
Date: 2009-04-17 15:42:02 -0400 (Fri, 17 Apr 2009)
New Revision: 351
Added:
grpl/trunk/patron_notifications/
grpl/trunk/patron_notifications/README
grpl/trunk/patron_notifications/do_holdshelf.plx
grpl/trunk/patron_notifications/do_overdues.plx
grpl/trunk/patron_notifications/extensions.conf
grpl/trunk/patron_notifications/grpl_courtesy.pl
grpl/trunk/patron_notifications/grpl_courtesy.sh
grpl/trunk/patron_notifications/grpl_courtesy_email
grpl/trunk/patron_notifications/grpl_holdnotice.cgi
grpl/trunk/patron_notifications/grpl_holdshelf.cgi
grpl/trunk/patron_notifications/grpl_overdue.pl
grpl/trunk/patron_notifications/grpl_overdue.sh
grpl/trunk/patron_notifications/grpl_overdue_email
grpl/trunk/patron_notifications/holdshelf-result.pl
grpl/trunk/patron_notifications/import_holdshelf.plx
grpl/trunk/patron_notifications/make_holdshelf_callfiles.plx
grpl/trunk/patron_notifications/make_overdue_callfiles.plx
grpl/trunk/patron_notifications/overdue-result.pl
grpl/trunk/patron_notifications/send_holdshelf_emails.plx
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/README-TADL.txt
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/asterisk.conf
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/cdr.conf
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/cdr_pgsql.conf
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/extensions.conf
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/features.conf
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/modules.conf
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/sip.conf
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/queue-feeder.pl
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var/lib/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var/lib/asterisk/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var/lib/asterisk/agi-bin/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var/lib/asterisk/agi-bin/holdshelf-result.pl
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/evergreen-server/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/evergreen-server/tadl_holdnotice.cgi
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/evergreen-server/tadl_holdshelf_all.cgi
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/holdshelf-schema.mysqldump
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/email-overdues.py
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/import-notices.py
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/xml2obj.py
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/noticeitems-schema.txt
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/root/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/root/import_holdshelf_all.plx
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/root/send_holdshelf_emails.plx
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk/holdshelf_template
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk/make_holdshelf_callfiles.plx
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk/tmp/
grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/overdues-sample.xml
Log:
patron notifications
Added: grpl/trunk/patron_notifications/README
===================================================================
--- grpl/trunk/patron_notifications/README (rev 0)
+++ grpl/trunk/patron_notifications/README 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,81 @@
+The basic idea when I started this project was to run a VM as an Evergreen notification server, seperate from our production Evergreen cluster.
+I planned to originate all email and phone notifications from this notification server, pulling the pertinent data from EG via remote calls
+to perl scripts on the cluster, storing the data, when needed, in a local database, and generating all my messages from there, although I
+wound up sending overdue and courtesy emails from the cluster since it was so easy to use the provided eg_gen_overdue files for that.
+
+EG cluster <------> Notification Server <----> Asterisk and/or Email Server
+ ^ |
+ |______________________________________________
+
+These files are provided as an Example Only of one way to approach Evergreen notifications, and were written for EG 1.2.x. There are hard coded
+references to our branches, policies, brand of telelphony cards, number of channels, etc.
+
+The process goes like this:
+Every morning the notifications server
+ deletes left over tmp(call) files from previous day
+ pulls "holds ready for pickup" info from Evergreen and inserts that info into a local DB (these files are written for mysql)
+ generates asterisk call files for holds from the local db
+ generates asterisk call files for overdues from the local db
+ (the overdue info is inserted via remote DBI connection from a script running on Evergreen)
+ copies call files to an Asterisk server
+ generates and send hold pickup emails from the local db
+The Asterisk server
+ runs programs that feed the call files into the outgoing queue
+ the calls trigger agi-bin scripts which create EG hold notification records and update the notifications server db
+
+
+** HOLD MESSAGES **
+on one of the EG cluster's HTTP servers:
+grpl_holdshelf.cgi (outputs EG data on holds ready for pickup, called from import_holdshelf.plx, via cron, on the notification server)
+grpl_holdnotice.cgi (adds a notification to a hold in EG, called from holdshelf-result.pl on the Asterisk serverm,
+ and from send_holdshelf_emails.plx on the notification server)
+
+on the Notification Server:
+import_holdshelf.plx (loads hold info from grpl_holdshelf.cgi into notify database, runs from cron)
+make_holdshelf_callfiles.plx (creates Asterisk call files from notify database, runs from cron)
+send_holdshelf_emails.plx (creates and sends emails from notify database, calls grpl_holdnotice.cgi, runs from cron)
+there are cron jobs to scp call files to the Asterisk server, and to clear the call file directory
+
+on the Asterisk Server
+holdshelf-result.pl (agi program that updates EG and notify database with call result, called from Asterisk dialplan)
+extensions.conf (Asterisk dialplan, we forego answering detection and play the message twice)
+do_holdshelf.plx (feeds call files to the Asterisk outgoing queue, Asterisk tends to choke if too many call files in the queue, runs from cron)
+there are cron jobs to kill asterisk in the evening and raise it in the morning.
+
+
+** OVERDUE MESSAGES **
+on one of the EG cluster's app servers:
+These files are modified from the eg_gen_overdue files provided in the EG distro support-scripts directory
+grpl_overdue.sh (args for the perl script, called from cron)
+grpl_overdue_email (message template)
+grpl_overdue.pl (pulls the overdues info from EG, sends emails, and inserts into the notify database on the notifications server)
+
+
+on the Notification Server:
+make_overdue_callfiles.plx (creates Asterisk call files from notify database, runs from cron)
+there are cron jobs to scp call files to the Asterisk server, and to clear the call file directory
+
+on the Asterisk Server
+overdue-result.pl (agi program that updates notify database with call result, called from Asterisk dialplan)
+extensions.conf (Asterisk dialplan, we forego answering detection and play the message twice)
+do_overdues.plx (feeds call files to the Asterisk outgoing queue, Asterisk tends to choke if too many call files in the queue, runs from cron)
+there are cron jobs to kill asterisk in the evening and raise it in the morning.
+
+
+** COURTESY MESSAGES **
+on one of the EG cluster's app servers:
+grpl_courtesy.sh (args for the perl script, called from cron)
+grpl_courtesy_email (message template)
+grpl_courtesy.pl (pulls the soon to be due info from EG and sends emails)
+
+
+----------------------------------------------------------
+Bill Ott wrote initial versions of the .cgi files
+
+Traverse Area Distric Library modified this work for their situation, those
+files are under the tadl-egnotify-scripts_20090306 directory.
+
+Doug Kyle
+Grand Rapids Public Library
+
+Questions to help at grpl dot org
Added: grpl/trunk/patron_notifications/do_holdshelf.plx
===================================================================
--- grpl/trunk/patron_notifications/do_holdshelf.plx (rev 0)
+++ grpl/trunk/patron_notifications/do_holdshelf.plx 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,28 @@
+#!/usr/bin/perl -w
+
+my @one = `grep -l Zap/1 /var/spool/asterisk/tmp/holdshelf/*`;
+my @two = `grep -l Zap/2 /var/spool/asterisk/tmp/holdshelf/*`;
+my @three = `grep -l Zap/3 /var/spool/asterisk/tmp/holdshelf/*`;
+
+map { chop } @one;
+map { chop } @two;
+map { chop } @three;
+my $z1 = 0;
+my $z2 = 0;
+my $z3 = 0;
+my $stop = 0;
+while ( ! $stop ) {
+ if ( ($one[$z1]) && !(`grep -l Zap/1 /var/spool/asterisk/outgoing/*`) ) { system ('mv', $one[$z1], '/var/spool/asterisk/outgoing'); $z1++; }
+ sleep 30;
+ if ( ($two[$z2]) && !(`grep -l Zap/2 /var/spool/asterisk/outgoing/*`) ) { system ('mv', $two[$z2], '/var/spool/asterisk/outgoing'); $z2++; }
+ sleep 30;
+ if ( ($three[$z3]) && !(`grep -l Zap/3 /var/spool/asterisk/outgoing/*`) ) { system ('mv', $three[$z3], '/var/spool/asterisk/outgoing'); $z3++; }
+ sleep 30;
+ $c++;
+ if ( !$one[$z1] && !$two[$z2] && !$three[$z3] ) {
+ $stop = 1;
+ }
+ sleep 30;
+}
+
+
Property changes on: grpl/trunk/patron_notifications/do_holdshelf.plx
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/do_overdues.plx
===================================================================
--- grpl/trunk/patron_notifications/do_overdues.plx (rev 0)
+++ grpl/trunk/patron_notifications/do_overdues.plx 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,28 @@
+#!/usr/bin/perl -w
+
+my @one = `grep -l Zap/1 /var/spool/asterisk/tmp/overdues/*`;
+my @two = `grep -l Zap/2 /var/spool/asterisk/tmp/overdues/*`;
+my @three = `grep -l Zap/3 /var/spool/asterisk/tmp/overdues/*`;
+my @four = `grep -l Zap/4 /var/spool/asterisk/tmp/overdues/*`;
+map { chop } @one;
+map { chop } @two;
+map { chop } @three;
+map { chop } @four;
+my $c = 0;
+my $stop = 0;
+while ( ! $stop ) {
+ if ($one[$c]) { system ('mv', $one[$c], '/var/spool/asterisk/outgoing') }
+ sleep 30;
+ if ($two[$c]) { system ('mv', $two[$c], '/var/spool/asterisk/outgoing') }
+ sleep 30;
+ if ($three[$c]) { system ('mv', $three[$c], '/var/spool/asterisk/outgoing') }
+ sleep 30;
+ if ($four[$c]) { system ('mv', $four[$c], '/var/spool/asterisk/outgoing') }
+ sleep 30;
+ $c++;
+ if ( !$one[$c] && !$two[$c] && !$three[$c] && !$four[$c] ) {
+ $stop = 1;
+ }
+ sleep 30;
+}
+
Property changes on: grpl/trunk/patron_notifications/do_overdues.plx
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/extensions.conf
===================================================================
--- grpl/trunk/patron_notifications/extensions.conf (rev 0)
+++ grpl/trunk/patron_notifications/extensions.conf 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,299 @@
+;!
+;! Automatically generated configuration file
+;! Filename: extensions.conf (/etc/asterisk/extensions.conf)
+;! Generator: Manager
+;! Creation Date: Mon Jun 2 12:03:36 2008
+;!
+
+[default]
+exten = s,1,Answer
+exten = s,n,AGI(festival-script.pl|This is the Grand Rapids Public Library\, you have items available for pick-up.)
+exten = s,n,Background(tt-thankyou)
+exten = s,n,AGI(record-result.pl|${CHANNEL}-${id})
+exten = s,n,Hangup
+exten = failed,1,AGI(record-result.pl|${CHANNEL}-${id})
+exten => 6001,2,Dial(zap3/1,15)
+
+[from-internal]
+include => record-outboundmsgs
+exten => 500,1,Verbose(1|Echo test application)
+exten => 500,n,Echo()
+exten => 500,n,Hangup()
+
+[holdshelfmsg]
+exten => s,1,Set(TIMEOUT(response)=5) ; Set Response Timeout to 10 seconds
+exten => s,2,Answer
+exten => s,3,Wait(1)
+exten => s,4,Background(outboundmsgs/holdshelfmsg1)
+exten => s,5,Background(outboundmsgs/${pickuplib})
+exten => s,6,Background(outboundmsgs/${pickuplib}-phone)
+exten => s,7,Background(outboundmsgs/holdshelfmsg1)
+exten => s,8,Background(outboundmsgs/${pickuplib})
+exten => s,9,Background(outboundmsgs/${pickuplib}-phone)
+exten => t,1,Playback(vm-goodbye)
+exten => t,2,AGI(holdshelf-result.pl|${CHANNEL}:${holdid}:${NumberDialed})
+exten => t,3,Hangup
+exten => h,1,DEADAGI(holdshelf-result.pl|${CHANNEL}:${holdid}:${NumberDialed})
+exten => failed,1,Set(NumberDialed=${CUT(PassedInfo,,1)})
+exten => failed,2,Set(CDR(userfield)=${NumberDialed})
+exten = failed,3,AGI(holdshelf-result.pl|${CHANNEL}:${holdid}:${NumberDialed})
+
+[overduemsg]
+exten => s,1,Answer
+exten => s,2,Wait(1)
+exten => s,3,Background(outboundmsgs/overduemsg1)
+exten => s,4,Background(outboundmsgs/GRPL-GR-phone)
+exten => s,5,Wait(3)
+exten => s,6,Background(outboundmsgs/overduemsg1)
+exten => s,7,Background(outboundmsgs/GRPL-GR-phone)
+exten => s,8,AGI(overdue-result.pl|${CHANNEL}:${odid})
+exten => s,9,Hangup
+exten = failed,1,AGI(overdue-result.pl|${CHANNEL}:${odid})
+
+[holdack]
+exten => s,1,Playback(outboundmsgs/thankyou)
+exten => s,2,Playback(vm-goodbye)
+exten => s,3,AGI(holdshelf-result.pl|${CHANNEL}:${holdid}:${NumberDialed}:ack)
+exten => s,4,Hangup
+
+
+[pickupmsg]
+exten => s,1,Set(TIMEOUT(digit)=5) ; Set Digit Timeout to 5 seconds
+exten => s,2,Set(TIMEOUT(response)=10) ; Set Response Timeout to 10 seconds
+exten => s,3,Answer
+exten => s,4,Wait(1)
+exten => s,5,Background(outboundmsgs/msg1) ; "play outbound msg"
+exten => s,6,Background(outboundmsgs/how_to_ack) ; "Press 1 to replay or 2 to acknowledge receiving this message"
+exten => 1,1,Goto(s,5) ; replay message
+exten => 2,1,Goto(msgack,s,1) ; acknowledge message
+exten => t,1,Playback(vm-goodbye)
+exten => t,2,Hangup
+; at this point we could do something like reschedule the call to try again later
+; or send an email saying the msg was not received,
+exten => failed,1,Set(NumberDialed=${CUT(PassedInfo,,1)})
+exten => failed,2,Set(CDR(userfield)=${NumberDialed})
+exten = failed,3,AGI(record-result.pl|${CHANNEL}-${id})
+
+[msgack]
+exten => s,1,Playback(outboundmsgs/thankyou)
+exten => s,2,Playback(vm-goodbye)
+; at this point we might want to log the message acknowledgement somewhere
+; and perhaps trigger some additional processing
+exten => s,3,AGI(record-result.pl|${CHANNEL}:${holdid}:ack)
+exten => s,4,Hangup
+
+[record-outboundmsgs]
+; Record voice files
+;
+; Before using this the first time
+; mkdir /var/lib/asterisk/sounds/outboundmsgs
+; chown asterisk_user:asterisk_user /var/lib/asterisk/sounds/outboundmsgs
+; (Where asterisk_user = the user that asterisk runs under: = root for many installations)
+;
+; In a context for incoming calls put something like
+; include => record-outboundmsgs
+;
+; Then call
+; 2051 to Record a new outbound msg1
+; 2052 to Record a new outbound holdshelfmsg1
+;
+; 2061 to Record the msg played when the recipient acks the message
+; 2062 to Record the "How to ACK message"
+;
+; After dialing one of the extensions above:
+; Wait for the record start tone
+; Record your message
+; Press # to stop recording
+; Listen to an automatic playback of your new message
+;
+; outbound msg1
+exten => 2051,1,Wait(2)
+exten => 2051,2,Record(outboundmsgs/msg1:gsm)
+exten => 2051,3,Wait(2)
+exten => 2051,4,Playback(outboundmsgs/msg1)
+exten => 2051,5,wait(2)
+exten => 2051,6,Hangup
+;
+; outbound holdshelfmsg1
+exten => 2052,1,Wait(2)
+exten => 2052,2,Record(outboundmsgs/holdshelfmsg1:gsm)
+exten => 2052,3,Wait(2)
+exten => 2052,4,Playback(outboundmsgs/holdshelfmsg1)
+exten => 2052,5,wait(2)
+exten => 2052,6,Hangup
+;
+; outbound overduemsg1
+exten => 2053,1,Wait(2)
+exten => 2053,2,Record(outboundmsgs/overduemsg1:gsm)
+exten => 2053,3,Wait(2)
+exten => 2053,4,Playback(outboundmsgs/overduemsg1)
+exten => 2053,5,wait(2)
+exten => 2053,6,Hangup
+;
+; Msg played when msg is acked
+exten => 2061,1,Wait(2)
+exten => 2061,2,Record(outboundmsgs/thankyou:gsm)
+exten => 2061,3,Wait(2)
+exten => 2061,4,Playback(outboundmsgs/thankyou)
+exten => 2061,5,wait(2)
+exten => 2061,6,Hangup
+;
+; Msg played after outbound msg: "Press 1 to replay or 2 to acknowledge receiving this message"
+exten => 2062,1,Wait(2)
+exten => 2062,2,Record(outboundmsgs/how_to_ack:gsm)
+exten => 2062,3,Wait(2)
+exten => 2062,4,Playback(outboundmsgs/how_to_ack)
+exten => 2062,5,wait(2)
+exten => 2062,6,Hangup
+;
+; main
+exten => 2071,1,Wait(2)
+exten => 2071,2,Record(outboundmsgs/GRPL-GR:gsm)
+exten => 2071,3,Wait(2)
+exten => 2071,4,Playback(outboundmsgs/GRPL-GR)
+exten => 2071,5,wait(2)
+exten => 2071,6,Hangup
+;
+; main phone
+exten => 2171,1,Wait(2)
+exten => 2171,2,Record(outboundmsgs/GRPL-GR-phone:gsm)
+exten => 2171,3,Wait(2)
+exten => 2171,4,Playback(outboundmsgs/GRPL-GR-phone)
+exten => 2171,5,wait(2)
+exten => 2171,6,Hangup
+;
+; madison
+exten => 2072,1,Wait(2)
+exten => 2072,2,Record(outboundmsgs/GRPL-GM:gsm)
+exten => 2072,3,Wait(2)
+exten => 2072,4,Playback(outboundmsgs/GRPL-GM)
+exten => 2072,5,wait(2)
+exten => 2072,6,Hangup
+;
+; madison phone
+exten => 2172,1,Wait(2)
+exten => 2172,2,Record(outboundmsgs/GRPL-GM-phone:gsm)
+exten => 2172,3,Wait(2)
+exten => 2172,4,Playback(outboundmsgs/GRPL-GM-phone)
+exten => 2172,5,wait(2)
+exten => 2172,6,Hangup
+;
+; ottawa
+exten => 2073,1,Wait(2)
+exten => 2073,2,Record(outboundmsgs/GRPL-GO:gsm)
+exten => 2073,3,Wait(2)
+exten => 2073,4,Playback(outboundmsgs/GRPL-GO)
+exten => 2073,5,wait(2)
+exten => 2073,6,Hangup
+;
+; ottawa phone
+exten => 2173,1,Wait(2)
+exten => 2173,2,Record(outboundmsgs/GRPL-GO-phone:gsm)
+exten => 2173,3,Wait(2)
+exten => 2173,4,Playback(outboundmsgs/GRPL-GO-phone)
+exten => 2173,5,wait(2)
+exten => 2173,6,Hangup
+;
+; seymour
+exten => 2074,1,Wait(2)
+exten => 2074,2,Record(outboundmsgs/GRPL-GS:gsm)
+exten => 2074,3,Wait(2)
+exten => 2074,4,Playback(outboundmsgs/GRPL-GS)
+exten => 2074,5,wait(2)
+exten => 2074,6,Hangup
+;
+; seymour phone
+exten => 2174,1,Wait(2)
+exten => 2174,2,Record(outboundmsgs/GRPL-GS-phone:gsm)
+exten => 2174,3,Wait(2)
+exten => 2174,4,Playback(outboundmsgs/GRPL-GS-phone)
+exten => 2174,5,wait(2)
+exten => 2174,6,Hangup
+;
+; vanbelkum
+exten => 2075,1,Wait(2)
+exten => 2075,2,Record(outboundmsgs/GRPL-GC:gsm)
+exten => 2075,3,Wait(2)
+exten => 2075,4,Playback(outboundmsgs/GRPL-GC)
+exten => 2075,5,wait(2)
+exten => 2075,6,Hangup
+;
+; vanbelkum phone
+exten => 2175,1,Wait(2)
+exten => 2175,2,Record(outboundmsgs/GRPL-GC-phone:gsm)
+exten => 2175,3,Wait(2)
+exten => 2175,4,Playback(outboundmsgs/GRPL-GC-phone)
+exten => 2175,5,wait(2)
+exten => 2175,6,Hangup
+;
+; wleonard
+exten => 2076,1,Wait(2)
+exten => 2076,2,Record(outboundmsgs/GRPL-GN:gsm)
+exten => 2076,3,Wait(2)
+exten => 2076,4,Playback(outboundmsgs/GRPL-GN)
+exten => 2076,5,wait(2)
+exten => 2076,6,Hangup
+;
+; wleonard phone
+exten => 2176,1,Wait(2)
+exten => 2176,2,Record(outboundmsgs/GRPL-GN-phone:gsm)
+exten => 2176,3,Wait(2)
+exten => 2176,4,Playback(outboundmsgs/GRPL-GN-phone)
+exten => 2176,5,wait(2)
+exten => 2176,6,Hangup
+;
+; westside
+exten => 2077,1,Wait(2)
+exten => 2077,2,Record(outboundmsgs/GRPL-GW:gsm)
+exten => 2077,3,Wait(2)
+exten => 2077,4,Playback(outboundmsgs/GRPL-GW)
+exten => 2077,5,wait(2)
+exten => 2077,6,Hangup
+;
+; westside phone
+exten => 2177,1,Wait(2)
+exten => 2177,2,Record(outboundmsgs/GRPL-GW-phone:gsm)
+exten => 2177,3,Wait(2)
+exten => 2177,4,Playback(outboundmsgs/GRPL-GW-phone)
+exten => 2177,5,wait(2)
+exten => 2177,6,Hangup
+;
+; yankee
+exten => 2078,1,Wait(2)
+exten => 2078,2,Record(outboundmsgs/GRPL-GY:gsm)
+exten => 2078,3,Wait(2)
+exten => 2078,4,Playback(outboundmsgs/GRPL-GY)
+exten => 2078,5,wait(2)
+exten => 2078,6,Hangup
+;
+; yankee phone
+exten => 2178,1,Wait(2)
+exten => 2178,2,Record(outboundmsgs/GRPL-GY-phone:gsm)
+exten => 2178,3,Wait(2)
+exten => 2178,4,Playback(outboundmsgs/GRPL-GY-phone)
+exten => 2178,5,wait(2)
+exten => 2178,6,Hangup
+;
+[asterisk_guitools]
+exten = executecommand,1,System(${command})
+exten = executecommand,n,Hangup()
+exten = record_vmenu,1,Answer
+exten = record_vmenu,n,Playback(vm-intro)
+exten = record_vmenu,n,Record(${var1})
+exten = record_vmenu,n,Playback(vm-saved)
+exten = record_vmenu,n,Playback(vm-goodbye)
+exten = record_vmenu,n,Hangup
+exten = play_file,1,Answer
+exten = play_file,n,Playback(${var1})
+exten = play_file,n,Hangup
+hasbeensetup = Y
+
+[numberplan-custom-1]
+plancomment = DialPlan1
+include = default
+include = parkedcalls
+
+[timebasedrules]
+
+[DID_trunk_2]
+include = default
Added: grpl/trunk/patron_notifications/grpl_courtesy.pl
===================================================================
--- grpl/trunk/patron_notifications/grpl_courtesy.pl (rev 0)
+++ grpl/trunk/patron_notifications/grpl_courtesy.pl 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,555 @@
+#!/usr/bin/perl
+# ---------------------------------------------------------------
+# Generates the overdue notices XML file
+# ./eg_gen_overdue.pl <bootstap> 0
+# generates today's notices
+# ./eg_gen_overdue.pl <bootstap> 1 0
+# generates notices for today - 1 and today
+# ./eg_gen_overdue.pl <bootstap> 2 1 0
+# ./eg_gen_overdue.pl <bootstap> 3 2 1 0 etc...
+# ---------------------------------------------------------------
+
+
+
+use strict; use warnings;
+require '/openils/src/Evergreen-ILS-1.2.2.3/Open-ILS/src/support-scripts/oils_header.pl';
+use vars qw/$logger $apputils/;
+use Data::Dumper;
+use OpenILS::Const qw/:const/;
+use OpenILS::Application::AppUtils;
+use DateTime;
+use Email::Send;
+use DateTime::Format::ISO8601;
+use OpenSRF::Utils qw/:datetime/;
+use OpenSRF::Utils::JSON;
+use Unicode::Normalize;
+use OpenILS::Const qw/:const/;
+use OpenSRF::AppSession;
+
+my $U = 'OpenILS::Application::AppUtils';
+
+my $SEND_EMAILS = 1;
+#my $SEND_EMAILS = 0;
+
+my $bsconfig = shift || die "usage: $0 <bootstrap_config>\n";
+my @goback = @ARGV;
+ at goback = (0) unless @goback;
+# osrf_connect($bsconfig);
+osrf_connect("/openils/conf/opensrf_core.xml");
+my $e = OpenILS::Utils::CStoreEditor->new;
+
+my $smtp = $ENV{EG_OVERDUE_SMTP_HOST};
+my $mail_sender = $ENV{EG_OVERDUE_EMAIL_SENDER};
+
+# ---------------------------------------------------------------
+# Set up the email template
+my $etmpl = $ENV{EG_OVERDUE_EMAIL_TEMPLATE};
+my $email_template;
+if( open(F,"$etmpl") ) {
+ my @etmpl = <F>;
+ $email_template = join('', at etmpl);
+ close(F);
+}
+# ---------------------------------------------------------------
+
+
+
+my @date = CORE::localtime;
+my $sec = $date[0];
+my $min = $date[1];
+my $hour = $date[2];
+my $day = $date[3];
+my $mon = $date[4] + 1;
+my $year = $date[5] + 1900;
+
+my %USER_CACHE;
+my %ORG_CACHE;
+
+
+print_notices($_) for @goback;
+
+
+# -----------------------------------------------------------------------
+# -----------------------------------------------------------------------
+
+
+sub print_notices {
+ my $goback = shift || 0;
+
+ for my $day ( qw/ -3 / ) { #grpl
+ my ($start, $end) = make_date_range($day + $goback);
+
+ $logger->info("OD_notice: process date range $start -> $end");
+
+ my $query = [
+ {
+ xact_finish => undef,
+ due_date => { between => [ $start, $end ] },
+ circ_lib => { between => [ 10, 17 ] }, #grpl
+ },
+ { order_by => { circ => 'usr, circ_lib' } }
+ ];
+ #my $circs = $e->search_action_circulation($query, {idlist=>1});
+
+ my $ses = OpenSRF::AppSession->create('open-ils.cstore');
+ my $req = $ses->request('open-ils.cstore.direct.action.circulation.id_list', @$query);
+ my $circs = [];
+ my $resp;
+ push(@$circs, $resp->content) while ($resp = $req->recv(timeout=>600));
+
+ process_circs( $circs, "${day}day" );
+ }
+}
+
+
+sub process_circs {
+ my $circs = shift;
+ my $range = shift;
+
+ return unless @$circs;
+
+ $logger->info("OD_notice: processing range $range and ".scalar(@$circs)." potential circs");
+
+ my $org;
+ my $patron;
+ my @current;
+
+ my $x = 0;
+ for my $circ (@$circs) {
+ $circ = $e->retrieve_action_circulation($circ);
+
+ if( !defined $org or
+ $circ->circ_lib != $org or $circ->usr ne $patron ) {
+ $org = $circ->circ_lib;
+ $patron = $circ->usr;
+ print_notice( $range, \@current ) if @current;
+ @current = ();
+ }
+
+ push( @current, $circ );
+ $x++;
+ }
+
+ $logger->info("OD_notice: processed $x circs");
+ print_notice( $range, \@current );
+}
+
+sub make_date_range {
+ my $daysback = shift;
+
+ my $epoch = CORE::time - ($daysback * 24 * 60 * 60);
+ my $date = DateTime->from_epoch( epoch => $epoch, time_zone => 'local');
+
+ $date->set_hour(0);
+ $date->set_minute(0);
+ $date->set_second(0);
+ my $start = "$date";
+
+ $date->set_hour(23);
+ $date->set_minute(59);
+ $date->set_second(59);
+
+ return ($start, "$date");
+}
+
+
+sub print_notice {
+ my( $range, $circs ) = @_;
+ return unless @$circs;
+
+ my $days_over = $range; #grpl
+ $days_over =~ s/'day'//; #grpl
+
+ my $s1 = scalar(@$circs);
+
+ # we don't charge for lost or claimsreturned
+ $circs = [
+ grep {
+ !$_->stop_fines or (
+ $_->stop_fines ne OILS_STOP_FINES_LOST and
+ $_->stop_fines ne OILS_STOP_FINES_CLAIMSRETURNED
+ )
+ } @$circs
+ ];
+
+ return unless @$circs;
+
+ my $s2 = $s1 - scalar(@$circs);
+ $logger->info("OD_notice: dropped $s2 lost/CR from processing...") if $s2;
+
+ my $org = $circs->[0]->circ_lib;
+
+
+ my $usr = $circs->[0]->usr;
+ $logger->debug("OD_notice: printing $range user:$usr org:$org");
+
+ my @patron_data = fetch_patron_data($usr);
+ my @org_data = fetch_org_data($org);
+
+ return unless (@patron_data and @org_data);
+
+ # $sth->execute($days_over,$patron_data[10]); #grpl
+
+ my $email;
+
+ if( $email = $patron_data[0]->email and $SEND_EMAILS
+ and $email =~ /.+\@.+/ ) {
+ send_email($range, \@patron_data, \@org_data, $circs);
+
+# } else {
+# if( $patron_data[9] ) {
+
+ print "\t\t<notice type='courtesy' count='$range'>\n";
+ print_patron_xml_chunk(@patron_data);
+ print_org_xml_chunk(@org_data);
+ print_circ_chunk($_) for @$circs;
+ print "\t\t</notice>\n";
+
+# } else {
+# # There is no zip, therefore no address.
+# $logger->warn("OD_notice: unable to send mail notification for $usr due to lack of valid address");
+# }
+ }
+}
+
+
+sub fetch_patron_data {
+ my $user_id = shift;
+
+ my $patron = $USER_CACHE{$user_id};
+
+ if( ! $patron ) {
+ $logger->debug("OD_notice: fetching patron $user_id");
+
+ $patron = $e->retrieve_actor_user(
+ [
+ $user_id,
+ {
+ flesh => 1,
+ flesh_fields => {
+ 'au' => [qw/ card billing_address mailing_address /]
+ }
+ }
+ ]
+ ) or return handle_event($e->event);
+
+ $USER_CACHE{$user_id} = $patron;
+ }
+
+ my $bc = $patron->card->barcode;
+ my $fn = $patron->first_given_name;
+ my $mn = $patron->second_given_name;
+ my $ln = $patron->family_name;
+
+ my ( $s1, $s2, $city, $state, $zip );
+
+ my $baddr = $patron->mailing_address;
+ unless( $baddr and $U->is_true($baddr->valid) ) {
+ $baddr = $patron->billing_address;
+ $baddr = undef unless( $baddr and $U->is_true($baddr->valid) );
+ }
+
+ if( $baddr ) {
+ $s1 = $baddr->street1;
+ $s2 = $baddr->street2;
+ $city = $baddr->city;
+ $state = $baddr->state;
+ $zip = $baddr->post_code;
+ }
+
+ my $pn = $patron->day_phone; #grpl
+
+ $bc = entityize($bc);
+ $fn = entityize($fn);
+ $mn = entityize($mn);
+ $ln = entityize($ln);
+ $s1 = entityize($s1);
+ $s2 = entityize($s2);
+ $city = entityize($city);
+ $state = entityize($state);
+ $zip = entityize($zip);
+ $pn = entityize($pn); #grpl
+
+ return ( $patron, $bc, $fn, $mn, $ln, $s1, $s2, $city, $state, $zip, $pn ); #grpl
+}
+
+
+sub print_patron_xml_chunk {
+ my( $patron, $bc, $fn, $mn, $ln, $s1, $s2, $city, $state, $zip ) = @_;
+ my $pid = $patron->id;
+ print <<" XML";
+ <patron>
+ <id type="barcode">$bc</id>
+ <fullname>$fn $mn $ln</fullname>
+ <street1>$s1 $s2</street1>
+ <city_state_zip>$city, $state $zip</city_state_zip>
+ <sys_id>$pid</sys_id>
+ </patron>
+ XML
+}
+
+
+sub fetch_org_data {
+ my $org_id = shift;
+
+ my $org = $ORG_CACHE{$org_id};
+
+ if( ! $org ) {
+ $logger->debug("OD_notice: fetching org $org_id");
+
+ $org = $e->retrieve_actor_org_unit(
+ [
+ $org_id,
+ {
+ flesh => 1,
+ flesh_fields =>
+ { aou => [ qw/billing_address mailing_address/ ] }
+ }
+ ]
+ ) or return handle_event($e->event);
+
+ $ORG_CACHE{$org_id} = $org;
+ }
+
+ my $name = $org->name;
+ my $phone = $org->phone;
+ my $email = $org->email;
+
+
+ my( $s1, $s2, $city, $state, $zip );
+ my $baddr = $org->billing_address || $org->mailing_address;
+ if( $baddr ) {
+ $s1 = $baddr->street1;
+ $s2 = $baddr->street2;
+ $city = $baddr->city;
+ $state = $baddr->state;
+ $zip = $baddr->post_code;
+ }
+
+ $name = entityize($name);
+ $phone = entityize($phone);
+ $s1 = entityize($s1);
+ $s2 = entityize($s2);
+ $city = entityize($city);
+ $state = entityize($state);
+ $zip = entityize($zip);
+ $email = entityize($email);
+
+ return ( $org, $name, $phone, $s1, $s2, $city, $state, $zip, $email );
+}
+
+
+sub print_org_xml_chunk {
+ my( $org, $name, $phone, $s1, $s2, $city, $state, $zip, $email ) = @_;
+ print <<" XML";
+ <library>
+ <libname>$name</libname>
+ <libphone>$phone</libphone>
+ <libstreet1>$s1 $s2</libstreet1>
+ <libcity_state_zip>$city, $state $zip</libcity_state_zip>
+ </library>
+ XML
+}
+
+
+sub fetch_circ_data {
+ my $circ = shift;
+
+ my $title;
+ my $author;
+ my $cn;
+
+ my $d = $circ->due_date;
+ $d =~ s/[T ].*//og; # just for logging
+ $logger->debug("OD_notice: processing circ ".$circ->id." $d");
+
+ my $due = DateTime::Format::ISO8601->new->parse_datetime(
+ clense_ISO8601($circ->due_date));
+
+ my $day = $due->day;
+ my $mon = $due->month;
+ my $year = $due->year;
+
+ my $copy = $e->retrieve_asset_copy($circ->target_copy)
+ or return handle_event($e->event);
+
+ my $loc = $copy->location;
+ my $cl = $e->retrieve_asset_copy_location($loc);
+ $cl = $cl->[6];
+
+ my $bc = $copy->barcode;
+
+ if( $copy->call_number == OILS_PRECAT_CALL_NUMBER ) {
+ $title = $copy->dummy_title || "";
+ $author = $copy->dummy_author || "";
+
+ } else {
+
+ my $volume = $e->retrieve_asset_call_number(
+ [
+ $copy->call_number,
+ {
+ flesh => 1,
+ flesh_fields => {
+ acn => [ qw/record/ ]
+ }
+ }
+ ]
+ ) or return handle_event($e->event);
+
+ $cn = $volume->label;
+ my $mods = $apputils->record_to_mvr($volume->record);
+ if( $mods ) {
+ $title = $mods->title || "";
+ $author = $mods->author || "";
+ }
+ }
+
+ $title = entityize($title);
+ $author = entityize($author);
+ $cn = entityize($cn);
+ $bc = entityize($bc);
+
+ my $xact = $circ->[13];
+ my $fine = simplereq('open-ils.cstore', 'open-ils.cstore.direct.money.billable_transaction_summary.retrieve', $xact);
+ $fine = $fine->[3];
+
+ my $co = DateTime::Format::ISO8601->new->parse_datetime(
+ clense_ISO8601($circ->xact_start));
+ my $co_day = $co->day;
+ my $co_mon = $co->month;
+ my $co_year = $co->year;
+ my $co_date = "$co_mon/$co_day/$co_year";
+
+ my $pr = $copy->price;
+
+ return( $title, $author, $cn, $bc, $day, $mon, $year, $co_date, $pr, $cl, $fine );
+}
+
+
+sub print_circ_chunk {
+ my $circ = shift;
+ my ( $title, $author, $cn, $bc, $day, $mon, $year, $co, $pr, $cl, $fine ) = fetch_circ_data($circ);
+ my $cid = $circ->id;
+ print <<" XML";
+ <item>
+ <title>$title</title>
+ <author>$author</author>
+ <duedate>$mon/$day/$year</duedate>
+ <callno>$cn</callno>
+ <location>$cl</location>
+ <barcode>$bc</barcode>
+ <circ_id>$cid</circ_id>
+ <check_out>$co</check_out>
+ <item_price>$pr</item_price>
+ <fine>$fine</fine>
+ </item>
+ XML
+}
+
+
+
+sub send_email {
+ my( $range, $patron_data, $org_data, $circs ) = @_;
+ my( $org, $org_name, $org_phone, $org_s1, $org_s2, $org_city, $org_state, $org_zip, $org_email ) = @$org_data;
+ my( $patron, $bc, $fn, $mn, $ln, $user_s1, $user_s2, $user_city, $user_state, $user_zip ) = @$patron_data;
+
+ return unless $SEND_EMAILS;
+
+ my $pemail = $patron_data->[0]->email;
+
+ my $tmpl = $email_template;
+ my @time = localtime;
+ my $year = $time[5] + 1900;
+ my $mon = $time[4] + 1;
+ my $day = $time[3];
+
+# my $r = ($range eq '7day') ? 7 : 14;
+ my $r = $range; #grpl
+ $r =~ s/'day'//; #grpl
+
+ # - default to the global sender for the errors-to header
+ my $errors_to = $mail_sender;
+
+ # if they have an org setting for errors-to, use that as the errors-to address
+ if( my $set = $e->search_actor_org_unit_setting(
+ { name => 'org.bounced_emails', org_unit => $org->id } )->[0] ) {
+
+ my $bemail = OpenSRF::Utils::JSON->JSON2perl($set->value);
+ $errors_to = $bemail if $bemail;
+ }
+
+
+ $tmpl =~ s/\${EMAIL_RECIPIENT}/$pemail/;
+ $tmpl =~ s/\${EMAIL_SENDER}/$errors_to/o;
+ $tmpl =~ s/\${EMAIL_REPLY_TO}/$errors_to/;
+ $tmpl =~ s/\${EMAIL_ERRORS_TO}/$errors_to/;
+ $tmpl =~ s/\${EMAIL_HEADERS}//; # - we have no additional headers to add
+
+ $tmpl =~ s/\${RANGE}/$r/;
+ $tmpl =~ s/\${DATE}/$mon\/$day\/$year/;
+ $tmpl =~ s/\${FIRST_NAME}/$fn/;
+ $tmpl =~ s/\${MIDDLE_NAME}/$mn/;
+ $tmpl =~ s/\${LAST_NAME}/$ln/;
+
+ my ($itmpl) = $tmpl =~ /\${COURTESY_ITEMS\[(.*)\]}/ms;
+
+ my $items = '';
+ for my $circ (@$circs) {
+ my $circtmpl = $itmpl;
+ my ( $title, $author, $cn, $bc, $due_day, $due_mon, $due_year, $co ) = fetch_circ_data($circ);
+ $circtmpl =~ s/\${TITLE}/$title/o;
+ $circtmpl =~ s/\${AUTHOR}/$author/o;
+ $circtmpl =~ s/\${CALL_NUMBER}/$cn/o;
+ $circtmpl =~ s/\${DUE_DAY}/$due_day/o;
+ $circtmpl =~ s/\${DUE_MONTH}/$due_mon/o;
+ $circtmpl =~ s/\${DUE_YEAR}/$due_year/o;
+ $circtmpl =~ s/\${ITEM_BARCODE}/$bc/o;
+ $circtmpl =~ s/\${ITEM_OUT}/$co/o;
+ $items .= "$circtmpl\n";
+ }
+
+ $tmpl =~ s/\${COURTESY_ITEMS\[.*\]}/$items/ms;
+
+# my $org_addr = "$org_s1 $org_s2 $org_city, $org_state $org_zip";
+# $tmpl =~ s/\${ORG_NAME}/$org_name/o;
+# $tmpl =~ s/\${ORG_ADDRESS}/$org_addr/o;
+# $tmpl =~ s/\${ORG_PHONE}/$org_phone/o;
+
+ $logger->debug("OD_notice: sending email to $pemail: $tmpl");
+
+ my $sender = Email::Send->new({mailer => 'SMTP'});
+ $sender->mailer_args([Host => $smtp]);
+
+ my $stat = $sender->send($tmpl);
+
+ if( $stat and $stat->type eq 'success' ) {
+ $logger->info("OD_notice: successfully sent overdue email");
+ } else {
+ $logger->warn("OD_notice: unable to send hold overdue email: ".Dumper($stat));
+ }
+
+ $logger->info("OD_notice: sending email to".$patron_data->[0]->email);
+}
+
+sub handle_event {
+ my $evt = shift;
+ warn "OD_notice: ".Dumper($evt) . "\n";
+ $logger->error("OD_notice: ".Dumper($evt));
+ return undef;
+}
+
+
+sub entityize {
+ my $stuff = shift || return "";
+ $stuff =~ s/\</</og;
+ $stuff =~ s/\>/>/og;
+ $stuff =~ s/\&/&/og;
+ $stuff = NFC($stuff);
+ $stuff =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
+ return $stuff;
+}
+
+
+
+
Property changes on: grpl/trunk/patron_notifications/grpl_courtesy.pl
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/grpl_courtesy.sh
===================================================================
--- grpl/trunk/patron_notifications/grpl_courtesy.sh (rev 0)
+++ grpl/trunk/patron_notifications/grpl_courtesy.sh 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,30 @@
+#!/bin/bash
+# ---------------------------------------------------------------
+# This file runs the overdue generation script.
+# If today is Monday, it runs the script for Sat/Sun/Mon,
+# otherwise it runs once per day.
+# ---------------------------------------------------------------
+
+
+
+
+SSH_CLIENT=$1
+RECIPIENT=$2;
+DATE=$(date +%Y-%m-%d);
+DAY=$(date +%u);
+BSCONFIG="/openils/conf/opensrf_core.xml"
+ODDIR="/openils/var/data/courtesy";
+
+export EG_OVERDUE_EMAIL_TEMPLATE="grpl_courtesy_email";
+export EG_OVERDUE_SMTP_HOST="your_email_host";
+export EG_OVERDUE_EMAIL_SENDER="courtesy_notice at your_domain";
+
+[ $(whoami) != "opensrf" ] && echo "Must be run as opensrf" && exit 1;
+source ~/.bashrc;
+ARGS="0"
+
+#[ $DAY == 6 -o $DAY == 7 ] && exit 0; # don't run on saturday or sunday
+#if [ $DAY == 1 ]; then ARGS="2 1 0"; fi; # If today is monday, run for sat/sun/mon
+
+./grpl_courtesy.pl $BSCONFIG $ARGS > "$ODDIR/grpl_courtesy.$DATE.xml"
+
Property changes on: grpl/trunk/patron_notifications/grpl_courtesy.sh
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/grpl_courtesy_email
===================================================================
--- grpl/trunk/patron_notifications/grpl_courtesy_email (rev 0)
+++ grpl/trunk/patron_notifications/grpl_courtesy_email 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,32 @@
+To: ${EMAIL_RECIPIENT}
+From: ${EMAIL_SENDER}
+Reply-To: ${EMAIL_REPLY_TO}
+Errors-To: ${EMAIL_ERRORS_TO}
+Subject: Library Courtesy Notice
+${EMAIL_HEADERS}
+
+
+${DATE}
+Dear ${FIRST_NAME} ${MIDDLE_NAME} ${LAST_NAME}
+
+This is a reminder that the following items will be due in 3 days.
+To avoid overdue charges, please return them on or before the due
+date. Some items may be renewed online at
+
+${COURTESY_ITEMS[
+AUTHOR: ${AUTHOR}
+TITLE: ${TITLE}
+CALL NO: ${CALL_NUMBER}
+BARCODE: ${ITEM_BARCODE}
+DUE: ${DUE_MONTH}/${DUE_DAY}/${DUE_YEAR}
+DATE CHECKED OUT: ${ITEM_OUT}
+]}
+
+This an an automated message, please do not reply to it. Instead
+if you have questions about this notice, please contact the library
+where you checked the item(s) out.
+
+Grand Rapids - Main / 111 Library St NE Grand Rapids, MI 49503
+616-988-5400
+
+
Added: grpl/trunk/patron_notifications/grpl_holdnotice.cgi
===================================================================
--- grpl/trunk/patron_notifications/grpl_holdnotice.cgi (rev 0)
+++ grpl/trunk/patron_notifications/grpl_holdnotice.cgi 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,35 @@
+#!/usr/bin/perl
+
+require '/openils/bin/support-scripts/oils_header.pl';
+use OpenILS::Utils::CStoreEditor q/:funcs/;
+use CGI qw(:standard);
+use DateTime;
+use DateTime::Format::ISO8601;
+
+print "Content-type: text/html\n\n";
+
+my $conf = '/openils/conf/opensrf_core.xml';
+
+my $holdid = param('h');
+my $status = param('s');
+
+my $d = DateTime->now;
+$d->add(days=>10);
+
+our %grpl_config;
+do '/openils/conf/grpl-egauth-setup.pl';
+osrf_connect($conf);
+my $authtok = oils_login($grpl_config{usr},$grpl_config{pw});
+
+
+$we = new_editor(xact=>1, authtoken => $auth);
+my $notify = Fieldmapper::action::hold_notification->new;
+$notify->hold($holdid);
+$notify->notify_time('now');
+$notify->method($status);
+$notify->notify_staff(1);
+$we->create_action_hold_notification($notify)
+ or return $we->die_event;
+$we->commit;
+
+
Property changes on: grpl/trunk/patron_notifications/grpl_holdnotice.cgi
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/grpl_holdshelf.cgi
===================================================================
--- grpl/trunk/patron_notifications/grpl_holdshelf.cgi (rev 0)
+++ grpl/trunk/patron_notifications/grpl_holdshelf.cgi 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+
+require '/openils/bin/support-scripts/oils_header.pl';
+use OpenILS::Utils::CStoreEditor q/:funcs/;
+use CGI qw(:standard);
+
+print "Content-type: text/html\n\n";
+
+my $conf = '/openils/conf/opensrf_core.xml';
+
+our %grpl_config;
+do '/openils/conf/grpl-egauth-setup.pl';
+osrf_connect($conf);
+my $authtok = oils_login($grpl_config{usr},$grpl_config{pw});
+my @date = localtime;
+my $today = ($date[5] + 1900) .'-'. ($date[4] + 1) .'-'. $date[3];
+my $tomorrow = ($date[5] + 1900) .'-'. ($date[4] + 1) .'-'. ($date[3] + 1);
+my $cdate = simplereq( ACTOR(),'open-ils.actor.org_unit.closed.retrieve.all', $authtok, { orgid => 10, start_date => $today, end_date => $tomorrow });
+exit if ($cdate->[0]);
+
+foreach my $loc (10..17) {
+ my $hrs = simplereq( ACTOR(), 'open-ils.actor.org_unit.hours_of_operation.retrieve', $authtok, $loc);
+ my $hr_op = wrap_perl($hrs);
+ my $dow = 'dow_' . ($date[6] - 1) . '_open';
+ next if ($hr_op->{$dow} eq '00:00:00');
+
+ my $ses = OpenSRF::AppSession->create( "open-ils.circ" );
+ my $req = $ses->request('open-ils.circ.captured_holds.on_shelf.retrieve', $authtok, $loc);
+ while(my $resp = $req->recv(timeout => 120)) {
+ my $hid = $resp->content;
+ my $hd = simplereq( CIRC(), 'open-ils.circ.hold.details.retrieve', $authtok, $$hid[14]);
+ my $hh = wrap_perl($hd);
+
+ my $avtime;
+ if ($hh->{hold}->{transit}) {
+ $avtime = $hh->{hold}->{transit}->{dest_recv_time}
+ }
+ my $pnotify = $hh->{hold}->{phone_notify};
+ my $p = simplereq( ACTOR(),'open-ils.actor.user.fleshed.retrieve', $authtok, $hh->{hold}->{usr});
+ my $ph = wrap_perl($p);
+ if ( !$pnotify && ($hh->{hold}->{id} < 9454) ) {
+ $pnotify = $ph->{day_phone};
+ }
+ $pnotify =~ s/(\d+)\D+(\d+)\D+(\d+).*/$1$2$3/;
+ $pnotify =~ s/\(//;
+ $pnotify =~ s/\///g;
+ foreach my $sc (@{$p}[10]) {
+ foreach my $v (@{$sc}) {
+ if ($v->{stat_cat_entry} eq 'Block Calls') {
+ $pnotify = 'Block Calls';
+ }
+ }
+ }
+ my $o = simplereq(ACTOR(), 'open-ils.actor.org_unit.retrieve', $authtok, $loc);
+ my $oh = wrap_perl($o);
+ my $oa = simplereq(ACTOR(), 'open-ils.actor.org_unit.address.retrieve', $oh->{mailing_address});
+ my $oah= wrap_perl($oa);
+ $avtime = $hh->{hold}->{capture_time} unless $avtime;
+ $avtime =~ s/(\d\d\d\d-\d\d-\d\d)T(\d\d:\d\d:\d\d).*/$1 $2/;
+ print "$hh->{hold}->{id}|$ph->{first_given_name}|$ph->{family_name}|$ph->{mailing_address}->{street1}|$ph->{mailing_address}->{city}|$ph->{mailing_address}->{state}|$ph->{mailing_address}->{post_code}|$ph->{email}|$hh->{hold}->{email_notify}|$pnotify|$hh->{hold}->{notify_time}|$avtime|$hh->{mvr}->{title}|$hh->{mvr}->{author}|$oh->{shortname}|$oah->{street1}|$oah->{city}|$oah->{state}|$oah->{post_code}|$ph->{card}->{barcode}||\n" unless $hh->{hold}->{notify_time};
+# }
+ } # end while
+} # end foreach
+
+sub wrap_perl {
+ my $obj = shift;
+ my $ref = ref($obj);
+
+ if ($ref =~ /^Fieldmapper/o) {
+ $ref = $obj->json_hint;
+ $obj = $obj->to_bare_hash;
+ }
+
+ if( $ref eq 'HASH' ) {
+ $obj->{$_} = wrap_perl( $obj->{$_} ) for (keys %$obj);
+ } elsif( $ref eq 'ARRAY' ) {
+ $obj->[$_] = wrap_perl( $obj->[$_] ) for(0..scalar(@$obj) - 1 );
+ } elsif( $ref ) {
+ if(UNIVERSAL::isa($obj, 'HASH')) {
+ $obj->{$_} = wrap_perl( $obj->{$_} ) for (keys %$obj);
+ bless($obj, 'HASH'); # so our parser won't add the hints
+ } elsif(UNIVERSAL::isa($obj, 'ARRAY')) {
+ $obj->[$_] = wrap_perl( $obj->[$_] ) for(0..scalar(@$obj) - 1);
+ bless($obj, 'ARRAY'); # so our parser won't add the hints
+ }
+# $obj = { $CLASS_KEY => $ref, $PAYLOAD_KEY => $obj };
+ }
+ return $obj;
+}
+
Property changes on: grpl/trunk/patron_notifications/grpl_holdshelf.cgi
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/grpl_overdue.pl
===================================================================
--- grpl/trunk/patron_notifications/grpl_overdue.pl (rev 0)
+++ grpl/trunk/patron_notifications/grpl_overdue.pl 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,572 @@
+#!/usr/bin/perl
+# ---------------------------------------------------------------
+# Generates the overdue notices XML file
+# ./eg_gen_overdue.pl <bootstap> 0
+# generates today's notices
+# ./eg_gen_overdue.pl <bootstap> 1 0
+# generates notices for today - 1 and today
+# ./eg_gen_overdue.pl <bootstap> 2 1 0
+# ./eg_gen_overdue.pl <bootstap> 3 2 1 0 etc...
+# ---------------------------------------------------------------
+
+
+
+use strict; use warnings;
+require 'oils_header.pl';
+use vars qw/$logger $apputils/;
+use Data::Dumper;
+use OpenILS::Const qw/:const/;
+use OpenILS::Application::AppUtils;
+use DateTime;
+use Email::Send;
+use DateTime::Format::ISO8601;
+use OpenSRF::Utils qw/:datetime/;
+use OpenSRF::Utils::JSON;
+use Unicode::Normalize;
+use OpenILS::Const qw/:const/;
+use OpenSRF::AppSession;
+use DBI; #grpl
+use DBD::mysql; #grpl
+
+my $U = 'OpenILS::Application::AppUtils';
+
+my $SEND_EMAILS = 1;
+#my $SEND_EMAILS = 0;
+my $bsconfig = shift || die "usage: $0 <bootstrap_config>\n";
+#my $bsconfig = "/openils/conf/opensrf_core.xml";
+
+my @goback = @ARGV;
+ at goback = (0) unless @goback;
+osrf_connect($bsconfig);
+my $e = OpenILS::Utils::CStoreEditor->new;
+
+my $smtp = $ENV{EG_OVERDUE_SMTP_HOST};
+my $mail_sender = $ENV{EG_OVERDUE_EMAIL_SENDER};
+
+# ---------------------------------------------------------------
+# Set up the email template
+my $etmpl = $ENV{EG_OVERDUE_EMAIL_TEMPLATE};
+my $email_template;
+if( open(F,"$etmpl") ) {
+ my @etmpl = <F>;
+ $email_template = join('', at etmpl);
+ close(F);
+}
+# ---------------------------------------------------------------
+
+
+
+my @date = CORE::localtime;
+my $sec = $date[0];
+my $min = $date[1];
+my $hour = $date[2];
+my $day = $date[3];
+my $mon = $date[4] + 1;
+my $year = $date[5] + 1900;
+
+my %USER_CACHE;
+my %ORG_CACHE;
+
+my $dbh=DBI->connect('dbi:mysql:database=notify;host=your_db_host;port=3306', "user", 'password', { RaiseError => 1, PrintError => 1 } ); # grpl
+my $sth=$dbh->prepare("insert into overdues set keynum = '', days_over = ?, phone_num = ?, notify_status = '', notify_time = now()"); # grpl
+
+
+print_notices($_) for @goback;
+
+
+# -----------------------------------------------------------------------
+# -----------------------------------------------------------------------
+
+
+sub print_notices {
+ my $goback = shift || 0;
+
+ for my $day ( qw/ 7 14 / ) { #grpl
+ my ($start, $end) = make_date_range($day + $goback);
+
+ $logger->info("OD_notice: process date range $start -> $end");
+
+ my $query = [
+ {
+ checkin_time => undef,
+ due_date => { between => [ $start, $end ] },
+ circ_lib => { between => [ 10, 17 ] }, #grpl
+ },
+ { order_by => { circ => 'usr, circ_lib' } }
+ ];
+ #my $circs = $e->search_action_circulation($query, {idlist=>1});
+
+ my $ses = OpenSRF::AppSession->create('open-ils.cstore');
+ my $req = $ses->request('open-ils.cstore.direct.action.circulation.id_list', @$query);
+ my $circs = [];
+ my $resp;
+ push(@$circs, $resp->content) while ($resp = $req->recv(timeout=>600));
+
+ process_circs( $circs, "${day}day" );
+ }
+}
+
+
+sub process_circs {
+ my $circs = shift;
+ my $range = shift;
+
+ return unless @$circs;
+
+ $logger->info("OD_notice: processing range $range and ".scalar(@$circs)." potential circs");
+
+ my $org;
+ my $patron;
+ my @current;
+
+ my $x = 0;
+ for my $circ (@$circs) {
+ $circ = $e->retrieve_action_circulation($circ);
+
+ if( !defined $org or
+ $circ->circ_lib != $org or $circ->usr ne $patron ) {
+ $org = $circ->circ_lib;
+ $patron = $circ->usr;
+ print_notice( $range, \@current ) if @current;
+ @current = ();
+ }
+
+ push( @current, $circ );
+ $x++;
+ }
+
+ $logger->info("OD_notice: processed $x circs");
+ print_notice( $range, \@current );
+}
+
+sub make_date_range {
+ my $daysback = shift;
+
+ my $epoch = CORE::time - ($daysback * 24 * 60 * 60);
+ my $date = DateTime->from_epoch( epoch => $epoch, time_zone => 'local');
+
+ $date->set_hour(0);
+ $date->set_minute(0);
+ $date->set_second(0);
+ my $start = "$date";
+
+ $date->set_hour(23);
+ $date->set_minute(59);
+ $date->set_second(59);
+
+ return ($start, "$date");
+}
+
+
+sub print_notice {
+ my( $range, $circs ) = @_;
+ return unless @$circs;
+
+ my $days_over = $range; #grpl
+ $days_over =~ s/'day'//; #grpl
+
+ my $s1 = scalar(@$circs);
+
+ # we don't charge for lost or claimsreturned
+ $circs = [
+ grep {
+ !$_->stop_fines or (
+ $_->stop_fines ne OILS_STOP_FINES_LOST and
+ $_->stop_fines ne OILS_STOP_FINES_CLAIMSRETURNED
+ )
+ } @$circs
+ ];
+
+ return unless @$circs;
+
+ my $s2 = $s1 - scalar(@$circs);
+ $logger->info("OD_notice: dropped $s2 lost/CR from processing...") if $s2;
+
+ my $org = $circs->[0]->circ_lib;
+
+
+ my $usr = $circs->[0]->usr;
+ $logger->debug("OD_notice: printing $range user:$usr org:$org");
+
+ my @patron_data = fetch_patron_data($usr);
+ my @org_data = fetch_org_data($org);
+
+ return unless (@patron_data and @org_data);
+ my $wd = (localtime)[6]; #grpl
+ if ( $wd != 0 ) { # grpl if not Sun
+ if ( ($patron_data[10] ne '') && (!$patron_data[11]) && (!$patron_data[0]->email) ) { # grpl [10] is phone_num and [11] is Block Calls stat_cat
+ my $pnum = $patron_data[10];
+ $pnum =~ s/(\d+)\D+(\d+)\D+(\d+).*/$1$2$3/;
+ $sth->execute($days_over,$pnum); #grpl
+ }
+ }
+
+ my $email;
+
+ if( $email = $patron_data[0]->email and $SEND_EMAILS
+ and $email =~ /.+\@.+/
+ and ($range eq '7day' or $range eq '14day') ) { #grpl
+ send_email($range, \@patron_data, \@org_data, $circs);
+
+ } else {
+
+ if( $patron_data[9] ) {
+
+ #print "\t\t<notice type='overdue' count='$range'>\n";
+ #print_patron_xml_chunk(@patron_data);
+ #print_org_xml_chunk(@org_data);
+ #print_circ_chunk($_) for @$circs;
+ #print "\t\t</notice>\n";
+
+ } else {
+ # There is no zip, therefore no address.
+ $logger->warn("OD_notice: unable to send mail notification for $usr due to lack of valid address");
+ }
+ }
+}
+
+
+sub fetch_patron_data {
+ my $user_id = shift;
+
+ my $patron = $USER_CACHE{$user_id};
+
+ if( ! $patron ) {
+ $logger->debug("OD_notice: fetching patron $user_id");
+
+ $patron = $e->retrieve_actor_user(
+ [
+ $user_id,
+ {
+ flesh => 1,
+ flesh_fields => {
+ 'au' => [qw/ card billing_address mailing_address stat_cat_entries/]
+ }
+ }
+ ]
+ ) or return handle_event($e->event);
+
+ $USER_CACHE{$user_id} = $patron;
+ }
+
+ my $bc = $patron->card->barcode;
+ my $fn = $patron->first_given_name;
+ my $mn = $patron->second_given_name;
+ my $ln = $patron->family_name;
+
+ my ( $s1, $s2, $city, $state, $zip );
+
+ my $baddr = $patron->mailing_address;
+ unless( $baddr and $U->is_true($baddr->valid) ) {
+ $baddr = $patron->billing_address;
+ $baddr = undef unless( $baddr and $U->is_true($baddr->valid) );
+ }
+
+ if( $baddr ) {
+ $s1 = $baddr->street1;
+ $s2 = $baddr->street2;
+ $city = $baddr->city;
+ $state = $baddr->state;
+ $zip = $baddr->post_code;
+ }
+
+ $bc = entityize($bc);
+ $fn = entityize($fn);
+ $mn = entityize($mn);
+ $ln = entityize($ln);
+ $s1 = entityize($s1);
+ $s2 = entityize($s2);
+ $city = entityize($city);
+ $state = entityize($state);
+ $zip = entityize($zip);
+
+ my $pn = $patron->day_phone; #grpl
+ $pn = entityize($pn); #grpl
+ my $patron_block = 0; #grpl
+ foreach my $sc (@{$patron->stat_cat_entries}) { #grpl
+ if ( $sc->[5] eq 'Block Calls' ) {
+ $patron_block = 1;
+ }
+ }
+
+ return ( $patron, $bc, $fn, $mn, $ln, $s1, $s2, $city, $state, $zip, $pn, $patron_block ); #grpl
+}
+
+
+sub print_patron_xml_chunk {
+ my( $patron, $bc, $fn, $mn, $ln, $s1, $s2, $city, $state, $zip ) = @_;
+ my $pid = $patron->id;
+ print <<" XML";
+ <patron>
+ <id type="barcode">$bc</id>
+ <fullname>$fn $mn $ln</fullname>
+ <street1>$s1 $s2</street1>
+ <city_state_zip>$city, $state $zip</city_state_zip>
+ <sys_id>$pid</sys_id>
+ </patron>
+ XML
+}
+
+
+sub fetch_org_data {
+ my $org_id = shift;
+
+ my $org = $ORG_CACHE{$org_id};
+
+ if( ! $org ) {
+ $logger->debug("OD_notice: fetching org $org_id");
+
+ $org = $e->retrieve_actor_org_unit(
+ [
+ $org_id,
+ {
+ flesh => 1,
+ flesh_fields =>
+ { aou => [ qw/billing_address mailing_address/ ] }
+ }
+ ]
+ ) or return handle_event($e->event);
+
+ $ORG_CACHE{$org_id} = $org;
+ }
+
+ my $name = $org->name;
+ my $phone = $org->phone;
+ my $email = $org->email;
+
+
+ my( $s1, $s2, $city, $state, $zip );
+ my $baddr = $org->billing_address || $org->mailing_address;
+ if( $baddr ) {
+ $s1 = $baddr->street1;
+ $s2 = $baddr->street2;
+ $city = $baddr->city;
+ $state = $baddr->state;
+ $zip = $baddr->post_code;
+ }
+
+ $name = entityize($name);
+ $phone = entityize($phone);
+ $s1 = entityize($s1);
+ $s2 = entityize($s2);
+ $city = entityize($city);
+ $state = entityize($state);
+ $zip = entityize($zip);
+ $email = entityize($email);
+
+ return ( $org, $name, $phone, $s1, $s2, $city, $state, $zip, $email );
+}
+
+
+sub print_org_xml_chunk {
+ my( $org, $name, $phone, $s1, $s2, $city, $state, $zip, $email ) = @_;
+ print <<" XML";
+ <library>
+ <libname>$name</libname>
+ <libphone>$phone</libphone>
+ <libstreet1>$s1 $s2</libstreet1>
+ <libcity_state_zip>$city, $state $zip</libcity_state_zip>
+ </library>
+ XML
+}
+
+
+sub fetch_circ_data {
+ my $circ = shift;
+
+ my $title;
+ my $author;
+ my $cn;
+
+ my $d = $circ->due_date;
+ $d =~ s/[T ].*//og; # just for logging
+ $logger->debug("OD_notice: processing circ ".$circ->id." $d");
+
+ my $due = DateTime::Format::ISO8601->new->parse_datetime(
+ clense_ISO8601($circ->due_date));
+
+ my $day = $due->day;
+ my $mon = $due->month;
+ my $year = $due->year;
+
+ my $copy = $e->retrieve_asset_copy($circ->target_copy)
+ or return handle_event($e->event);
+
+ my $loc = $copy->location;
+ my $cl = $e->retrieve_asset_copy_location($loc);
+ $cl = $cl->[7];
+
+ my $bc = $copy->barcode;
+
+ if( $copy->call_number == OILS_PRECAT_CALL_NUMBER ) {
+ $title = $copy->dummy_title || "";
+ $author = $copy->dummy_author || "";
+
+ } else {
+
+ my $volume = $e->retrieve_asset_call_number(
+ [
+ $copy->call_number,
+ {
+ flesh => 1,
+ flesh_fields => {
+ acn => [ qw/record/ ]
+ }
+ }
+ ]
+ ) or return handle_event($e->event);
+
+ $cn = $volume->label;
+ my $mods = $apputils->record_to_mvr($volume->record);
+ if( $mods ) {
+ $title = $mods->title || "";
+ $author = $mods->author || "";
+ }
+ }
+
+ $title = entityize($title);
+ $author = entityize($author);
+ $cn = entityize($cn);
+ $bc = entityize($bc);
+
+ my $xact = $circ->[13];
+ my $fine = simplereq('open-ils.cstore', 'open-ils.cstore.direct.money.billable_transaction_summary.retrieve', $xact);
+ $fine = $fine->[3];
+
+ my $co = DateTime::Format::ISO8601->new->parse_datetime(
+ clense_ISO8601($circ->xact_start));
+ my $co_day = $co->day;
+ my $co_mon = $co->month;
+ my $co_year = $co->year;
+ my $co_date = "$co_mon/$co_day/$co_year";
+
+ my $pr = $copy->price;
+
+ return( $title, $author, $cn, $bc, $day, $mon, $year, $co_date, $pr, $cl, $fine );
+}
+
+
+sub print_circ_chunk {
+ my $circ = shift;
+ my ( $title, $author, $cn, $bc, $day, $mon, $year, $co, $pr, $cl, $fine ) = fetch_circ_data($circ);
+ my $cid = $circ->id;
+ print <<" XML";
+ <item>
+ <title>$title</title>
+ <author>$author</author>
+ <duedate>$mon/$day/$year</duedate>
+ <callno>$cn</callno>
+ <location>$cl</location>
+ <barcode>$bc</barcode>
+ <circ_id>$cid</circ_id>
+ <check_out>$co</check_out>
+ <item_price>$pr</item_price>
+ <fine>$fine</fine>
+ </item>
+ XML
+}
+
+
+
+sub send_email {
+ my( $range, $patron_data, $org_data, $circs ) = @_;
+ my( $org, $org_name, $org_phone, $org_s1, $org_s2, $org_city, $org_state, $org_zip, $org_email ) = @$org_data;
+ my( $patron, $bc, $fn, $mn, $ln, $user_s1, $user_s2, $user_city, $user_state, $user_zip ) = @$patron_data;
+
+ return unless $SEND_EMAILS;
+
+ my $pemail = $patron_data->[0]->email;
+
+ my $tmpl = $email_template;
+ my @time = localtime;
+ my $year = $time[5] + 1900;
+ my $mon = $time[4] + 1;
+ my $day = $time[3];
+
+ my $r = ($range eq '7day') ? 7 : 14; #grpl
+
+ # - default to the global sender for the errors-to header
+ my $errors_to = $mail_sender;
+
+ # if they have an org setting for errors-to, use that as the errors-to address
+ if( my $set = $e->search_actor_org_unit_setting(
+ { name => 'org.bounced_emails', org_unit => $org->id } )->[0] ) {
+
+ my $bemail = OpenSRF::Utils::JSON->JSON2perl($set->value);
+ $errors_to = $bemail if $bemail;
+ }
+
+
+ $tmpl =~ s/\${EMAIL_RECIPIENT}/$pemail/;
+ $tmpl =~ s/\${EMAIL_SENDER}/$errors_to/o;
+ $tmpl =~ s/\${EMAIL_REPLY_TO}/$errors_to/;
+ $tmpl =~ s/\${EMAIL_ERRORS_TO}/$errors_to/;
+ $tmpl =~ s/\${EMAIL_HEADERS}//; # - we have no additional headers to add
+
+ $tmpl =~ s/\${RANGE}/$r/;
+ $tmpl =~ s/\${DATE}/$mon\/$day\/$year/;
+ $tmpl =~ s/\${FIRST_NAME}/$fn/;
+ $tmpl =~ s/\${MIDDLE_NAME}/$mn/;
+ $tmpl =~ s/\${LAST_NAME}/$ln/;
+ $tmpl =~ s/\${BARCODE}/$bc/; # grpl
+
+ my ($itmpl) = $tmpl =~ /\${OVERDUE_ITEMS\[(.*)\]}/ms;
+
+ my $items = '';
+ for my $circ (@$circs) {
+ my $circtmpl = $itmpl;
+ my ( $title, $author, $cn, $bc, $due_day, $due_mon, $due_year ) = fetch_circ_data($circ);
+ $circtmpl =~ s/\${TITLE}/$title/o;
+ $circtmpl =~ s/\${AUTHOR}/$author/o;
+ $circtmpl =~ s/\${CALL_NUMBER}/$cn/o;
+ $circtmpl =~ s/\${DUE_DAY}/$due_day/o;
+ $circtmpl =~ s/\${DUE_MONTH}/$due_mon/o;
+ $circtmpl =~ s/\${DUE_YEAR}/$due_year/o;
+ $circtmpl =~ s/\${ITEM_BARCODE}/$bc/o;
+ $items .= "$circtmpl\n";
+ }
+
+ $tmpl =~ s/\${OVERDUE_ITEMS\[.*\]}/$items/ms;
+
+ my $org_addr = "$org_s1 $org_s2 $org_city, $org_state $org_zip";
+ $tmpl =~ s/\${ORG_NAME}/$org_name/o;
+ $tmpl =~ s/\${ORG_ADDRESS}/$org_addr/o;
+ $tmpl =~ s/\${ORG_PHONE}/$org_phone/o;
+
+ $logger->debug("OD_notice: sending email to $pemail: $tmpl");
+
+ my $sender = Email::Send->new({mailer => 'SMTP'});
+ $sender->mailer_args([Host => $smtp]);
+
+ my $stat = $sender->send($tmpl);
+
+ if( $stat and $stat->type eq 'success' ) {
+ $logger->info("OD_notice: successfully sent overdue email");
+ } else {
+ $logger->warn("OD_notice: unable to send hold overdue email: ".Dumper($stat));
+ }
+
+ $logger->info("OD_notice: sending email to".$patron_data->[0]->email);
+}
+
+sub handle_event {
+ my $evt = shift;
+ warn "OD_notice: ".Dumper($evt) . "\n";
+ $logger->error("OD_notice: ".Dumper($evt));
+ return undef;
+}
+
+
+sub entityize {
+ my $stuff = shift || return "";
+ $stuff =~ s/\</</og;
+ $stuff =~ s/\>/>/og;
+ $stuff =~ s/\&/&/og;
+ $stuff = NFC($stuff);
+ $stuff =~ s/([\x{0080}-\x{fffd}])/sprintf('&#x%X;',ord($1))/sgoe;
+ return $stuff;
+}
+
+
+
+
Property changes on: grpl/trunk/patron_notifications/grpl_overdue.pl
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/grpl_overdue.sh
===================================================================
--- grpl/trunk/patron_notifications/grpl_overdue.sh (rev 0)
+++ grpl/trunk/patron_notifications/grpl_overdue.sh 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,30 @@
+#!/bin/bash
+# ---------------------------------------------------------------
+# This file runs the overdue generation script.
+# If today is Monday, it runs the script for Sat/Sun/Mon,
+# otherwise it runs once per day.
+# ---------------------------------------------------------------
+
+
+
+
+SSH_CLIENT=$1
+RECIPIENT=$2;
+DATE=$(date +%Y-%m-%d);
+DAY=$(date +%u);
+BSCONFIG="/openils/conf/opensrf_core.xml"
+ODDIR="/openils/var/data/overdue";
+
+export EG_OVERDUE_EMAIL_TEMPLATE="grpl_overdue_email";
+export EG_OVERDUE_SMTP_HOST="your_email_host";
+export EG_OVERDUE_EMAIL_SENDER="overdues at your_domain";
+
+[ $(whoami) != "opensrf" ] && echo "Must be run as opensrf" && exit 1;
+source ~/.bashrc;
+ARGS="0"
+
+#[ $DAY == 6 -o $DAY == 7 ] && exit 0; # don't run on saturday or sunday
+if [ $DAY == 1 ]; then ARGS="2 1 0"; fi; # If today is monday, run for sat/sun/mon
+
+./grpl_overdue.pl $BSCONFIG $ARGS > "$ODDIR/grpl_overdue.$DATE.xml"
+
Property changes on: grpl/trunk/patron_notifications/grpl_overdue.sh
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/grpl_overdue_email
===================================================================
--- grpl/trunk/patron_notifications/grpl_overdue_email (rev 0)
+++ grpl/trunk/patron_notifications/grpl_overdue_email 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,30 @@
+To: ${EMAIL_RECIPIENT}
+From: ${EMAIL_SENDER}
+Reply-To: ${EMAIL_REPLY_TO}
+Errors-To: ${EMAIL_ERRORS_TO}
+Subject: Overdue Materials Notification
+${EMAIL_HEADERS}
+
+
+${DATE}
+Dear ${FIRST_NAME} ${MIDDLE_NAME} ${LAST_NAME} : ${BARCODE}
+
+
+Our records indicate these items are ${RANGE} days or more overdue:
+
+TITLE AUTHOR CALL NUMBER
+
+${OVERDUE_ITEMS[
+${TITLE} : ${AUTHOR} ${CALL_NUMBER}
+Due: ${DUE_MONTH}/${DUE_DAY}/${DUE_YEAR} ID: ${ITEM_BARCODE}
+]}
+
+
+Please return the above items to avoid additional fines. Please do not
+
+respond to this email. Contact your library for more information:
+
+${ORG_NAME} / ${ORG_ADDRESS}
+${ORG_PHONE}
+
+
Added: grpl/trunk/patron_notifications/holdshelf-result.pl
===================================================================
--- grpl/trunk/patron_notifications/holdshelf-result.pl (rev 0)
+++ grpl/trunk/patron_notifications/holdshelf-result.pl 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,52 @@
+#!/usr/bin/perl
+
+use Asterisk::AGI;
+use DBI;
+use DBD::mysql;
+use LWP;
+
+my $AGI = new Asterisk::AGI;
+
+my %input = $AGI->ReadParse();
+my ($res)=@ARGV;
+#my $res = 'Zap/1-1:1235,1242,1210,1207';
+my $status;
+my ($channel,$hid,$numdialed,$ack) = split(':', $res);
+my @hold_ids = split(',', $hid);
+if ($channel =~ 'Failed') {
+ $status = 'failed'
+} elsif ($ack eq 'ack') {
+ $status = 'acknowledged'
+} else {
+ $status = 'completed'
+}
+my $reason = $AGI->get_variable("HANGUPCAUSE");
+
+my $logdir = "/var/log/asterisk/holdshelf.log";
+my $time;
+
+# update notify server database
+my $dbh=DBI->connect('dbi:mysql:database=notify;host=your_db_host;port=3306', "user", 'passw', { RaiseError => 1, PrintError => 1 } );
+my $sth=$dbh->prepare("update holdshelf set notify_time = now(), notify_status = ? where id = ?");
+my $sth2=$dbh->prepare("select notify_time from holdshelf where id = ?");
+foreach my $h (@hold_ids) {
+ $sth->execute($status,$h);
+ $sth2->execute($h);
+ $time = @{$sth2->fetchrow_arrayref}[0];
+}
+$sth->finish;
+$sth2->finish;
+$dbh->disconnect;
+
+# update hold notice in Evergreen database
+foreach my $h (@hold_ids) {
+ $ua=LWP::UserAgent->new();
+ $egres=$ua->get("http://your_eg_server/cgi-bin/utils/grpl_holdnotice.cgi?h=$h&s=$status");
+}
+
+
+# write local log file
+open (OUT,">>$logdir");
+print OUT "@hold_ids $numdialed $time $res $status $reason\n";
+close (OUT);
+
Property changes on: grpl/trunk/patron_notifications/holdshelf-result.pl
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/import_holdshelf.plx
===================================================================
--- grpl/trunk/patron_notifications/import_holdshelf.plx (rev 0)
+++ grpl/trunk/patron_notifications/import_holdshelf.plx 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,16 @@
+#!/usr/bin/perl -w
+
+use LWP::UserAgent();
+use XML::Simple;
+
+$ua=LWP::UserAgent->new();
+
+$res=$ua->get('http://your_eg_server/cgi-bin/utils/grpl_holdshelf.cgi');
+$c = $res->content;
+
+$outname = ((localtime)[4]+1).(localtime)[3].(localtime)[2].(localtime)[1].'holdshelf';
+open(OUT, ">/usr/notify/$outname");
+print OUT $c;
+close OUT;
+
+system('mysql', 'notify', '-e', "load data infile '/usr/notify/$outname' ignore into table holdshelf fields terminated by '|'");
Property changes on: grpl/trunk/patron_notifications/import_holdshelf.plx
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/make_holdshelf_callfiles.plx
===================================================================
--- grpl/trunk/patron_notifications/make_holdshelf_callfiles.plx (rev 0)
+++ grpl/trunk/patron_notifications/make_holdshelf_callfiles.plx 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,61 @@
+#!/usr/bin/perl -w
+
+use DBI;
+use DBD::mysql;
+
+my $dbh = DBI->connect('dbi:mysql:database=notify', "user", 'passw', { RaiseError => 1, PrintError => 1 } );
+
+# get distinct phone number/pickup library combinations
+my $sth=$dbh->prepare("select id,phone_notify,count(phone_notify) as hnum ,pickup_lib from holdshelf where (notify_time = 0 and notify_status = '') group by phone_notify,pickup_lib having phone_notify <> '' and phone_notify <> 'Block Calls'");
+$sth->execute;
+
+my $sth2= $dbh->prepare("select id from holdshelf where notify_time = 0 and phone_notify = ? and pickup_lib = ?");
+
+my $f;
+my $cft;
+my $channel = 1;
+
+# slurp in default call file
+{
+$f = '/usr/notify/asterisk/holdshelf_template';
+local( $/, *CFT ) ;
+open( CFT, $f) or die "Can't open $f";
+$cft = <CFT>;
+}
+
+while (my $h=$sth->fetchrow_hashref) {
+ my $id = $h->{id};
+ my $num = $h->{phone_notify};
+ my $numholds = $h->{hnum};
+ my $lib = $h->{pickup_lib};
+
+ if ($numholds > 1) { #get all hold ids for this phone number/pickup library
+ $sth2->execute($num,$lib);
+ $id = '';
+ map { $id .= ($$_[0] . ',') } @{$sth2->fetchall_arrayref};
+ chop $id;
+ }
+
+
+ # substitue hold info into call file timeplate
+ my $temp = $cft;
+ $temp =~ s/CHANNEL/$channel/;
+ $temp =~ s/NUM/$num/g;
+ $temp =~ s/ID/$id/;
+ $temp =~ s/PKUPLIB/$lib/;
+
+ # write new call file
+ my $cf = "/usr/notify/asterisk/tmp/$num.holdshelf";
+ open(OUT, ">$cf");
+ print OUT $temp;
+ close OUT;
+
+ # switch to next channel for next call file
+ if ($channel == 1) {
+ $channel = 2
+ } elsif ($channel == 2) {
+ $channel = 3
+ } else { $channel = 1 }
+
+}
+
Property changes on: grpl/trunk/patron_notifications/make_holdshelf_callfiles.plx
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/make_overdue_callfiles.plx
===================================================================
--- grpl/trunk/patron_notifications/make_overdue_callfiles.plx (rev 0)
+++ grpl/trunk/patron_notifications/make_overdue_callfiles.plx 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,52 @@
+#!/usr/bin/perl -w
+
+use DBI;
+use DBD::mysql;
+
+my $dbh = DBI->connect('dbi:mysql:database=notify', "user", 'passw', { RaiseError => 1, PrintError => 1 } );
+
+# get distinct phone number/pickup library combinations
+my $sth=$dbh->prepare("select distinct(phone_num) from overdues where phone_num <> ''");
+$sth->execute;
+
+my $f;
+my $cft;
+my $channel = 1;
+
+# slurp in default call file
+{
+$f = '/usr/notify/asterisk/overdue_template';
+local( $/, *CFT ) ;
+open( CFT, $f) or die "Can't open $f";
+$cft = <CFT>;
+}
+
+while (my $h=$sth->fetchrow_hashref) {
+ #my $id = $h->{keynum};
+ my $num = $h->{phone_num};
+ $num =~ s/\D//g;
+
+
+ # substitue hold info into call file timeplate
+ my $temp = $cft;
+ $temp =~ s/CHANNEL/$channel/;
+ $temp =~ s/NUM/$num/g;
+ #$temp =~ s/ID/$id/;
+
+ # write new call file
+ my $cf = "/usr/notify/asterisk/tmp/$num.overdue";
+ open(OUT, ">$cf");
+ print OUT $temp;
+ close OUT;
+
+ # switch to next channel for next call file
+ if ($channel == 1) {
+ $channel = 2
+ } elsif ($channel == 2) {
+ $channel = 3
+ } elsif ($channel == 3) {
+ $channel = 4
+ } else { $channel = 1 }
+
+}
+
Property changes on: grpl/trunk/patron_notifications/make_overdue_callfiles.plx
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/overdue-result.pl
===================================================================
--- grpl/trunk/patron_notifications/overdue-result.pl (rev 0)
+++ grpl/trunk/patron_notifications/overdue-result.pl 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+# overdue-result.pl
+
+use Asterisk::AGI;
+use DBI;
+use DBD::mysql;
+
+my $AGI = new Asterisk::AGI;
+
+my %input = $AGI->ReadParse();
+my ($res)=@ARGV;
+my $status;
+my ($channel,$odid) = split(':', $res);
+if ($channel =~ 'Failed') {
+ $status = 'failed'
+} else {
+ $status = 'completed'
+}
+
+my $logdir = "/var/log/asterisk/overdues.log";
+my $time;
+
+# update notify server database
+my $dbh=DBI->connect('dbi:mysql:database=notify;host=your_db_host;port=3306', "user", 'passw', { RaiseError => 1, PrintError => 1 } );
+my $sth=$dbh->prepare("update overdues set notify_time = now(), notify_status = ? where id = ?");
+$sth->execute($status,$odid);
+$sth->finish;
+$dbh->disconnect;
+
+# write local log file
+open (OUT,">>$logdir");
+print OUT "$time $res $status \n";
+close (OUT);
+
Property changes on: grpl/trunk/patron_notifications/overdue-result.pl
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/send_holdshelf_emails.plx
===================================================================
--- grpl/trunk/patron_notifications/send_holdshelf_emails.plx (rev 0)
+++ grpl/trunk/patron_notifications/send_holdshelf_emails.plx 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,66 @@
+#!/usr/bin/perl -w
+
+use DBI;
+use DBD::mysql;
+use MIME::Lite;
+use LWP;
+
+my $dbh = DBI->connect('dbi:mysql:database=notify', "user", 'passw', { RaiseError => 1, PrintError => 1 } );
+
+my $sth=$dbh->prepare("select id,email,email_notify,pickup_lib,title,barcode from holdshelf where email <> '' and email_notify='t';");
+$sth->execute;
+
+my $updh=$dbh->prepare("update holdshelf set email_notify='s',notify_time=now() where id = ?");
+
+while (my $m=$sth->fetchrow_hashref) {
+ my $id = $m->{id};
+ my $addr = $m->{email};
+ my $lib = $m->{pickup_lib};
+ my $title = $m->{title};
+ my $bcode = $m->{barcode};
+ my $branch;
+ my $pnum;
+
+ SWITCH: {
+ $_ = $lib;
+ /GRPL-GR/ and do {$branch="Main Library"; $pnum="616 988-5400"; last SWITCH; };
+ /GRPL-GM/ and do {$branch="Madison Square Branch"; $pnum="616 988-5411"; last SWITCH; };
+ /GRPL-GO/ and do {$branch="Ottawa Hills Branch"; $pnum="616 988-5412"; last SWITCH; };
+ /GRPL-GS/ and do {$branch="Seymour Branch"; $pnum="616 988-5413"; last SWITCH; };
+ /GRPL-GC/ and do {$branch="Van Belkum Branch"; $pnum="616 988-5410"; last SWITCH; };
+ /GRPL-GN/ and do {$branch="West Leonard Branch"; $pnum="616 988-5416"; last SWITCH; };
+ /GRPL-GW/ and do {$branch="West Side Branch"; $pnum="616 988-5414"; last SWITCH; };
+ /GRPL-GY/ and do {$branch="Yankee Clipper Branch"; $pnum="616 988-5415"; last SWITCH; };
+ }
+
+ send_me($addr,$branch,$pnum,$title,$bcode);
+ $updh->execute($id);
+ # update hold notice in Evergreen database
+ my $ua=LWP::UserAgent->new();
+ my $hn=$ua->get("http://your_db_host/cgi-bin/utils/grpl_holdnotice.cgi?h=$id&s=email_sent");
+
+}
+
+
+sub send_me {
+ my ($a,$b,$p,$t,$c) = @_;
+
+ $a =~ s/(.*?)(\;.*)/$1/; # if someone thinks it's a good idea to have multiple addresses separated by a semi-colon, trash the second.
+
+ my $body = "Your hold item: $t \nis now available for pickup at the $b. This hold will expire in 7 business days. For more information please call $p.\n\nPatron Barcode: $c.";
+
+ my $msg = MIME::Lite->new(
+ To =>"$a",
+ From =>'holdmsg at your_domain',
+ Subject =>'Library Items on hold',
+ Type =>'multipart/mixed'
+ );
+
+ $msg->attach(
+ Type => 'text/plain',
+ Data => "$body");
+
+ $msg->send('smtp','your_smtp_server',Debug=>0);
+
+}
+
Property changes on: grpl/trunk/patron_notifications/send_holdshelf_emails.plx
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/README-TADL.txt
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/README-TADL.txt (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/README-TADL.txt 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,61 @@
+This is a snapshot of what TADL is using for Evergreen patron notification.
+
+It is based heavily on code shared with TADL by Bill Ott and Doug Kyle
+at the Grand Rapids Public Library (GRPL).
+
+Please address any questions to
+Jeff Godin
+Traverse Area District Library
+231-932-8546
+jgodin at tadl.org
+
+I've made every effort to sanitize these files without rendering them
+useless. Please let me know if I've broken something for you.
+
+A description of the files in this archive follows:
+
+./grpl/
+Collection of original files shared with TADL by GRPL
+
+./overdues-sample.xml
+sample XML generated by GRPL-modified eg_gen_overdue.pl
+
+./asterisk-box/var/lib/asterisk/agi-bin/holdshelf-result.pl
+called via AGI from extensions.conf to record notification
+to mysql table "holdshelf",
+
+./asterisk-box/etc/asterisk/
+Asterisk config is here. Most of the "meat" is in extensions.conf
+
+./asterisk-box/queue-feeder.pl
+Script that feeds /var/spool/asterisk/outgoing one callfile at a time
+
+./notify-box/holdshelf-schema.mysqldump
+Schema for mysql table "holdshelf"
+
+./notify-box/noticeitems-schema.txt
+Schema for postgresql table "noticeitems"
+
+./notify-box/home/notify/bin/xml2obj.py
+./notify-box/home/notify/bin/import-notices.py
+imports overdues.xml data to postgresql table "noticeitems"
+
+./notify-box/home/notify/bin/email-overdues.py
+sends e-mail messages based on postgresql table "noticeitems"
+
+./notify-box/root/import_holdshelf_all.plx
+calls tadl_holdshelf_all.cgi on evergreen server and imports
+data into mysql table "holdshelf" (and others)
+
+./notify-box/root/send_holdshelf_emails.plx
+sends e-mails based on mysql table "holdshelf"
+
+./notify-box/usr/notify/asterisk/holdshelf_template
+./notify-box/usr/notify/asterisk/make_holdshelf_callfiles.plx
+create callfiles for asterisk, based off of this template
+
+./evergreen-server/tadl_holdshelf_all.cgi
+called by import_holdshelf_all.plx
+
+./evergreen-server/tadl_holdnotice.cgi
+called by holdshelf-result.pl
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/asterisk.conf
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/asterisk.conf (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/asterisk.conf 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,9 @@
+[global]
+astetcdir => /etc/asterisk
+astmoddir => /usr/lib/asterisk/modules
+astvarlibdir => /var/lib/asterisk
+astagidir => /var/lib/asterisk/agi-bin
+astspooldir => /var/spool/asterisk
+astrundir => /var/run/asterisk
+astlogdir => /var/log/asterisk
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/cdr.conf
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/cdr.conf (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/cdr.conf 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,10 @@
+[general]
+enable=yes
+unanswered=yes
+
+
+[csv]
+usegmtime=no
+loguniqueid=yes
+loguserfield=yes
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/cdr_pgsql.conf
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/cdr_pgsql.conf (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/cdr_pgsql.conf 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,8 @@
+[global]
+hostname=localhost
+port=5432
+dbname=asterisk
+password=REMOVED
+user=asterisk
+table=cdr
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/extensions.conf
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/extensions.conf (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/extensions.conf 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,216 @@
+;
+; recording and holdshelf contexts based on GRPL-shared extensions.conf
+; which I believe were based on
+; http://www.voip-info.org/wiki/view/Asterisk+auto-dial+out+deliver+message
+;
+; modifications that i can remember here:
+; * modified to prevent double-logging some results
+; * use Background's m argument to prevent hangup on invalid dial (like #)
+;
+; Changed the order of Playback, AGI on holdack so that a hangup during the
+; thank you playback wouldn't result in a no-log, but now the patron gets
+; dead air while that AGI runs. Need to address that.
+;
+
+
+[general]
+static=yes
+writeprotect=yes
+autofallthrough=yes
+
+[globals]
+
+
+[incoming]
+exten => REMOVED,1,Ringing
+exten => REMOVED,n,Wait,3
+exten => REMOVED,n,Answer
+exten => REMOVED,n,Wait,1
+exten => REMOVED,n,Background(tt-monkeys)
+
+include => record-outboundmsgs
+
+[test-outgoing]
+exten => s,1,Answer()
+exten => s,n,Wait(1)
+exten => s,n,Playback(tt-monkeys)
+exten => s,n,Wait(1)
+exten => s,n,Hangup()
+
+[holdshelfmsg]
+exten => s,1,Set(TIMEOUT(digit)=5) ; Set Digit Timeout to 5 seconds
+exten => s,n,Set(TIMEOUT(response)=10) ; Set Response Timeout to 10 seconds
+exten => s,n,Set(NumberDialed=${CUT(PassedInfo,,1)})
+exten => s,n,Set(CDR(accountcode)=${NumberDialed}-${holdid})
+exten => s,n,Answer
+exten => s,n,Monitor()
+exten => s,n,Wait(1)
+
+#begin message
+exten => s,n(start),Background(outboundmsgs/holdshelfmsg1,m) ; hello, you have one or more library items waiting for pickup at
+exten => s,n,Background(outboundmsgs/${pickuplib},m) ; (library name here)
+exten => s,n,Background(outboundmsgs/how_to_ack,m) ; "Press 1 to replay or 2 to acknowledge receiving this message"
+
+#repeat message once
+exten => s,n,Background(outboundmsgs/holdshelfmsg1,m)
+exten => s,n,Background(outboundmsgs/${pickuplib},m)
+exten => s,n,Background(outboundmsgs/how_to_ack,m)
+
+#repeat a second time -- dirty hack for voicemail/answering machines
+exten => s,n,Background(outboundmsgs/holdshelfmsg1,m)
+exten => s,n,Background(outboundmsgs/${pickuplib},m)
+exten => s,n,Background(outboundmsgs/how_to_ack,m)
+
+exten => 1,1,Goto(s,start) ; replay message
+
+exten => 2,1,Goto(holdack,s,1) ; acknowledge message
+
+exten => t,1,Playback(vm-goodbye)
+exten => t,n,AGI(holdshelf-result.pl|${CHANNEL}:${holdid}:${NumberDialed})
+exten => t,n,Set(resultlogged=1)
+exten => t,n,Hangup
+
+exten => h,1,NoOp(Hangup Extension Called, resultlogged: ${resultlogged})
+exten => h,n,GotoIf($[${ISNULL(${resultlogged})}]?hanguplog,1:hangupnolog,1)
+
+exten => hanguplog,1,NoOp(Hangup log extension reached)
+exten => hanguplog,n,DEADAGI(holdshelf-result.pl|${CHANNEL}:${holdid}:${NumberDialed})
+
+exten => hangupnolog,1,NoOp(Hangup but NO log extension reached)
+
+exten => failed,1,Set(NumberDialed=${CUT(PassedInfo,,1)})
+exten => failed,n,Set(CDR(userfield)=${NumberDialed})
+exten => failed,n,AGI(holdshelf-result.pl|${CHANNEL}:${holdid}:${NumberDialed})
+exten => failed,n,Set(resultlogged=1)
+
+[holdack]
+exten => s,1,AGI(holdshelf-result.pl|${CHANNEL}:${holdid}:${NumberDialed}:ack)
+exten => s,n,Playback(outboundmsgs/thankyou)
+exten => s,n,Hangup
+
+[record-outboundmsgs]
+; Record voice files
+;
+; Before using this the first time
+; mkdir /var/lib/asterisk/sounds/outboundmsgs
+; chown asterisk_user:asterisk_user /var/lib/asterisk/sounds/outboundmsgs
+; (Where asterisk_user = the user that asterisk runs under: = root for many installations)
+;
+; In a context for incoming calls put something like
+; include => record-outboundmsgs
+;
+; Then call
+; 2051 to Record a new outbound msg1
+; 2052 to Record a new outbound holdshelfmsg1
+;
+; 2061 to Record the msg played when the recipient acks the message
+; 2062 to Record the "How to ACK message"
+;
+; After dialing one of the extensions above:
+; Wait for the record start tone
+; Record your message
+; Press # to stop recording
+; Listen to an automatic playback of your new message
+;
+; outbound msg1
+exten => 2051,1,Wait(2)
+exten => 2051,2,Record(outboundmsgs/msg1:gsm)
+exten => 2051,3,Wait(2)
+exten => 2051,4,Playback(outboundmsgs/msg1)
+exten => 2051,5,wait(2)
+exten => 2051,6,Hangup
+;
+; outbound holdshelfmsg1
+exten => 2052,1,Wait(2)
+exten => 2052,2,Record(outboundmsgs/holdshelfmsg1:gsm)
+exten => 2052,3,Wait(2)
+exten => 2052,4,Playback(outboundmsgs/holdshelfmsg1)
+exten => 2052,5,wait(2)
+exten => 2052,6,Hangup
+;
+; outbound overduemsg1
+exten => 2053,1,Wait(2)
+exten => 2053,2,Record(outboundmsgs/overduemsg1:gsm)
+exten => 2053,3,Wait(2)
+exten => 2053,4,Playback(outboundmsgs/overduemsg1)
+exten => 2053,5,wait(2)
+exten => 2053,6,Hangup
+;
+; Msg played when msg is acked
+exten => 2061,1,Wait(2)
+exten => 2061,2,Record(outboundmsgs/thankyou:gsm)
+exten => 2061,3,Wait(2)
+exten => 2061,4,Playback(outboundmsgs/thankyou)
+exten => 2061,5,wait(2)
+exten => 2061,6,Hangup
+;
+; Msg played after outbound msg: "Press 1 to replay or 2 to acknowledge receiving this message"
+exten => 2062,1,Wait(2)
+exten => 2062,2,Record(outboundmsgs/how_to_ack:gsm)
+exten => 2062,3,Wait(2)
+exten => 2062,4,Playback(outboundmsgs/how_to_ack)
+exten => 2062,5,wait(2)
+exten => 2062,6,Hangup
+;
+; main
+exten => 2071,1,Wait(2)
+exten => 2071,2,Record(outboundmsgs/TADL-WOOD:gsm)
+exten => 2071,3,Wait(2)
+exten => 2071,4,Playback(outboundmsgs/TADL-WOOD)
+exten => 2071,5,wait(2)
+exten => 2071,6,Hangup
+;
+; main phone
+exten => 2171,1,Wait(2)
+exten => 2171,2,Record(outboundmsgs/TADL-WOOD-phone:gsm)
+exten => 2171,3,Wait(2)
+exten => 2171,4,Playback(outboundmsgs/TADL-WOOD-phone)
+exten => 2171,5,wait(2)
+exten => 2171,6,Hangup
+;
+
+;
+; interlochen
+exten => 2072,1,Wait(2)
+exten => 2072,2,Record(outboundmsgs/TADL-IPL:gsm)
+exten => 2072,3,Wait(2)
+exten => 2072,4,Playback(outboundmsgs/TADL-IPL)
+exten => 2072,5,wait(2)
+exten => 2072,6,Hangup
+
+;
+; kingsley
+exten => 2073,1,Wait(2)
+exten => 2073,2,Record(outboundmsgs/TADL-KBL:gsm)
+exten => 2073,3,Wait(2)
+exten => 2073,4,Playback(outboundmsgs/TADL-KBL)
+exten => 2073,5,wait(2)
+exten => 2073,6,Hangup
+
+;
+; peninsula
+exten => 2074,1,Wait(2)
+exten => 2074,2,Record(outboundmsgs/TADL-PCL:gsm)
+exten => 2074,3,Wait(2)
+exten => 2074,4,Playback(outboundmsgs/TADL-PCL)
+exten => 2074,5,wait(2)
+exten => 2074,6,Hangup
+
+;
+; fife lake
+exten => 2075,1,Wait(2)
+exten => 2075,2,Record(outboundmsgs/TADL-FLPL:gsm)
+exten => 2075,3,Wait(2)
+exten => 2075,4,Playback(outboundmsgs/TADL-FLPL)
+exten => 2075,5,wait(2)
+exten => 2075,6,Hangup
+
+;
+; east bay
+exten => 2076,1,Wait(2)
+exten => 2076,2,Record(outboundmsgs/TADL-EBB:gsm)
+exten => 2076,3,Wait(2)
+exten => 2076,4,Playback(outboundmsgs/TADL-EBB)
+exten => 2076,5,wait(2)
+exten => 2076,6,Hangup
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/features.conf
===================================================================
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/modules.conf
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/modules.conf (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/modules.conf 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,67 @@
+[modules]
+autoload=yes
+;
+; Any modules that need to be loaded before the Asterisk core has been
+; initialized (just after the logger has been initialized) can be loaded
+; using 'preload'. This will frequently be needed if you wish to map all
+; module configuration files into Realtime storage, since the Realtime
+; driver will need to be loaded before the modules using those configuration
+; files are initialized.
+;
+; An example of loading ODBC support would be:
+;preload => res_odbc.so
+;preload => res_config_odbc.so
+;
+; If you want, load the GTK console right away.
+; Don't load the KDE console since
+; it's not as sophisticated right now.
+;
+noload => pbx_gtkconsole.so
+;load => pbx_gtkconsole.so
+noload => pbx_kdeconsole.so
+;
+; Intercom application is obsoleted by
+; chan_oss. Don't load it.
+;
+noload => app_intercom.so
+;
+; The 'modem' channel driver and its subdrivers are
+; obsolete, don't load them.
+;
+noload => chan_modem.so
+noload => chan_modem_aopen.so
+noload => chan_modem_bestdata.so
+noload => chan_modem_i4l.so
+noload => chan_capi.so
+;
+noload => res_musiconhold.so
+;
+; Load either OSS or ALSA, not both
+; By default, load OSS only (automatically) and do not load ALSA
+;
+noload => chan_alsa.so
+;noload => chan_oss.so
+
+;jeff
+noload => chan_agent.so
+noload => chan_iax2.so
+noload => chan_mgcp.so
+noload => chan_oss.so
+noload => chan_phone.so
+noload => chan_skinny.so
+noload => app_voicemail.so
+noload => app_followme.so
+noload => app_queue.so
+noload => pbx_ael.so
+noload => pbx_dundi.so
+noload => cdr_custom.so
+noload => res_smdi.so
+noload => res_config_pgsql.so
+noload => app_amd.so
+noload => app_festival.so
+
+;
+; Module names listed in "global" section will have symbols globally
+; exported to modules loaded after them.
+;
+[global]
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/sip.conf
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/sip.conf (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/etc/asterisk/sip.conf 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,26 @@
+[clearrate-voip1]
+type=friend
+call-limit=1
+qualify=250
+host=REMOVED
+trustrpid = yes
+sendrpid = yes
+disallow=all
+allow=ulaw
+insecure=port,invite
+context=incoming
+dtmfmode=rfc2833
+
+[clearrate-voip2]
+type=friend
+call-limit=1
+qualify=250
+host=REMOVED
+trustrpid = yes
+sendrpid = yes
+disallow=all
+allow=ulaw
+insecure=port,invite
+context=incoming
+dtmfmode=rfc2833
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/queue-feeder.pl
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/queue-feeder.pl (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/queue-feeder.pl 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,70 @@
+#!/usr/bin/perl
+
+#
+# Copyright 2008 Traverse Area District Library
+# Jeff Godin <jeff at tcnet.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+
+my $tmpdir = "/var/spool/asterisk/tmp";
+my $outdir = "/var/spool/asterisk/outgoing";
+
+use strict;
+
+my $fullcount;
+my $files;
+
+while () {
+
+ opendir(OUTDIR,$outdir);
+ my @outfiles = readdir(OUTDIR);
+
+ my $outcount = scalar(@outfiles);
+
+ if ($outcount > 2) {
+ $fullcount++;
+ #print "output full $fullcount times!\n";
+ if ($fullcount > 20) {
+ print "touching $outdir and resetting fullcount...\n";
+ system("touch", $outdir);
+ $fullcount = 0;
+ }
+ } else {
+ print "output not full!\n";
+ opendir(TMPDIR,$tmpdir);
+ while (my $tmpfile = readdir(TMPDIR)) {
+ next if $tmpfile =~ /^\./;
+ print "moving $tmpfile\n";
+ system("chown", "asterisk:", $tmpdir . "/" . $tmpfile);
+ system("mv", $tmpdir . "/" . $tmpfile, $outdir);
+ $files++;
+ $fullcount = 0;
+ opendir(COUNTDIR,$tmpdir);
+ my $filecount;
+ $filecount = 0;
+ while ( my $countfile = readdir(COUNTDIR)) {
+ next if $countfile =~ /^\./;
+ $filecount++;
+ }
+ print "$files files moved, $filecount files remain.\n";
+ my $avgtime;
+ if ($files > 2) {
+ $avgtime = (time() - $^T) / ($files - 1);
+ my $completetime = time() + ($avgtime * $filecount);
+ print "avgtime = $avgtime - expect complete at " . scalar localtime($completetime) . "\n";
+ }
+ last;
+ }
+ }
+
+ sleep 5;
+}
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var/lib/asterisk/agi-bin/holdshelf-result.pl
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var/lib/asterisk/agi-bin/holdshelf-result.pl (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/asterisk-box/var/lib/asterisk/agi-bin/holdshelf-result.pl 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,62 @@
+#!/usr/bin/perl
+
+# GRPL-shared code
+# modified by TADL:
+# * use proxy server on localhost
+# * don't record notification in Evergreen if "failed"
+#
+
+use Asterisk::AGI;
+use DBI;
+use DBD::mysql;
+use LWP;
+
+$ENV{http_proxy} = "localhost:3128";
+
+my $AGI = new Asterisk::AGI;
+
+my %input = $AGI->ReadParse();
+my ($res)=@ARGV;
+#my $res = 'Zap/1-1:1235,1242,1210,1207';
+my $status;
+my ($channel,$hid,$numdialed,$ack) = split(':', $res);
+my @hold_ids = split(',', $hid);
+if ($channel =~ 'Failed') {
+ $status = 'failed'
+} elsif ($ack eq 'ack') {
+ $status = 'acknowledged'
+} else {
+ $status = 'completed'
+}
+
+my $logdir = "/var/log/asterisk/holdshelf.log";
+my $time;
+
+# update notify server database
+#my $dbh=DBI->connect('dbi:mysql:database=notify;host=127.0.0.1;port=3306', "user", 'pass', { RaiseError => 1, PrintError => 1 } );
+my $dbh=DBI->connect('dbi:mysql:database=notify;host=127.0.0.1;port=3306', "root", undef, { RaiseError => 1, PrintError => 1 } );
+my $sth=$dbh->prepare("update holdshelf set notify_time = now(), notify_status = ? where id = ?");
+my $sth2=$dbh->prepare("select notify_time from holdshelf where id = ?");
+foreach my $h (@hold_ids) {
+ $sth->execute($status,$h);
+ $sth2->execute($h);
+ $time = @{$sth2->fetchrow_arrayref}[0];
+}
+$sth->finish;
+$sth2->finish;
+$dbh->disconnect;
+
+# update hold notice in Evergreen database
+foreach my $h (@hold_ids) {
+ # $ua=LWP::UserAgent->new();
+ # $egres=$ua->get("http://eg1.michiganevergreen.org/cgi-bin/utils/grpl_holdnotice.cgi?h=$h&s=$status");
+## system("/usr/bin/wget", "-q", "http://eg1.michiganevergreen.org/cgi-bin/utils/grpl_holdnotice.cgi?h=$h&s=$status");
+ system("/usr/bin/wget", "-q", "http://eg1.michiganevergreen.org/cgi-bin/utils/tadl/tadl_holdnotice.cgi?h=$h&s=$status") unless $status =~ 'failed';
+}
+
+
+# write local log file
+open (OUT,">>$logdir");
+print OUT "@hold_ids $numdialed $time $res $status \n";
+close (OUT);
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/evergreen-server/tadl_holdnotice.cgi
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/evergreen-server/tadl_holdnotice.cgi (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/evergreen-server/tadl_holdnotice.cgi 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,43 @@
+#!/usr/bin/perl
+
+# GRPL-shared code
+# oils_login() needs credentials
+
+require '/openils/bin/support-scripts/oils_header.pl';
+use OpenILS::Utils::CStoreEditor q/:funcs/;
+use CGI qw(:standard);
+use DateTime;
+use DateTime::Format::ISO8601;
+
+print "Content-type: text/html\n\n";
+
+my $conf = '/openils/conf/opensrf_core.xml';
+
+my $holdid = param('h');
+my $status = param('s');
+
+my $d = DateTime->now;
+$d->add(days=>10);
+
+osrf_connect($conf);
+my $auth = oils_login('','');
+
+#my $we = new_editor(xact=>1, requestor=>1);
+#$we = new_editor(xact=>1, requestor=>$auth);
+$we = new_editor(xact=>1, authtoken => $auth);
+my $notify = Fieldmapper::action::hold_notification->new;
+$notify->hold($holdid);
+$notify->notify_time('now');
+$notify->method($status);
+$notify->notify_staff(1);
+$we->create_action_hold_notification($notify)
+ or return $we->die_event;
+$we->commit;
+
+#my $e = new_editor(authtoken=>$auth, xact=>1);
+#my $hold = $e->retrieve_action_hold_request($holdid);
+#$hold->expire_time($d->ymd);
+#$e->update_action_hold_request($hold)
+# or return $e->event;
+#$e->commit;
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/evergreen-server/tadl_holdshelf_all.cgi
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/evergreen-server/tadl_holdshelf_all.cgi (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/evergreen-server/tadl_holdshelf_all.cgi 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+
+# GRPL-shared code
+# oils_login() needs credentials
+# minor tweak by TADL to output all holds on shelf, not just those
+# that have not yet been notified
+#
+# hold id 53619 is when we re-enabled the phone
+# notification option in the patron OPAC
+# -- we force phone notification for holds before that id
+#
+
+require '/openils/bin/support-scripts/oils_header.pl';
+use OpenILS::Utils::CStoreEditor q/:funcs/;
+use CGI qw(:standard);
+
+print "Content-type: text/html\n\n";
+
+my $conf = '/openils/conf/opensrf_core.xml';
+
+foreach my $loc (23..28) {
+ osrf_connect($conf);
+ my $authtok = oils_login('','');
+
+ my $ses = OpenSRF::AppSession->create( "open-ils.circ" );
+ my $req = $ses->request('open-ils.circ.captured_holds.on_shelf.retrieve', $authtok, $loc);
+ while(my $resp = $req->recv(timeout => 120)) {
+ my $hid = $resp->content;
+ my $hd = simplereq( CIRC(), 'open-ils.circ.hold.details.retrieve', $authtok, $$hid[14]);
+ my $hh = wrap_perl($hd);
+
+ my $avtime;
+ if ($hh->{hold}->{transit}) {
+ $avtime = $hh->{hold}->{transit}->{dest_recv_time}
+ }
+
+ my $pnotify = $hh->{hold}->{phone_notify};
+ my $p = simplereq( ACTOR(),'open-ils.actor.user.fleshed.retrieve', $authtok, $hh->{hold}->{usr});
+ my $ph = wrap_perl($p);
+ if ( !$pnotify && ($hh->{hold}->{id} < 53619) ) {
+ $pnotify = $ph->{day_phone};
+ }
+ $pnotify =~ s/(\d+)\D+(\d+)\D+(\d+).*/$1$2$3/;
+ $pnotify =~ s/\(//;
+ $pnotify =~ s/\///g;
+ foreach my $sc (@{$p}[10]) {
+ foreach my $v (@{$sc}) {
+ if ($v->{stat_cat_entry} eq 'Block Calls') {
+ $pnotify = 'Block Calls';
+ }
+ }
+ }
+ my $o = simplereq(ACTOR(), 'open-ils.actor.org_unit.retrieve', $authtok, $loc);
+ my $oh = wrap_perl($o);
+ my $oa = simplereq(ACTOR(), 'open-ils.actor.org_unit.address.retrieve', $oh->{mailing_address});
+ my $oah= wrap_perl($oa);
+ $avtime = $hh->{hold}->{capture_time} unless $avtime;
+ $avtime =~ s/(\d\d\d\d-\d\d-\d\d)T(\d\d:\d\d:\d\d).*/$1 $2/;
+ print "$hh->{hold}->{id}|$ph->{first_given_name}|$ph->{family_name}|$ph->{mailing_address}->{street1}|$ph->{mailing_address}->{city}|$ph->{mailing_address}->{state}|$ph->{mailing_address}->{post_code}|$ph->{email}|$hh->{hold}->{email_notify}|$pnotify|$hh->{hold}->{notify_time}|$avtime|$hh->{mvr}->{title}|$hh->{mvr}->{author}|$oh->{shortname}|$oah->{street1}|$oah->{city}|$oah->{state}|$oah->{post_code}||\n";
+ } # end while
+} # end foreach
+
+sub wrap_perl {
+ my $obj = shift;
+ my $ref = ref($obj);
+
+ if ($ref =~ /^Fieldmapper/o) {
+ $ref = $obj->json_hint;
+ $obj = $obj->to_bare_hash;
+ }
+
+ if( $ref eq 'HASH' ) {
+ $obj->{$_} = wrap_perl( $obj->{$_} ) for (keys %$obj);
+ } elsif( $ref eq 'ARRAY' ) {
+ $obj->[$_] = wrap_perl( $obj->[$_] ) for(0..scalar(@$obj) - 1 );
+ } elsif( $ref ) {
+ if(UNIVERSAL::isa($obj, 'HASH')) {
+ $obj->{$_} = wrap_perl( $obj->{$_} ) for (keys %$obj);
+ bless($obj, 'HASH'); # so our parser won't add the hints
+ } elsif(UNIVERSAL::isa($obj, 'ARRAY')) {
+ $obj->[$_] = wrap_perl( $obj->[$_] ) for(0..scalar(@$obj) - 1);
+ bless($obj, 'ARRAY'); # so our parser won't add the hints
+ }
+# $obj = { $CLASS_KEY => $ref, $PAYLOAD_KEY => $obj };
+ }
+ return $obj;
+}
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/holdshelf-schema.mysqldump
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/holdshelf-schema.mysqldump (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/holdshelf-schema.mysqldump 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,57 @@
+-- MySQL dump 10.11
+--
+-- Host: localhost Database: notify
+-- ------------------------------------------------------
+-- Server version 5.0.32-Debian_7etch8-log
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `holdshelf`
+--
+
+DROP TABLE IF EXISTS `holdshelf`;
+CREATE TABLE `holdshelf` (
+ `id` int(11) NOT NULL default '0',
+ `first` varchar(32) default NULL,
+ `last` varchar(64) default NULL,
+ `street` varchar(128) default NULL,
+ `city` varchar(32) default NULL,
+ `state` varchar(2) default NULL,
+ `zip` varchar(10) default NULL,
+ `email` varchar(128) default NULL,
+ `email_notify` varchar(1) default NULL,
+ `phone_notify` varchar(12) default NULL,
+ `notify_time` datetime default NULL,
+ `capture_time` datetime default NULL,
+ `title` varchar(255) default NULL,
+ `author` varchar(128) default NULL,
+ `pickup_lib` varchar(128) default NULL,
+ `pickup_street` varchar(128) default NULL,
+ `pickup_city` varchar(32) default NULL,
+ `pickup_state` varchar(2) default NULL,
+ `pcikup_zip` varchar(10) default NULL,
+ `notify_status` varchar(255) default NULL,
+ `failcount` int(11) default NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2009-02-13 16:21:27
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/email-overdues.py
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/email-overdues.py (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/email-overdues.py 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,72 @@
+#!/usr/bin/python
+
+"""
+Copyright 2009 Traverse Area District Library
+Jeff Godin <jeff at tcnet.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+"""
+
+import smtplib
+# these are for python 2.4 -- python 2.5 is different
+from email.MIMEText import MIMEText
+from email.Utils import make_msgid
+# python 2.5 uses:
+#from email.mime.text import MIMEText
+#from email.utils import make_msgid
+
+import psycopg2 as dbapi2
+import psycopg2.extensions
+
+# without this, psycopg2 will often return utf-8 encoded str objects,
+# and we want unicode objects here
+psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
+
+db = dbapi2.connect(database="notify", user="notify")
+cur = db.cursor()
+cur.execute("select count(item_circ_id) as total_overdue, date_trunc('day', max(file_time))::date as file_date, patron_fullname, patron_email, patron_sys_id from noticeitems where patron_email <> '' and notified_email = false group by patron_fullname, patron_email, patron_sys_id")
+rows = cur.fetchall()
+for row in rows:
+ (total_overdue, file_date, patron_fullname, patron_email, patron_sys_id) = row
+ body = u'\nOur records show that the following '
+ if ( total_overdue == 1 ):
+ body = body + 'item is overdue. \n\n'
+ else:
+ body = body + '%s items are overdue. \n\n' % (total_overdue, )
+ itemcur = db.cursor()
+ itemcur.execute('select distinct item_circ_id, item_title, item_author, item_duedate FROM noticeitems WHERE notified_email = false and patron_sys_id = %s;', (patron_sys_id, ))
+ itemrows = itemcur.fetchall()
+ for itemrow in itemrows:
+ (item_circ_id, item_title, item_author, item_duedate) = itemrow
+ body = body + "Title: " + item_title.strip() + '\n'
+ body = body + "Author: " + item_author.strip() + '\n'
+ body = body + "Due: " + str(item_duedate) + '\n'
+ body = body + '\n'
+ if ( total_overdue == 1 ):
+ itemref = 'this item'
+ else:
+ itemref = 'these items'
+ body = body + 'If you have already returned %s, please disregard this message.\nFor your convenience, you may return %s to any of the libraries in the Traverse Area District Library system.\n\nThank you!' % (itemref, itemref)
+ msg = MIMEText(body, 'plain', 'latin-1')
+ msg['Subject'] = 'Overdue library materials as of %s' % (file_date, )
+ msg['From'] = 'TADL Evergreen Notifications <notify at catalog.tadl.org>'
+ to = patron_fullname + ' <' + patron_email + '>'
+ msg['To'] = to
+ msgid = make_msgid()
+ msg['Message-ID'] = msgid
+ print msg.as_string()
+ s = smtplib.SMTP('egmx')
+ s.sendmail('notify at catalog.tadl.org', patron_email, msg.as_string())
+ s.close()
+ statuscur = db.cursor()
+ statuscur.execute("UPDATE noticeitems SET notified_email = true, notified_email_msgid = %s, notified_email_time = now() where notified_email = false and patron_sys_id = %s", (msgid, patron_sys_id, ))
+ db.commit()
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/import-notices.py
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/import-notices.py (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/import-notices.py 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,86 @@
+#!/usr/bin/python
+
+"""
+Copyright 2009 Traverse Area District Library
+Jeff Godin <jeff at tcnet.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+"""
+
+from optparse import OptionParser
+import string
+import sys
+
+import psycopg2 as dbapi2
+
+from xml2obj import Xml2Obj
+
+optparser = OptionParser()
+optparser.add_option("-f", "--file", dest="filename")
+(options, args) = optparser.parse_args()
+xmlparser = Xml2Obj()
+if (options.filename == None):
+ optparser.error('-f/--file argument is required')
+
+file = xmlparser.Parse(options.filename)
+
+db = dbapi2.connect (database="notify", user="notify")
+cur = db.cursor()
+
+file_type = file.getAttribute('type')
+file_time = file.getAttribute('date') + ' ' + file.getAttribute('time')
+agencies = file.getElements('agency')
+for agency in agencies:
+ agency_name = agency.getAttribute('name')
+ notices = agency.getElements('notice')
+ for notice in notices:
+ notice_type = notice.getAttribute('type')
+ notice_count = notice.getAttribute('count')
+ patron = notice.getElements('patron')[0]
+ patron_sys_id = patron.getElements('sys_id')[0].getData()
+ patron_barcode = patron.getElements('id')[0].getData()
+ patron_fullname = patron.getElements('fullname')[0].getData()
+ patron_day_phone = patron.getElements('day_phone')[0].getData()
+ patron_email = patron.getElements('email')[0].getData()
+ libraries = notice.getElements('library')
+ for library in libraries:
+ library_name = library.getElements('libname')[0].getData()
+ items = notice.getElements('item')
+ for item in items:
+ item_title = item.getElements('title')[0].getData()
+ item_author = item.getElements('author')[0].getData()
+ item_duedate = item.getElements('duedate')[0].getData()
+ item_callno = item.getElements('callno')[0].getData()
+ item_location = item.getElements('location')[0].getData()
+ item_barcode = item.getElements('barcode')[0].getData()
+ item_circ_id = item.getElements('circ_id')[0].getData()
+ item_check_out = item.getElements('check_out')[0].getData()
+ item_item_price = item.getElements('item_price')[0].getData()
+ if isinstance(item_author, str):
+ print type(item_author)
+ print item_author
+ insert_query = "INSERT INTO noticeitems (file_type, \
+ file_time, agency_name, notice_type, notice_count, \
+ patron_sys_id, patron_barcode, patron_fullname, \
+ patron_day_phone, patron_email, library_name, item_title, \
+ item_author, item_duedate, item_callno, item_location, \
+ item_barcode, item_circ_id, item_check_out, item_item_price) \
+ VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, \
+ %s, %s, %s, %s, %s, %s, %s)"
+ insert_row = (file_type, file_time, agency_name, notice_type,
+ notice_count, patron_sys_id, patron_barcode,
+ patron_fullname, patron_day_phone, patron_email,
+ library_name, item_title, item_author,
+ item_duedate, item_callno, item_location,
+ item_barcode, item_circ_id, item_check_out,
+ item_price)
+ cur.execute(insert_query, insert_row)
+ db.commit()
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/xml2obj.py
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/xml2obj.py (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/home/notify/bin/xml2obj.py 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,103 @@
+#!/usr/bin/python
+
+"""
+This code is taken from ActiveState Code Recipe 149368: xml2obj
+"A generic script using expat to convert xml into objects"
+http://code.activestate.com/recipes/149368/
+posted Wed, 11 Sep 2002
+
+Note: Recipes that were part of the original Python Cookbook -- Python
+recipes submitted before July 15, 2008 -- on ASPN (aspn.activestate.com) are
+under the Python license in accordance with the Python Cookbook agreement.
+"""
+
+"""
+Borrowed from wxPython XML tree demo and modified.
+"""
+
+import string
+from xml.parsers import expat
+
+class Element:
+ 'A parsed XML element'
+ def __init__(self,name,attributes):
+ 'Element constructor'
+ # The element's tag name
+ self.name = name
+ # The element's attribute dictionary
+ self.attributes = attributes
+ # The element's cdata
+ self.cdata = u''
+ # The element's child element list (sequence)
+ self.children = []
+
+ def AddChild(self,element):
+ 'Add a reference to a child element'
+ self.children.append(element)
+
+ def getAttribute(self,key):
+ 'Get an attribute value'
+ return self.attributes.get(key)
+
+ def getData(self):
+ 'Get the cdata'
+ return self.cdata
+
+ def getElements(self,name=''):
+ 'Get a list of child elements'
+ #If no tag name is specified, return the all children
+ if not name:
+ return self.children
+ else:
+ # else return only those children with a matching tag name
+ elements = []
+ for element in self.children:
+ if element.name == name:
+ elements.append(element)
+ return elements
+
+class Xml2Obj:
+ 'XML to Object'
+ def __init__(self):
+ self.root = None
+ self.nodeStack = []
+
+ def StartElement(self,name,attributes):
+ 'SAX start element even handler'
+ # Instantiate an Element object
+ element = Element(name.encode(),attributes)
+
+ # Push element onto the stack and make it a child of parent
+ if len(self.nodeStack) > 0:
+ parent = self.nodeStack[-1]
+ parent.AddChild(element)
+ else:
+ self.root = element
+ self.nodeStack.append(element)
+
+ def EndElement(self,name):
+ 'SAX end element event handler'
+ self.nodeStack = self.nodeStack[:-1]
+
+ def CharacterData(self,data):
+ 'SAX character data event handler'
+ if string.strip(data):
+ #data = data.encode()
+ element = self.nodeStack[-1]
+ element.cdata += data
+ return
+
+ def Parse(self,filename):
+ # Create a SAX parser
+ Parser = expat.ParserCreate()
+
+ # SAX event handlers
+ Parser.StartElementHandler = self.StartElement
+ Parser.EndElementHandler = self.EndElement
+ Parser.CharacterDataHandler = self.CharacterData
+
+ # Parse the XML File
+ ParserStatus = Parser.Parse(open(filename,'r').read(), 1)
+
+ return self.root
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/noticeitems-schema.txt
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/noticeitems-schema.txt (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/noticeitems-schema.txt 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,26 @@
+create table noticeitems (
+file_type text,
+file_time timestamp,
+agency_name text,
+notice_type text,
+notice_count text,
+patron_sys_id text,
+patron_barcode text,
+patron_fullname text,
+patron_day_phone text,
+patron_email text,
+library_name text,
+item_title text,
+item_author text,
+item_duedate date,
+item_callno text,
+item_location text,
+item_barcode text,
+item_circ_id text,
+item_check_out date,
+item_item_price money,
+notified_email boolean default False,
+notified_email_msgid text,
+notified_email_time timestamp with time zone
+);
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/root/import_holdshelf_all.plx
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/root/import_holdshelf_all.plx (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/root/import_holdshelf_all.plx 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,46 @@
+#!/usr/bin/perl -w
+
+# GRPL-shared code with some messy SQL for handling the way TADL
+# uses the holdshelf database for notifications
+# * also added "failcount" to track number of failed calls
+# * "holdshelfnonotify" for holds we can't even attempt to notify
+#
+
+use LWP::UserAgent();
+use XML::Simple;
+
+$ua=LWP::UserAgent->new();
+
+$res=$ua->get('http://eg1.michiganevergreen.org/cgi-bin/utils/tadl/tadl_holdshelf_all.cgi');
+$c = $res->content;
+
+$outname = ((localtime)[4]+1).(localtime)[3].(localtime)[2].(localtime)[1].'holdshelf_all';
+open(OUT, ">/root/$outname");
+print OUT $c;
+close OUT;
+
+system('mysql', 'notify', '-e', "load data infile '/root/$outname' ignore into table holdshelf fields terminated by '|'");
+
+#stop forcing email notification on
+#system('mysql', 'notify', '-e', "update holdshelf set email_notify = 't' where email <> '' and email_notify = 'f';");
+#and only force it on for pre-migration-complete holds:
+system('mysql', 'notify', '-e', "update holdshelf set email_notify = 't' where id <= 45446 and email <> '' and email_notify = 'f';");
+system('mysql', 'notify', '-e', "update holdshelf set email_notify = 'f' where email = '' and email_notify = 't';");
+
+system('mysql', 'notify', '-e', "drop table holdnonotify;");
+system('mysql', 'notify', '-e', "create table holdnonotify like holdshelf;");
+system('mysql', 'notify', '-e', "insert into holdnonotify select * from holdshelf where email_notify='f' and phone_notify='';");
+system('mysql', 'notify', '-e', "delete from holdshelf where email_notify='f' and phone_notify=''");
+
+system('mysql', 'notify', '-e', "drop table tempshelf;");
+system('mysql', 'notify', '-e', "create table tempshelf like holdshelf;");
+system('mysql', 'notify', '-e', "load data infile '/root/$outname' ignore into table tempshelf fields terminated by '|'");
+
+system('mysql', 'notify', '-e', "drop table delshelf;");
+system('mysql', 'notify', '-e', "create table delshelf like holdshelf;");
+system('mysql', 'notify', '-e', "insert into delshelf select holdshelf.* from holdshelf left join tempshelf on holdshelf.id = tempshelf.id where tempshelf.id is null;");
+system('mysql', 'notify', '-e', "delete holdshelf from holdshelf inner join delshelf where delshelf.id = holdshelf.id;");
+
+system('mysql', 'notify', '-e', "update holdshelf set notify_status = '', failcount = coalesce(failcount,0) + 1 where notify_status = 'failed';");
+
+#%hold_info = %{XMLin($c, NoAttr => 1, ForceArray => 1)};
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/root/send_holdshelf_emails.plx
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/root/send_holdshelf_emails.plx (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/root/send_holdshelf_emails.plx 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,66 @@
+#!/usr/bin/perl -w
+
+# GRPL-shared code with minor (mostly config) tweaks for TADL
+
+use DBI;
+use DBD::mysql;
+use MIME::Lite;
+use LWP;
+
+my $dbh = DBI->connect('dbi:mysql:database=notify', "", '', { RaiseError => 1, PrintError => 1 } );
+#$dbh->trace(4);
+
+my $sth=$dbh->prepare("select id,email,email_notify,pickup_lib,title from holdshelf where email <> '' and email_notify='t';");
+$sth->execute;
+
+my $updh=$dbh->prepare("update holdshelf set email_notify='s',notify_time=now() where id = ?");
+
+while (my $m=$sth->fetchrow_hashref) {
+ my $id = $m->{id};
+ my $addr = $m->{email};
+ my $lib = $m->{pickup_lib};
+ my $title = $m->{title};
+ my $branch;
+ my $pnum;
+
+ SWITCH: {
+ $_ = $lib;
+ /TADL-EBB/ and do {$branch="East Bay Branch"; $pnum="231 922-2085"; last SWITCH; };
+ /TADL-FLPL/ and do {$branch="Fife Lake Public Library"; $pnum="231 879-4101"; last SWITCH; };
+ /TADL-IPL/ and do {$branch="Interlochen Public Library"; $pnum="231 276-6767"; last SWITCH; };
+ /TADL-KBL/ and do {$branch="Kingley Branch"; $pnum="231 263-5484"; last SWITCH; };
+ /TADL-PCL/ and do {$branch="Peninsula Community Library"; $pnum="231 223-7700"; last SWITCH; };
+ /TADL-WOOD/ and do {$branch="Woodmere (Main) Branch"; $pnum="231 932-8500"; last SWITCH; };
+ }
+ print "sending for hold $id\n";
+ send_me($addr,$branch,$pnum,$title);
+ $updh->execute($id);
+ # update hold notice in Evergreen database
+ my $ua=LWP::UserAgent->new();
+ my $hn=$ua->get("http://eg1.michiganevergreen.org/cgi-bin/utils/tadl/tadl_holdnotice.cgi?h=$id&s=email_sent");
+
+}
+
+
+sub send_me {
+ my ($a,$b,$p,$t) = @_;
+
+ $a =~ s/(.*?)(\;.*)/$1/; # if someone thinks it's a good idea to have multiple addresses separated by a semi-colon, trash the second.
+
+ my $body = "Your hold item: $t is now available for pickup at the $b. \n This hold will expire in 7 days. For more information please call $p. \n\n This is an outgoing email address only. Please do not respond.";
+
+ my $msg = MIME::Lite->new(
+ To =>"$a",
+ From =>'"TADL Catalog" <Reserve.Notification at catalog.tadl.org>',
+ Subject =>'Your reserve is in at the Traverse Area District Library',
+ Type =>'multipart/mixed'
+ );
+
+ $msg->attach(
+ Type => 'text/plain',
+ Data => "$body");
+
+ $msg->send('smtp','egmx.in.tcnet.org',Debug=>0);
+
+}
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk/holdshelf_template
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk/holdshelf_template (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk/holdshelf_template 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,13 @@
+; GRPL-shared template, used by make_holdshelf_callfiles.plx
+; see that script for mention of TADL changes
+CallerID: CIDNAME <CIDNO>
+Channel: SIP/clearrate-voip1/NUM ; outgoing channel and phone number to dial
+Set: holdid=HOLDID ; local variable to identify hold
+Set: pickuplib=PKUPLIB ; local variable to identify pickup library
+WaitTime: 60 ; total time allowed to complete call
+MaxRetries: 0 ; retry attempts that is, initial call plus 1 retry = 2 calls
+RetryTime: 600 ; time between retries
+Context: holdshelfmsg ; see extensions.conf
+Extension: s ; see extensions.conf
+Priority: 1
+Set: PassedInfo= NUM
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk/make_holdshelf_callfiles.plx
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk/make_holdshelf_callfiles.plx (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk/make_holdshelf_callfiles.plx 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,117 @@
+#!/usr/bin/perl -w
+
+# GRPL-shared code
+# Summary of TADL modifications to this file:
+# * removed channel switching logic - not applicable for us, we use SIP
+# * added caller-id mapping per pickup lib shortname
+# * changed some of the SQL logic
+# * added various queries for placing calls to different subsets of holds
+# (failed, not previously failed, only those not yet emailed, etc)
+#
+
+use DBI;
+use DBD::mysql;
+
+my $dbh = DBI->connect('dbi:mysql:database=notify', "", '', { RaiseError => 1, PrintError => 1 } );
+#$dbh->trace(4);
+
+# get distinct phone number/pickup library combinations
+#my $sth=$dbh->prepare("select id,phone_notify,count(phone_notify) as hnum ,pickup_lib from holdshelf where (notify_time = 0 and notify_status = '') group by phone_notify,pickup_lib having phone_notify <> '' and phone_notify <> 'Block Calls'");
+#my $sth=$dbh->prepare("select id,phone_notify,count(phone_notify) as hnum ,pickup_lib from holdshelf where (email_notify = 'f' and notify_status = '') group by phone_notify,pickup_lib having phone_notify <> '' and phone_notify <> 'Block Calls'");
+
+# normal operation
+my $sth=$dbh->prepare("select id,phone_notify,count(phone_notify) as hnum ,pickup_lib from holdshelf where (notify_status = '') group by phone_notify,pickup_lib having phone_notify <> '' and phone_notify <> 'Block Calls'");
+
+# just those without a failcount
+#my $sth=$dbh->prepare("select id,phone_notify,count(phone_notify) as hnum ,pickup_lib from holdshelf where (notify_status = '' and failcount < 1) group by phone_notify,pickup_lib having phone_notify <> '' and phone_notify <> 'Block Calls'");
+
+# just those with failcount > 0
+#my $sth=$dbh->prepare("select id,phone_notify,count(phone_notify) as hnum ,pickup_lib from holdshelf where (notify_status = '' and failcount > 0) group by phone_notify,pickup_lib having phone_notify <> '' and phone_notify <> 'Block Calls'");
+
+# just those without email
+#my $sth=$dbh->prepare("select id,phone_notify,count(phone_notify) as hnum ,pickup_lib from holdshelf where (notify_status = '' and email = '') group by phone_notify,pickup_lib having phone_notify <> '' and phone_notify <> 'Block Calls'");
+$sth->execute;
+
+#my $sth2= $dbh->prepare("select id from holdshelf where notify_time = 0 and phone_notify = ? and pickup_lib = ?");
+#my $sth2= $dbh->prepare("select id from holdshelf where email_notify = 'f' and phone_notify = ? and pickup_lib = ?");
+my $sth2= $dbh->prepare("select id from holdshelf where phone_notify = ? and pickup_lib = ?");
+
+# define array of lib shortname to callerid data
+%cid = (
+ "TADL-WOOD" => {
+ name => "TADL",
+ number => "2319328500",
+ },
+ "TADL-IPL" => {
+ name => "IPL",
+ number => "2312766767",
+ },
+ "TADL-KBL" => {
+ name => "KBL",
+ number => "2312635484",
+ },
+ "TADL-PCL" => {
+ name => "PCL",
+ number => "2312237700",
+ },
+ "TADL-FLPL" => {
+ name => "FLPL",
+ number => "2318794101",
+ },
+ "TADL-EBB" => {
+ name => "EBB",
+ number => "2319222085",
+ },
+);
+
+my $f;
+my $cft;
+
+# slurp in default call file
+{
+$f = '/usr/notify/asterisk/holdshelf_template';
+local( $/, *CFT ) ;
+open( CFT, $f) or die "Can't open $f";
+$cft = <CFT>;
+}
+
+while (my $h=$sth->fetchrow_hashref) {
+ my $id = $h->{id};
+ my $num = $h->{phone_notify};
+ my $numholds = $h->{hnum};
+ my $lib = $h->{pickup_lib};
+
+ if ($numholds > 1) { #get all hold ids for this phone number/pickup library
+ $sth2->execute($num,$lib);
+ $id = '';
+ map { $id .= ($$_[0] . ',') } @{$sth2->fetchall_arrayref};
+ chop $id;
+ }
+
+
+ # substitue hold info into call file timeplate
+ my $temp = $cft;
+ $temp =~ s/NUM/$num/g;
+ $temp =~ s/HOLDID/$id/;
+ $temp =~ s/PKUPLIB/$lib/;
+ $temp =~ s/CIDNAME/$cid{$lib}{name}/;
+ $temp =~ s/CIDNO/$cid{$lib}{number}/;
+
+
+ # write new call file
+ my $cf = "/usr/notify/asterisk/tmp/$num$lib.holdshelf";
+ open(OUT, ">$cf");
+ print OUT $temp;
+ close OUT;
+
+ # set call file time
+ #my $newtime = time + 120;
+ #my $stamp =
+ #system('touch', '-t', $stamp, $cf);
+
+ # move into queue
+ # system ('mv', $cf, '/var/spool/asterisk/outgoing');
+ # scp to asterisk server
+
+}
+
Property changes on: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/notify-box/usr/notify/asterisk/make_holdshelf_callfiles.plx
___________________________________________________________________
Name: svn:executable
+
Added: grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/overdues-sample.xml
===================================================================
--- grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/overdues-sample.xml (rev 0)
+++ grpl/trunk/patron_notifications/tadl-egnotify-scripts_20090306/overdues-sample.xml 2009-04-17 19:42:02 UTC (rev 351)
@@ -0,0 +1,124 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<file type="notice" date="8/4/2008" time="5:5:7">
+<agency name="MLC">
+<notice type='overdue' count='14day'>
+<patron>
+<id type="barcode">22780000000001</id>
+<fullname>Mitchell E Mouse</fullname>
+<street1>2003 E WEST ST</street1>
+<city_state_zip>Union City, MI 49094</city_state_zip>
+<sys_id>17884</sys_id>
+<day_phone></day_phone>
+<email></email>
+</patron>
+<library>
+<libname>Union Township Branch</libname>
+<libphone></libphone>
+<libstreet1>221 N. Broadway St. </libstreet1>
+<libcity_state_zip>Union City, MI 49094-1153</libcity_state_zip>
+</library>
+<item>
+<title>South Carolina sea creatures</title>
+<author>Rand, Johnathan.</author>
+<duedate>7/21/2008</duedate>
+<callno>J FIC RAN17</callno>
+<location>123</location>
+<barcode>35406423940095</barcode>
+<circ_id>271367</circ_id>
+<check_out>7/1/2008</check_out>
+<item_price>11.95</item_price>
+</item>
+</notice>
+<notice type='overdue' count='14day'>
+<patron>
+<id type="barcode">2278000000002</id>
+<fullname>Robert Smith</fullname>
+<street1>3111 SOUTH MAIN</street1>
+<city_state_zip>SHERWOOD, MI 49089</city_state_zip>
+<sys_id>22834</sys_id>
+<day_phone></day_phone>
+<email></email>
+</patron>
+<library>
+<libname>Union Township Branch</libname>
+<libphone></libphone>
+<libstreet1>221 N. Broadway St. </libstreet1>
+<libcity_state_zip>Union City, MI 49094-1153</libcity_state_zip>
+</library>
+<item>
+<title>Say cheese and die!</title>
+<author>Stine, R. L.</author>
+<duedate>7/21/2008</duedate>
+<callno>J FIC STI4</callno>
+<location>123</location>
+<barcode>35406423825908</barcode>
+<circ_id>273690</circ_id>
+<check_out>7/1/2008</check_out>
+<item_price>11.95</item_price>
+</item>
+</notice>
+<notice type='overdue' count='14day'>
+<patron>
+<id type="barcode">254010000001</id>
+<fullname>John S. Doe</fullname>
+<street1>100 SMITH STREET </street1>
+<city_state_zip>UNION CITY, MI 49094</city_state_zip>
+<sys_id>26988</sys_id>
+<day_phone></day_phone>
+<email></email>
+</patron>
+<library>
+<libname>Union Township Branch</libname>
+<libphone></libphone>
+<libstreet1>221 N. Broadway St. </libstreet1>
+<libcity_state_zip>Union City, MI 49094-1153</libcity_state_zip>
+</library>
+<item>
+<title>Violin</title>
+<author>Rice, Anne</author>
+<duedate>7/21/2008</duedate>
+<callno>FIC RIC</callno>
+<location>123</location>
+<barcode>35406423824893</barcode>
+<circ_id>271615</circ_id>
+<check_out>7/1/2008</check_out>
+<item_price>11.95</item_price>
+</item>
+<item>
+<title>Family first : your step-by-step plan for creating a phenomenal
+family</title>
+<author>McGraw, Phillip C.</author>
+<duedate>7/21/2008</duedate>
+<callno>649.1 MCG</callno>
+<location>123</location>
+<barcode>35406423934866</barcode>
+<circ_id>271914</circ_id>
+<check_out>7/1/2008</check_out>
+<item_price>11.95</item_price>
+</item>
+<item>
+<title>Servant of the bones </title>
+<author>Rice, Anne</author>
+<duedate>7/21/2008</duedate>
+<callno>FIC RIC</callno>
+<location>123</location>
+<barcode>35406423817111</barcode>
+<circ_id>272450</circ_id>
+<check_out>7/1/2008</check_out>
+<item_price>11.95</item_price>
+</item>
+<item>
+<title>Christ the Lord out of Egypt : a novel</title>
+<author>Rice, Anne</author>
+<duedate>7/21/2008</duedate>
+<callno>FIC RIC</callno>
+<location>123</location>
+<barcode>35406423946969</barcode>
+<circ_id>272496</circ_id>
+<check_out>7/1/2008</check_out>
+<item_price>11.95</item_price>
+</item>
+</notice>
+</agency>
+</file>
+
More information about the open-ils-commits
mailing list