--- /dev/null
+#!/bin/bash
+
+# Copyright (C) 2014 Georgia Public Library Service
+# Chris Sharp <csharp@georgialibraries.org>
+#
+# A program that takes a library system or branch name and a date or set of dates
+# on the command line to apply a batch void for billings applied on that day.
+# This is particularly useful if closed dates are set after the fine generator has
+# run for that day.
+#
+# This script assumes that you are on a server with direct access to your master
+# database, and that you have set the credentials for that database in the .pgpass
+# file in your user's home directory.
+#
+# See http://www.postgresql.org/docs/9.1/static/libpq-pgpass.html for more information.
+#
+# Usage Notes:
+#
+# You'll want to set the $EGUSER/$EGPASS variables to the username/password of an Evergreen
+# user (e.g., your administrative user in Evergreen). Adjust the $SRFSH variable to suit
+# your environment. As of this writing, we're still installing Evergreen in /openils.
+# The $VOID_NOTE variable should be something informative to your staff users as to why these
+# bills were voided. Our use case was closings due to inclement weather.
+#
+# The $BACKUP_SCHEMA variable should be set to a schema in your postgresql database that is
+# for administrative use. You should NOT use an existing Evergreen schema name (e.g. "action",
+# "actor", etc. for this purpose. I use "csharp" for that in our case.
+#
+# My hope is that this can be re-implemented in Perl or something with actual OpenSRF bindings,
+# but my current skill level and available time prevented me from doing so now.
+
+EGUSER="myuser"
+EGPASS="mypass"
+SRFSH="/openils/bin/srfsh"
+DBHOST="mydbhost"
+DBUSER="mydbuser"
+VOID_NOTE="VOIDED BY SYSTEM STAFF - INCLEMENT WEATHER"
+BACKUP_SCHEMA="myschema"
+
+Usage() { echo "Usage: ./batch_void_fines.sh -d YYYY-MM-DD,YYYY-MM-DD,... -s systemname OR -b branchname."
+}
+
+while getopts s:b:d:h OPTIONS
+do case "$OPTIONS" in
+ s) SYSTEM="$OPTARG";;
+ b) BRANCH="$OPTARG";;
+ d) DATE="$OPTARG";;
+ h) Usage ; exit 1;;
+ *) Usage ; exit 2;;
+ esac
+done
+
+if [ -n "$SYSTEM" ] && [ -n "$BRANCH" ]; then
+ Usage
+ exit 1;
+fi
+
+if [ -z "$DATE" ]; then
+ Usage
+ exit 1;
+fi
+
+if [ $(echo $DATE | grep ",") ]; then
+ SPLITDATE=`echo $DATE | sed "s/,/', '/g"`
+ DATE=$SPLITDATE
+fi
+
+if [ -n "$SYSTEM" ]; then
+ BACKUP_TABLE="$BACKUP_SCHEMA.`echo $SYSTEM | tr '[:upper:]' '[:lower:]'`_snowday_fines_`echo $DATE | tr '-' '_'`"
+else
+ BACKUP_TABLE="$BACKUP_SCHEMA.`echo $BRANCH | tr '[:upper:]' '[:lower:]' | tr '-' '_'`_snowday_fines_`echo $DATE | tr '-' '_'`"
+fi
+read -d '' SYSTEM_Q <<END_OF_Q
+SELECT * INTO $BACKUP_TABLE
+FROM money.billing mb
+WHERE date(billing_ts) IN (
+ '$DATE'
+) AND voided = FALSE
+ AND EXISTS (
+ SELECT 1
+ FROM action.circulation ac
+ WHERE mb.xact = ac.id
+ AND ac.circ_lib IN (
+ SELECT id
+ FROM actor.org_unit
+ WHERE parent_ou IN (
+ SELECT id
+ FROM actor.org_unit
+ WHERE shortname = '$SYSTEM')));
+END_OF_Q
+read -d '' BRANCH_Q <<END_OF_Q
+SELECT * INTO $BACKUP_TABLE
+FROM money.billing mb
+WHERE date(billing_ts) IN (
+ '$DATE'
+) AND voided = FALSE
+ AND EXISTS (
+ SELECT 1
+ FROM action.circulation ac
+ WHERE mb.xact = ac.id
+ AND ac.circ_lib IN (
+ SELECT id
+ FROM actor.org_unit
+ WHERE shortname = '$BRANCH'));
+END_OF_Q
+
+if [ -n "$SYSTEM" ]; then
+ echo "$SYSTEM_Q"
+ psql -U "$DBUSER" -h "$DBHOST" -c "$SYSTEM_Q"
+fi
+
+if [ -n "$BRANCH" ]; then
+ echo "$BRANCH_Q"
+ psql -U "$DBUSER" -h "$DBHOST" -c "$BRANCH_Q"
+fi
+
+read -d '' BILLS_SQL <<END_OF_Q
+SELECT id FROM $BACKUP_TABLE;
+END_OF_Q
+
+read -d '' COUNT_SQL <<END_OF_Q
+SELECT count(*)
+FROM money.billing
+WHERE NOT voided
+AND id IN (
+ SELECT id
+ FROM $BACKUP_TABLE
+);
+END_OF_Q
+
+read -d '' UPDATE_SQL <<END_OF_Q
+BEGIN;
+UPDATE money.billing
+SET note = '$VOID_NOTE'
+WHERE id IN (
+ SELECT id
+ FROM $BACKUP_TABLE
+);
+COMMIT;
+END_OF_Q
+
+BILLS=`psql -A -t -U "$DBUSER" -h "$DBHOST" -c "$BILLS_SQL" | sed 's/^/"/g' | sed 's/$/", /g' | tr '\n' ' '`
+
+AUTHTOKEN=`echo "login $EGUSER $EGPASS" | $SRFSH | grep "Login Session" | cut -d':' -f 2 | cut -d'.' -f1 | sed 's/ //g'`
+
+SRFSH_COMMAND="request open-ils.circ open-ils.circ.money.billing.void \"$AUTHTOKEN\" $BILLS"
+
+echo "$SRFSH_COMMAND" >> "${BACKUP_TABLE}_void.srfsh"
+
+echo "$SRFSH_COMMAND" | $SRFSH
+
+until [ $(psql -A -t -U "$DBUSER" -h "$DBHOST" -c "$COUNT_SQL") == "0" ]; do
+ echo "Waiting for srfsh command to complete..."
+ sleep 10
+done
+
+psql -U "$DBUSER" -h "$DBHOST" -c "$UPDATE_SQL"
+
+echo "Update complete"