Begin to break config out into ini file
[sitka/iNCIPit.git] / iNCIPit.cgi
old mode 100755 (executable)
new mode 100644 (file)
index 6e6f3d0..6e3a215
@@ -1,6 +1,6 @@
 #! /usr/bin/perl 
 
-# This file is part of iNCIPit 
+# This file is part of iNCIPit
 #
 # iNCIPit is free software: you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
 # License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with issa. If not, see <http://www.gnu.org/licenses/>.
-
+# along with iNCIPit. If not, see <http://www.gnu.org/licenses/>.
 
 use warnings;
+use strict;
 use XML::LibXML;
 use CGI::XMLPost;
 use HTML::Entities;
@@ -34,11 +34,17 @@ use MARC::Field;
 use MARC::File::XML;
 use POSIX qw/strftime/;
 use DateTime;
+use Config::Tiny;
+
+my $U = "OpenILS::Application::AppUtils";
+
+my $conf = load_config( 'iNCIPit.ini' );
 
 my $xmlpost = CGI::XMLPost->new();
-my $xml = $xmlpost->data(); 
+my $xml     = $xmlpost->data();
 
-# log posted data 
+# log posted data
+# XXX: posted ncip message log filename should be in config.
 open POST_DATA, ">>post_data.txt";
 print POST_DATA $xml;
 close POST_DATA;
@@ -52,66 +58,71 @@ my %session = login();
 # Setup our SIGALRM handler.
 $SIG{'ALRM'} = \&logout;
 
-if (defined($session{authtoken})) {
-    $doc->exists('/NCIPMessage/LookupUser') ? lookupUser() :
-        ( $doc->exists('/NCIPMessage/ItemRequested') ? item_request() :
-                ( $doc->exists('/NCIPMessage/ItemShipped') ? item_shipped() :
-                        ( $doc->exists('/NCIPMessage/ItemCheckedOut') ? item_checked_out() :
-                          ( $doc->exists('/NCIPMessage/CheckOutItem') ? check_out_item() :
-                                ( $doc->exists('/NCIPMessage/ItemCheckedIn') ? item_checked_in() :
-                                  ( $doc->exists('/NCIPMessage/CheckInItem') ? check_in_item() :
-                                        ( $doc->exists('/NCIPMessage/ItemReceived') ? item_received() :
-                                                ( $doc->exists('/NCIPMessage/AcceptItem') ? accept_item() :
-                                                       ( $doc->exists('/NCIPMessage/ItemRequestCancelled') ? item_cancelled() :
-                                                               ( $doc->exists('/NCIPMessage/ItemRenewed') ? item_renew() :
-                                                                       fail("UNKNOWN NCIPMessage")
-                                                               )
-                                                       )
-                                                )
-                                        )
-                                 )
-                                )
-                          )
-                       )
-                )
-        );
+if ( defined( $session{authtoken} ) ) {
+    $doc->exists('/NCIPMessage/LookupUser')           ? lookupUser()       : (
+    $doc->exists('/NCIPMessage/ItemRequested')        ? item_request()     : (
+    $doc->exists('/NCIPMessage/ItemShipped')          ? item_shipped()     : (
+    $doc->exists('/NCIPMessage/ItemCheckedOut')       ? item_checked_out() : (
+    $doc->exists('/NCIPMessage/CheckOutItem')         ? check_out_item()   : (
+    $doc->exists('/NCIPMessage/ItemCheckedIn')        ? item_checked_in()  : (
+    $doc->exists('/NCIPMessage/CheckInItem')          ? check_in_item()    : (
+    $doc->exists('/NCIPMessage/ItemReceived')         ? item_received()    : (
+    $doc->exists('/NCIPMessage/AcceptItem')           ? accept_item()      : (
+    $doc->exists('/NCIPMessage/ItemRequestCancelled') ? item_cancelled()   : (
+    $doc->exists('/NCIPMessage/ItemRenewed')          ? item_renew()       : (
+    $doc->exists('/NCIPMessage/RenewItem')            ? renew_item()       :
+    fail("UNKNOWN NCIPMessage")
+    )))))))))));
 
     # Clear any SIGALRM timers.
     alarm(0);
     logout();
 } else {
-    # red dwarf - s1:e1
-    fail("They are all dead, Dave.");
+    fail("Unable to perform action : Unknown Service Request");
+}
+
+# load and parse config file
+sub load_config {
+    my $file = shift;
+
+    my $Config = Config::Tiny->new;
+    $Config = Config::Tiny->read( $file ) ||
+        die( "Error reading config file ", $file, ": ", Config::Tiny->errstr, "\n" );
+    return $Config;
 }
 
 sub logit {
-       my ($msg,$func) = @_;
-       open RESP_DATA, ">>resp_data.txt";
-       print RESP_DATA $msg;
-       close RESP_DATA;
-       print $msg || fail($func);
+    my ( $msg, $func, $more_info ) = @_;
+    open RESP_DATA, ">>resp_data.txt";
+    print RESP_DATA $msg;
+    print RESP_DATA $more_info unless !$more_info;
+    close RESP_DATA;
+    print $msg || fail($func);
+}
+
+sub staff_log {
+    my ( $taiv, $faiv, $more_info ) = @_;
+    my $now = localtime();
+    open STAFF_LOG, ">>staff_data.csv";
+    print STAFF_LOG "$now, $faiv, $taiv, $more_info\n";
+    close STAFF_LOG;
 }
 
 sub item_renew {
-       my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemRenewed/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');  
-       my $faidScheme = HTML::Entities::encode($faidSchemeX);
-       my $faidValue  = $doc->find('/NCIPMessage/ItemRenewed/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');  
-       my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemRenewed/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');  
-       my $taidScheme = HTML::Entities::encode($taidSchemeX);
-       my $taidValue  = $doc->find('/NCIPMessage/ItemRenewed/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');  
-
-       my $pid         = $doc->findvalue('/NCIPMessage/ItemRenewed/UniqueUserId/UserIdentifierValue');  
-       my $visid      = $doc->findvalue('/NCIPMessage/ItemRenewed/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier').$faidValue;  
-       #my $barcode    = $doc->findvalue('/NCIPMessage/ItemRenewed/UniqueItemId/ItemIdentifierValue').$faidValue;  
-       my $due_date   = $doc->findvalue('/NCIPMessage/ItemRenewed/DateDue');  
-
-       #my $copy = copy_from_barcode($barcode);
-       #fail($copy->{textcode}) unless (blessed $copy);
-       #my $r = update_copy($copy,0); # seemed like copy had to be available before it could be checked out, so ...
-       #my $r2 = checkout($barcode,$pid,$due_date);
-       my $r = renewal($visid,$due_date);
-
-my $hd = <<ITEMRENEWAL;
+    my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemRenewed/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    my $faidScheme = HTML::Entities::encode($faidSchemeX);
+    my $faidValue  = $doc->find('/NCIPMessage/ItemRenewed/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+    my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemRenewed/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    my $taidScheme = HTML::Entities::encode($taidSchemeX);
+    my $taidValue  = $doc->find('/NCIPMessage/ItemRenewed/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
+
+    my $pid = $doc->findvalue('/NCIPMessage/ItemRenewed/UniqueUserId/UserIdentifierValue');
+    my $visid = $doc->findvalue('/NCIPMessage/ItemRenewed/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
+    my $due_date = $doc->findvalue('/NCIPMessage/ItemRenewed/DateDue');
+
+    my $r = renewal( $visid, $due_date );
+
+    my $hd = <<ITEMRENEWAL;
 Content-type: text/xml
 
 
@@ -140,36 +151,100 @@ Content-type: text/xml
 
 ITEMRENEWAL
 
-my $more_info = <<MOREINFO;
+    my $more_info = <<MOREINFO;
 
-VISID                  = $visid
-Desired Due Date       = $date_due
+VISID             = $visid
+Desired Due Date     = $due_date
 
 MOREINFO
 
-       $hd .= $more_info;
+    logit( $hd, ( caller(0) )[3], $more_info );
+    staff_log( $taidValue, $faidValue,
+            "ItemRenewal -> Patronid : "
+          . $pid
+          . " | Visid : "
+          . $visid
+          . " | Due Date : "
+          . $due_date );
+}
+
+sub renew_item {
+    my $faidSchemeX = $doc->findvalue('/NCIPMessage/RenewItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    my $faidScheme = HTML::Entities::encode($faidSchemeX);
+    my $faidValue  = $doc->find('/NCIPMessage/RenewItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+    my $taidSchemeX = $doc->findvalue('/NCIPMessage/RenewItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    my $taidScheme = HTML::Entities::encode($taidSchemeX);
+    my $taidValue  = $doc->find('/NCIPMessage/RenewItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
+
+    my $pid = $doc->findvalue('/NCIPMessage/RenewItem/UniqueUserId/UserIdentifierValue');
+    my $unique_item_id = $doc->findvalue('/NCIPMessage/RenewItem/UniqueItemId/ItemIdentifierValue');
+    my $due_date = $doc->findvalue('/NCIPMessage/RenewItem/DateDue');
+
+    # we are using the UniqueItemId value as a barcode here
+    my $r = renewal( $unique_item_id, $due_date );
 
-       logit($hd,(caller(0))[3]);
+    my $hd = <<ITEMRENEWAL;
+Content-type: text/xml
+
+
+<!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
+<NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
+    <RenewItemResponse>
+        <ResponseHeader>
+            <FromAgencyId>
+                <UniqueAgencyId>
+                    <Scheme>$faidScheme</Scheme>
+                    <Value>$faidValue</Value>
+                </UniqueAgencyId>
+            </FromAgencyId>
+            <ToAgencyId>
+                <UniqueAgencyId>
+                    <Scheme>$taidScheme</Scheme>
+                    <Value>$taidValue</Value>
+                </UniqueAgencyId>
+            </ToAgencyId>
+        </ResponseHeader>
+        <UniqueItemId>
+            <ItemIdentifierValue datatype="string">$unique_item_id</ItemIdentifierValue>
+        </UniqueItemId>
+    </RenewItemResponse>
+</NCIPMessage> 
+
+ITEMRENEWAL
+
+    my $more_info = <<MOREINFO;
+
+UNIQUEID             = $unique_item_id
+Desired Due Date     = $due_date
+
+MOREINFO
+
+    logit( $hd, ( caller(0) )[3], $more_info );
+    staff_log( $taidValue, $faidValue,
+            "RenewItem -> Patronid : "
+          . $pid
+          . " | Uniqueid: : "
+          . $unique_item_id
+          . " | Due Date : "
+          . $due_date );
 }
 
 sub accept_item {
-       my $faidSchemeX = $doc->findvalue('/NCIPMessage/AcceptItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');  
-       my $faidScheme = HTML::Entities::encode($faidSchemeX);
-       my $faidValue  = $doc->find('/NCIPMessage/AcceptItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');  
-       my $taidSchemeX = $doc->findvalue('/NCIPMessage/AcceptItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');  
-       my $taidScheme = HTML::Entities::encode($taidSchemeX);
-       my $taidValue  = $doc->find('/NCIPMessage/AcceptItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');  
-
-       my $visid      = $doc->findvalue('/NCIPMessage/AcceptItem/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier').$faidValue;  
-       my $request_id = $doc->findvalue('/NCIPMessage/AcceptItem/UniqueRequestId/RequestIdentifierValue') || "unknown" ;  
-#      my $barcode    = $doc->findvalue('/NCIPMessage/AcceptItem/UniqueItemId/ItemIdentifierValue').$faidValue;  
-       my $patron     = $doc->findvalue('/NCIPMessage/AcceptItem/UserOptionalFields/VisibleUserId/VisibleUserIdentifier');  
-#      my $copy = copy_from_barcode($barcode);
-#     my $r = place_hold ('C', $copy, $patron, OUHERE);
-       my $copy = copy_from_barcode($visid);
-       my $r2 = update_copy($copy,112); # put into INN-Reach Hold status
-
-my $hd = <<ACCEPTITEM;
+    my $faidSchemeX = $doc->findvalue('/NCIPMessage/AcceptItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    my $faidScheme = HTML::Entities::encode($faidSchemeX);
+    my $faidValue  = $doc->find('/NCIPMessage/AcceptItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+    my $taidSchemeX = $doc->findvalue('/NCIPMessage/AcceptItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    my $taidScheme = HTML::Entities::encode($taidSchemeX);
+    my $taidValue  = $doc->find('/NCIPMessage/AcceptItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
+    my $visid = $doc->findvalue('/NCIPMessage/AcceptItem/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
+    my $request_id = $doc->findvalue('/NCIPMessage/AcceptItem/UniqueRequestId/RequestIdentifierValue') || "unknown";
+    my $patron = $doc->findvalue('/NCIPMessage/AcceptItem/UserOptionalFields/VisibleUserId/VisibleUserIdentifier');
+    my $copy = copy_from_barcode($visid);
+    my $r2 = update_copy( $copy, 111 ); # XXX CUSTOMIZATION NEEDED XXX # put into INN-Reach Hold status
+
+# TODO: this should probably fulfill the original hold, not just change the status.  Eventually we should split the hold type, as holds arriving are not the same as holds needing to be sent
+
+    my $hd = <<ACCEPTITEM;
 Content-type: text/xml
 
 
@@ -190,7 +265,7 @@ Content-type: text/xml
                 </UniqueAgencyId>
             </ToAgencyId>
         </ResponseHeader>
-       <UniqueRequestId>
+    <UniqueRequestId>
             <ItemIdentifierValue datatype="string">$request_id</ItemIdentifierValue>
         </UniqueRequestId>
         <UniqueItemId>
@@ -201,19 +276,25 @@ Content-type: text/xml
 
 ACCEPTITEM
 
-       logit($hd,(caller(0))[3]);
+    logit( $hd, ( caller(0) )[3] );
+    staff_log( $taidValue, $faidValue,
+        "AcceptItem -> Request Id : " . $request_id . " | Patron Id : " . $patron . " | Visible Id :" . $visid );
 }
 
 sub item_received {
-     my $faidValue  = $doc->find('/NCIPMessage/ItemReceived/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');  
-     my $barcode      = $doc->findvalue('/NCIPMessage/ItemReceived/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier').$faidValue;  
-     #my $barcode = $doc->findvalue('/NCIPMessage/ItemReceived/UniqueItemId/ItemIdentifierValue').$faidValue;  
-     my $copy = copy_from_barcode($barcode);
-     fail($copy->{textcode}) unless (blessed $copy);
-     my $r1 = checkin($barcode,OUHERE) if ($copy->status == OILS_COPY_STATUS_CHECKED_OUT); # checkin the item before delete if ItemCheckedIn step was skipped
-     my $r2 = delete_copy($copy);
-
-my $hd = <<ITEMRECEIVED; 
+    my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemReceived/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    my $faidScheme = HTML::Entities::encode($faidSchemeX);
+    my $faidValue = $doc->find('/NCIPMessage/ItemReceived/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+    my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemReceived/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    my $taidScheme = HTML::Entities::encode($taidSchemeX);
+    my $taidValue  = $doc->find('/NCIPMessage/ItemReceived/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
+    my $visid = $doc->findvalue('/NCIPMessage/ItemReceived/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
+    my $copy = copy_from_barcode($visid);
+    fail( $copy->{textcode} . " $visid" ) unless ( blessed $copy);
+    my $r1 = checkin($visid) if ( $copy->status == OILS_COPY_STATUS_CHECKED_OUT ); # checkin the item before delete if ItemCheckedIn step was skipped
+    my $r2 = delete_copy($copy);
+
+    my $hd = <<ITEMRECEIVED;
 Content-type: text/xml
 
 
@@ -235,41 +316,43 @@ Content-type: text/xml
             </ToAgencyId>
         </ResponseHeader>
         <UniqueItemId>
-            <ItemIdentifierValue datatype="string">$barcode</ItemIdentifierValue>
+            <ItemIdentifierValue datatype="string">$visid</ItemIdentifierValue>
         </UniqueItemId>
     </ItemReceivedResponse>
 </NCIPMessage> 
 
 ITEMRECEIVED
 
-       logit($hd,(caller(0))[3]);
+    logit( $hd, ( caller(0) )[3] );
+    staff_log( $taidValue, $faidValue, "ItemReceived -> Visible ID : " . $visid );
 }
 
 sub item_cancelled {
-       my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');  
-       my $faidScheme = HTML::Entities::encode($faidSchemeX);
-       my $faidValue  = $doc->find('/NCIPMessage/ItemRequestCancelled/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');  
-
-       my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');  
-       my $taidScheme = HTML::Entities::encode($taidSchemeX);
-       my $taidValue  = $doc->find('/NCIPMessage/ItemRequestCancelled/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');  
-       my $UniqueItemIdAgencyIdValue  = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/UniqueItemId/UniqueAgencyId/Value');  
-
-       #my $barcode      = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier').$faidValue;  
-       my $barcode = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/UniqueItemId/ItemIdentifierValue').$faidValue;  
-
-       if ($UniqueItemIdAgencyIdValue eq SPECIALTOAGENCY ) { 
-       #        my $localid = locid_from_barcode($barcode);
-       #       $r = place_hold($localid, SPECIALTOAGEID );
-       # remove hold!
-       } 
-       else {
-               my $copy = copy_from_barcode($barcode);
-               fail($copy->{textcode}) unless (blessed $copy);
-               my $r = delete_copy($copy);
-       }
-
-my $hd = <<ITEMREQUESTCANCELLED; 
+    my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    my $faidScheme = HTML::Entities::encode($faidSchemeX);
+    my $faidValue  = $doc->find('/NCIPMessage/ItemRequestCancelled/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+
+    my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    my $taidScheme = HTML::Entities::encode($taidSchemeX);
+    my $taidValue  = $doc->find('/NCIPMessage/ItemRequestCancelled/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
+    my $UniqueItemIdAgencyIdValue = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/UniqueItemId/UniqueAgencyId/Value');
+
+    my $barcode = $doc->findvalue('/NCIPMessage/ItemRequestCancelled/UniqueItemId/ItemIdentifierValue');
+
+    if ( $barcode =~ /^i/ ) {    # delete copy only if barcode is an iNUMBER
+        $barcode .= $faidValue;
+        my $copy = copy_from_barcode($barcode);
+        fail( $copy->{textcode} . " $barcode" ) unless ( blessed $copy);
+        my $r = delete_copy($copy);
+    } else {
+
+        # remove hold!
+        my $copy = copy_from_barcode($barcode);
+        fail( $copy->{textcode} . " $barcode" ) unless ( blessed $copy);
+        my $r = update_copy( $copy, 0 ); # TODO: we need to actually remove the hold, not just reset to available
+    }
+
+    my $hd = <<ITEMREQUESTCANCELLED;
 Content-type: text/xml
 
 
@@ -298,24 +381,26 @@ Content-type: text/xml
 
 ITEMREQUESTCANCELLED
 
-       logit($hd,(caller(0))[3]);
+    logit( $hd, ( caller(0) )[3] );
+    staff_log( $taidValue, $faidValue,
+        "ItemRequestCancelled -> Barcode : " . $barcode );
 }
 
 sub item_checked_in {
-       my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedIn/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');  
-       my $faidScheme = HTML::Entities::encode($faidSchemeX);
-       my $faidValue  = $doc->find('/NCIPMessage/ItemCheckedIn/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');  
-       my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedIn/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');  
-       my $taidScheme = HTML::Entities::encode($taidSchemeX);
-       my $taidValue  = $doc->find('/NCIPMessage/ItemCheckedIn/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');  
-
-       my $barcode      = $doc->findvalue('/NCIPMessage/ItemCheckedIn/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier').$faidValue;  
-       # my $barcode    = $doc->findvalue('/NCIPMessage/ItemCheckedIn/UniqueItemId/ItemIdentifierValue').$faidValue;  
-       my $r = checkin($barcode, PICKUPLOCATION );  
-       my $copy = copy_from_barcode($barcode);
-       my $r2 = update_copy($copy,114); # "INN-Reach Transit Return" status
-
-my $hd = <<ITEMCHECKEDIN;
+    my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedIn/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    my $faidScheme = HTML::Entities::encode($faidSchemeX);
+    my $faidValue  = $doc->find('/NCIPMessage/ItemCheckedIn/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+    my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedIn/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    my $taidScheme = HTML::Entities::encode($taidSchemeX);
+    my $taidValue  = $doc->find('/NCIPMessage/ItemCheckedIn/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
+
+    my $visid = $doc->findvalue('/NCIPMessage/ItemCheckedIn/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
+    my $r = checkin($visid);
+    my $copy = copy_from_barcode($visid);
+    fail( $copy->{textcode} . " $visid" ) unless ( blessed $copy);
+    my $r2 = update_copy( $copy, 113 ); # XXX CUSTOMIZATION NEEDED XXX # "INN-Reach Transit Return" status
+
+    my $hd = <<ITEMCHECKEDIN;
 Content-type: text/xml
 
 
@@ -337,38 +422,36 @@ Content-type: text/xml
             </ToAgencyId>
         </ResponseHeader>
         <UniqueItemId>
-            <ItemIdentifierValue datatype="string">$barcode</ItemIdentifierValue>
+            <ItemIdentifierValue datatype="string">$visid</ItemIdentifierValue>
         </UniqueItemId>
     </ItemCheckedInResponse>
 </NCIPMessage> 
 
 ITEMCHECKEDIN
 
-       logit($hd,(caller(0))[3]);
+    logit( $hd, ( caller(0) )[3] );
+    staff_log( $taidValue, $faidValue, "ItemCheckedIn -> Visible ID : " . $visid );
 }
 
 sub item_checked_out {
-       my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedOut/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');  
-       my $faidScheme = HTML::Entities::encode($faidSchemeX);
-       my $faidValue  = $doc->find('/NCIPMessage/ItemCheckedOut/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');  
-       my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedOut/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');  
-       my $taidScheme = HTML::Entities::encode($taidSchemeX);
-       my $taidValue  = $doc->find('/NCIPMessage/ItemCheckedOut/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');  
-
-       my $pid         = $doc->findvalue('/NCIPMessage/ItemCheckedOut/UserOptionalFields/VisibleUserId/VisibleUserIdentifier');  
-       # my $barcode    = $doc->findvalue('/NCIPMessage/ItemCheckedOut/UniqueItemId/ItemIdentifierValue').$faidValue;  
-       my $due_date   = $doc->findvalue('/NCIPMessage/ItemCheckedOut/DateDue');  
-       # my $title    = $doc->findvalue('/NCIPMessage/ItemCheckedOut/ItemOptionalFields/BibliographicDescription/Title');  
-       
-       my $visid    = $doc->findvalue('/NCIPMessage/ItemCheckedOut/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier').$faidValue;  
-
-       my $copy = copy_from_barcode($visid);
-       fail($copy->{textcode}) unless (blessed $copy);
-       my $r = update_copy($copy,0); # seemed like copy had to be available before it could be checked out, so ...
-       # my $r1 = checkin($visid, PICKUPOU ) if ($copy->status == OILS_COPY_STATUS_CHECKED_OUT); # double posted itemcheckedout messages cause error ... trying to simplify 
-       my $r2 = checkout($visid,$pid,$due_date);
-
-my $hd = <<ITEMCHECKEDOUT;
+    my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedOut/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    my $faidScheme = HTML::Entities::encode($faidSchemeX);
+    my $faidValue  = $doc->find('/NCIPMessage/ItemCheckedOut/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+    my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemCheckedOut/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    my $taidScheme = HTML::Entities::encode($taidSchemeX);
+    my $taidValue  = $doc->find('/NCIPMessage/ItemCheckedOut/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
+
+    my $patron_barcode = $doc->findvalue('/NCIPMessage/ItemCheckedOut/UserOptionalFields/VisibleUserId/VisibleUserIdentifier');
+    my $due_date = $doc->findvalue('/NCIPMessage/ItemCheckedOut/DateDue');
+    my $visid = $doc->findvalue('/NCIPMessage/ItemCheckedOut/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
+
+    my $copy = copy_from_barcode($visid);
+    fail( $copy->{textcode} . " $visid" ) unless ( blessed $copy);
+    my $r = update_copy( $copy, 0 ); # seemed like copy had to be available before it could be checked out, so ...
+    my $r1 = checkin($visid) if ( $copy->status == OILS_COPY_STATUS_CHECKED_OUT ); # double posted itemcheckedout messages cause error ... trying to simplify
+    my $r2 = checkout( $visid, $patron_barcode, $due_date );
+
+    my $hd = <<ITEMCHECKEDOUT;
 Content-type: text/xml
 
 
@@ -397,31 +480,35 @@ Content-type: text/xml
 
 ITEMCHECKEDOUT
 
-$hd .= $r;
-       logit($hd,(caller(0))[3]);
+    logit( $hd, ( caller(0) )[3] );
+    staff_log( $taidValue, $faidValue,
+        "ItemCheckedOut -> Visible Id : " . $visid . " | Patron Barcode : " . $patron_barcode . " | Due Date : " . $due_date );
 }
 
 sub check_out_item {
-       my $faidSchemeX = $doc->findvalue('/NCIPMessage/CheckOutItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');  
-       my $faidScheme = HTML::Entities::encode($faidSchemeX);
-       my $faidValue  = $doc->find('/NCIPMessage/CheckOutItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');  
-       my $taidSchemeX = $doc->findvalue('/NCIPMessage/CheckOutItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');  
-       my $taidScheme = HTML::Entities::encode($taidSchemeX);
-       my $taidValue  = $doc->find('/NCIPMessage/CheckOutItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');  
+    my $faidSchemeX = $doc->findvalue('/NCIPMessage/CheckOutItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    my $faidScheme = HTML::Entities::encode($faidSchemeX);
+    my $faidValue  = $doc->find('/NCIPMessage/CheckOutItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+    my $taidSchemeX = $doc->findvalue('/NCIPMessage/CheckOutItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    my $taidScheme = HTML::Entities::encode($taidSchemeX);
+    my $taidValue  = $doc->find('/NCIPMessage/CheckOutItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
 
-       my $mdate       = $doc->findvalue('/NCIPMessage/CheckOutItem/MandatedAction/DateEventOccurred');  
-       my $pid         = $doc->find('/NCIPMessage/CheckOutItem/UserOptionalFields/UniqueAgencyId/Value');  
+    my $mdate = $doc->findvalue('/NCIPMessage/CheckOutItem/MandatedAction/DateEventOccurred');
+    my $patron_barcode = "zyyyy";    # XXX: CUSTOMIZATION NEEDED XXX institution/eg_as_item_agency user lookup here
 
-       my $barcode    = $doc->findvalue('/NCIPMessage/CheckOutItem/UniqueItemId/ItemIdentifierValue');  
-       my $due_date   = $doc->findvalue('/NCIPMessage/CheckOutItem/DateDue');  
+    my $barcode = $doc->findvalue('/NCIPMessage/CheckOutItem/UniqueItemId/ItemIdentifierValue');
 
-       my $copy = copy_from_barcode($barcode);
-       fail($copy->{textcode}) unless (blessed $copy);
-       # my $r = update_copy($copy,0); # seemed like copy had to be available before it could be checked out, so ...
+    # TODO: watch for possible real ids here?
+    my $due_date = $doc->findvalue('/NCIPMessage/CheckOutItem/DateDue');
+
+    my $copy = copy_from_barcode($barcode);
+    fail( $copy->{textcode} . " $barcode" ) unless ( blessed $copy);
 
-       my $r2 = checkout($barcode,$pid,$due_date);
+    my $r2 = checkout( $barcode, $patron_barcode, $due_date );
 
-my $hd = <<CHECKOUTITEM;
+    # TODO: check for checkout exception (like OPEN_CIRCULATION_EXISTS)
+
+    my $hd = <<CHECKOUTITEM;
 Content-type: text/xml
 
 
@@ -450,23 +537,28 @@ Content-type: text/xml
 
 CHECKOUTITEM
 
-       logit($hd,(caller(0))[3]);
+    logit( $hd, ( caller(0) )[3] );
+    staff_log( $taidValue, $faidValue,
+        "CheckOutItem -> Barcode : " . $barcode . " | Patron Barcode : " . $patron_barcode . " | Due Date : " . $due_date );
 }
 
 sub check_in_item {
-       my $faidSchemeX = $doc->findvalue('/NCIPMessage/CheckInItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');  
-       my $faidScheme = HTML::Entities::encode($faidSchemeX);
-       my $faidValue  = $doc->find('/NCIPMessage/CheckInItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');  
-       my $taidSchemeX = $doc->findvalue('/NCIPMessage/CheckInItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');  
-       my $taidScheme = HTML::Entities::encode($taidSchemeX);
-       my $taidValue  = $doc->find('/NCIPMessage/CheckInItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');  
-
-       my $barcode    = $doc->findvalue('/NCIPMessage/CheckInItem/UniqueItemId/ItemIdentifierValue');  
-       my $r = checkin($barcode, OUHERE);  
-       my $copy = copy_from_barcode($barcode);
-       my $r2 = update_copy($copy,0); # Available now 
-
-my $hd = <<CHECKINITEM;
+    my $faidSchemeX = $doc->findvalue('/NCIPMessage/CheckInItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    my $faidScheme = HTML::Entities::encode($faidSchemeX);
+    my $faidValue  = $doc->find('/NCIPMessage/CheckInItem/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+    my $taidSchemeX = $doc->findvalue('/NCIPMessage/CheckInItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    my $taidScheme = HTML::Entities::encode($taidSchemeX);
+    my $taidValue  = $doc->find('/NCIPMessage/CheckInItem/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
+
+    my $barcode = $doc->findvalue('/NCIPMessage/CheckInItem/UniqueItemId/ItemIdentifierValue');
+    my $r = checkin($barcode);
+    fail($r) if $r =~ /^COPY_NOT_CHECKED_OUT/;
+    # TODO: do we need to do these next steps?  checkin() should handle everything, and we want this to end up in 'reshelving'.  If we are worried about transits, we should handle (abort) them, not just change the status
+    ##my $copy = copy_from_barcode($barcode);
+    ##fail($copy->{textcode}." $barcode") unless (blessed $copy);
+    ##         my $r2 = update_copy($copy,0); # Available now 
+
+    my $hd = <<CHECKINITEM;
 Content-type: text/xml
 
 
@@ -495,27 +587,28 @@ Content-type: text/xml
 
 CHECKINITEM
 
-       logit($hd,(caller(0))[3]);
+    logit( $hd, ( caller(0) )[3] );
+    staff_log( $taidValue, $faidValue, "CheckInItem -> Barcode : " . $barcode );
 }
 
 sub item_shipped {
-       my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemShipped/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');  
-       my $faidScheme = HTML::Entities::encode($faidSchemeX);
-       my $faidValue  = $doc->find('/NCIPMessage/ItemShipped/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');  
-       my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemShipped/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');  
-       my $taidScheme = HTML::Entities::encode($taidSchemeX);
-       my $taidValue  = $doc->find('/NCIPMessage/ItemShipped/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');  
-
-       my $visid      = $doc->findvalue('/NCIPMessage/ItemShipped/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier').$faidValue;  
-       my $barcode    = $doc->findvalue('/NCIPMessage/ItemShipped/UniqueItemId/ItemIdentifierValue').$faidValue;  
-       my $title    = $doc->findvalue('/NCIPMessage/ItemShipped/ItemOptionalFields/BibliographicDescription/Title');  
-       my $callnumber    = $doc->findvalue('/NCIPMessage/ItemShipped/ItemOptionalFields/ItemDescription/CallNumber');  
-
-       my $copy = copy_from_barcode($barcode);
-       fail($copy->{textcode}) unless (blessed $copy);
-       my $r = update_copy_shipped($copy,113,$visid); # put copy into INN-Reach Transit status & modify barcode = Visid != tempIIIiNumber
-
-my $hd = <<ITEMSHIPPED;
+    my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemShipped/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    my $faidScheme = HTML::Entities::encode($faidSchemeX);
+    my $faidValue  = $doc->find('/NCIPMessage/ItemShipped/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+    my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemShipped/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    my $taidScheme = HTML::Entities::encode($taidSchemeX);
+    my $taidValue  = $doc->find('/NCIPMessage/ItemShipped/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
+
+    my $visid = $doc->findvalue('/NCIPMessage/ItemShipped/ItemOptionalFields/ItemDescription/VisibleItemId/VisibleItemIdentifier') . $faidValue;
+    my $barcode = $doc->findvalue('/NCIPMessage/ItemShipped/UniqueItemId/ItemIdentifierValue') . $faidValue;
+    my $title = $doc->findvalue('/NCIPMessage/ItemShipped/ItemOptionalFields/BibliographicDescription/Title');
+    my $callnumber = $doc->findvalue('/NCIPMessage/ItemShipped/ItemOptionalFields/ItemDescription/CallNumber');
+
+    my $copy = copy_from_barcode($barcode);
+    fail( $copy->{textcode} . " $barcode" ) unless ( blessed $copy);
+    my $r = update_copy_shipped( $copy, 112, $visid );    # XXX CUSTOMIZATION NEEDED XXX # put copy into INN-Reach Transit status & modify barcode = Visid != tempIIIiNumber
+
+    my $hd = <<ITEMSHIPPED;
 Content-type: text/xml
 
 
@@ -544,38 +637,49 @@ Content-type: text/xml
 
 ITEMSHIPPED
 
-       logit($hd,(caller(0))[3]);
+    logit( $hd, ( caller(0) )[3] );
+    staff_log( $taidValue, $faidValue,
+        "ItemShipped -> Visible Id : " . $visid . " | Barcode : " . $barcode . " | Title : " . $title . " | Call Number : " . $callnumber );
 }
 
 sub item_request {
-       my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequested/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');  
-       my $faidScheme = HTML::Entities::encode($faidSchemeX);
-       my $faidValue  = $doc->find('/NCIPMessage/ItemRequested/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');  
-
-       my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequested/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');  
-       my $taidScheme = HTML::Entities::encode($taidSchemeX);
-       my $taidValue  = $doc->find('/NCIPMessage/ItemRequested/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');  
-       my $UniqueItemIdAgencyIdValue  = $doc->findvalue('/NCIPMessage/ItemRequested/UniqueItemId/UniqueAgencyId/Value');  
-
-       my $id         = $doc->findvalue('/NCIPMessage/ItemRequested/UniqueUserId/UserIdentifierValue');  
-       my $barcode    = $doc->findvalue('/NCIPMessage/ItemRequested/UniqueItemId/ItemIdentifierValue'); 
-       my $author    = $doc->findvalue('/NCIPMessage/ItemRequested/ItemOptionalFields/BibliographicDescription/Author');  
-       my $title    = $doc->findvalue('/NCIPMessage/ItemRequested/ItemOptionalFields/BibliographicDescription/Title');  
-       my $callnumber    = $doc->findvalue('/NCIPMessage/ItemRequested/ItemOptionalFields/ItemDescription/CallNumber');  
-
-       my $r = "default error checking response"; 
-
-       if ($UniqueItemIdAgencyIdValue eq SPECIALFROMAGENCY ) { 
-               my $localid = locid_from_barcode($barcode);
-               $r = place_simple_hold($localid, SPECIALFROMAGENCYID );
-       } 
-       else {
-               my $copy_status_id = 110; # INN-Reach loan 
-               $barcode .= $faidValue;
-               $r = create_copy($title, $callnumber, $barcode, $copy_status_id);
-       }
-
-my $hd = <<ITEMREQ; 
+    my $faidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequested/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    my $faidScheme = HTML::Entities::encode($faidSchemeX);
+    my $faidValue  = $doc->find('/NCIPMessage/ItemRequested/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+
+    my $taidSchemeX = $doc->findvalue('/NCIPMessage/ItemRequested/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    my $taidScheme = HTML::Entities::encode($taidSchemeX);
+    my $taidValue  = $doc->find('/NCIPMessage/ItemRequested/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
+    my $UniqueItemIdAgencyIdValue = $doc->findvalue('/NCIPMessage/ItemRequested/UniqueItemId/UniqueAgencyId/Value');
+
+    # TODO: should we use the VisibleID for item agency variation of this method call
+
+    my $pid = $doc->findvalue('/NCIPMessage/ItemRequested/UniqueUserId/UserIdentifierValue');
+    my $barcode = $doc->findvalue('/NCIPMessage/ItemRequested/UniqueItemId/ItemIdentifierValue');
+    my $author = $doc->findvalue('/NCIPMessage/ItemRequested/ItemOptionalFields/BibliographicDescription/Author');
+    my $title = $doc->findvalue('/NCIPMessage/ItemRequested/ItemOptionalFields/BibliographicDescription/Title');
+    my $callnumber = $doc->findvalue('/NCIPMessage/ItemRequested/ItemOptionalFields/ItemDescription/CallNumber');
+    my $medium_type = $doc->find('/NCIPMessage/ItemRequested/ItemOptionalFields/BibliographicDescription/MediumType/Value');
+
+    my $r = "default error checking response";
+
+    if ( $barcode =~ /^i/ ) {    # XXX EG is User Agency # create copy only if barcode is an iNUMBER
+        my $copy_status_id = 110;    # XXX CUSTOMIZATION NEEDED XXX # INN-Reach Loan Requested - local configured status
+        $barcode .= $faidValue;
+        # we want our custom status to be then end result, so create the copy with status of "Available, then hold it, then update the status
+        $r = create_copy( $title, $callnumber, $barcode, 0, $medium_type );
+        my $copy = copy_from_barcode($barcode);
+        my $r2   = place_simple_hold( $copy->id, $pid );
+        my $r3   = update_copy( $copy, $copy_status_id );
+    } else {    # XXX EG is Item Agency
+        # place hold for user UniqueUserId/UniqueAgencyId/Value = institution account
+        my $copy = copy_from_barcode($barcode);
+        my $pid2 = 1013459; # XXX CUSTOMIZATION NEEDED XXX # this is the id of a user representing your DCB system, TODO: use agency information to create and link to individual accounts per agency, if needed
+        $r = place_simple_hold( $copy->id, $pid2 );
+        my $r2 = update_copy( $copy, 111 ); # XXX CUSTOMIZATION NEEDED XXX # put into INN-Reach Hold status
+    }
+
+    my $hd = <<ITEMREQ;
 Content-type: text/xml
 
 
@@ -601,15 +705,15 @@ Content-type: text/xml
                 <Scheme datatype="string">$taidScheme</Scheme>
                 <Value datatype="string">$taidValue</Value>
             </UniqueAgencyId>
-            <UserIdentifierValue datatype="string">$id</UserIdentifierValue>
+            <UserIdentifierValue datatype="string">$pid</UserIdentifierValue>
         </UniqueUserId>
         <UniqueItemId>
             <ItemIdentifierValue datatype="string">$barcode</ItemIdentifierValue>
         </UniqueItemId>
         <ItemOptionalFields>
             <BibliographicDescription>
-               <Author datatype="string">$author</Author>
-               <Title datatype="string">$title</Title>
+        <Author datatype="string">$author</Author>
+        <Title datatype="string">$title</Title>
             </BibliographicDescription>
             <ItemDescription>
                 <CallNumber datatype="string">$callnumber</CallNumber>
@@ -620,136 +724,197 @@ Content-type: text/xml
 
 ITEMREQ
 
-       logit($hd,(caller(0))[3]);
+    logit( $hd, ( caller(0) )[3] );
+    staff_log( $taidValue, $faidValue,
+        "ItemRequested -> Barcode : " . $barcode . " | Title : " . $title . " | Call Number : " . $callnumber . " | Patronid :" . $pid );
 }
 
+sub lookupUser {
 
-sub lookupUser { 
+    my $faidScheme = $doc->findvalue('/NCIPMessage/LookupUser/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');
+    $faidScheme = HTML::Entities::encode($faidScheme);
+    my $faidValue = $doc->find('/NCIPMessage/LookupUser/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');
+    my $taidScheme = $doc->findvalue('/NCIPMessage/LookupUser/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');
+    $taidScheme = HTML::Entities::encode($taidScheme);
 
-my $faidScheme = $doc->findvalue('/NCIPMessage/LookupUser/InitiationHeader/FromAgencyId/UniqueAgencyId/Scheme');  
-$faidScheme = HTML::Entities::encode($faidScheme);
-my $faidValue  = $doc->find('/NCIPMessage/LookupUser/InitiationHeader/FromAgencyId/UniqueAgencyId/Value');  
-my $taidScheme = $doc->findvalue('/NCIPMessage/LookupUser/InitiationHeader/ToAgencyId/UniqueAgencyId/Scheme');  
-$taidScheme = HTML::Entities::encode($taidScheme);
+    my $taidValue = $doc->find('/NCIPMessage/LookupUser/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');
+    my $id = $doc->findvalue('/NCIPMessage/LookupUser/VisibleUserId/VisibleUserIdentifier');
+    my $uidValue = user_id_from_barcode($id);
 
-my $taidValue  = $doc->find('/NCIPMessage/LookupUser/InitiationHeader/ToAgencyId/UniqueAgencyId/Value');  
-my $id         = $doc->findvalue('/NCIPMessage/LookupUser/VisibleUserId/VisibleUserIdentifier');  
-my $uidValue   = user_id_from_barcode($id);
+    if ( !defined($uidValue)
+        || ( ref($uidValue) && reftype($uidValue) eq 'HASH' ) )
+    {
+        do_lookup_user_error_stanza("PATRON_NOT_FOUND : $id");
+        die;
+    }
 
-if (!defined($uidValue) || (ref($uidValue) && reftype($uidValue) eq 'HASH')) {
-        do_lookup_user_error_stanza("PATRON_NOT_FOUND");
-       die;
-}
+    my ( $propername, $email, $good_until, $userprivid, $block_stanza ) =
+      ( "name here", "", "good until", "0", "" );    # defaults
 
-my ($propername,$email,$good_until,$userprivid) = ("name here","","good until","0") ;
-            
-my $patron = flesh_user($uidValue);
-            
-#if (blessed($patron)) {
-       if ($patron->deleted eq 't') {
-               do_lookup_user_error_stanza("PATRON_DELETED");
-                die;
-        }
-       $propername = $patron->first_given_name . " " . $patron->family_name;
-
-        if ( defined($patron->email) ) {
-       $email = qq(
-               <UserAddressInformation>
-                        <ElectronicAddress>
-                                <ElectronicAddressType>
-                                        <Scheme datatype="string">http:/blah.com</Scheme>
-                                        <Value datatype="string">mailto</Value>
-                                </ElectronicAddressType>
-                                <ElectronicAddressData datatype="string">).HTML::Entities::encode($patron->email).qq(</ElectronicAddressData>]
-                        </ElectronicAddress>
-                </UserAddressInformation>);
-       }
-
-        $good_until = $patron->expire_date || "unknown";
-        $userprivid = $patron->profile;
-        #my $homeOU = $patron->home_ou->name;
-        my $userpriv = $patron->profile->name;
-
-my $hd =            <<LOOKUPUSERRESPONSE;
+    my $patron = flesh_user($uidValue);
+
+    #if (blessed($patron)) {
+    my $patron_ok = 1;
+    my @penalties = @{ $patron->standing_penalties };
+
+    if ( $patron->deleted eq 't' ) {
+        do_lookup_user_error_stanza("PATRON_DELETED : $uidValue");
+        die;
+    } elsif ( $patron->barred eq 't' ) {
+        do_lookup_user_error_stanza("PATRON_BARRED : $uidValue");
+        die;
+    } elsif ( $patron->active eq 'f' ) {
+        do_lookup_user_error_stanza("PATRON_INACTIVE : $uidValue");
+        die;
+    }
+
+    elsif ( $#penalties > -1 ) {
+
+#                my $penalty;
+#                   foreach $penalty (@penalties) {
+#                    if (defined($penalty->standing_penalty->block_list)) {
+#                            my @block_list = split(/\|/, $penalty->standing_penalty->block_list);
+#                            foreach my $block (@block_list) {
+#                                foreach my $block_on (@$block_types) {
+#                                    if ($block eq $block_on) {
+#                                        $block_stanza .= "\n".$penalty->standing_penalty->name;
+#                                        $patron_ok = 0;
+#                                    }
+#                                    last unless ($patron_ok);
+#                            }
+#                                last unless ($patron_ok);
+#                          }
+#                     }
+#                }
+        $block_stanza = qq(
+            <BlockOrTrap>
+                <UniqueAgencyId>
+                    <Scheme datatype="string">http://just.testing.now</Scheme>
+                    <Value datatype="string">$faidValue</Value>
+                </UniqueAgencyId>
+                <BlockOrTrapType>
+                    <Scheme datatype="string">http://just.testing.now</Scheme>
+                    <Value datatype="string">Block Hold</Value>
+                </BlockOrTrapType>
+            </BlockOrTrap>);
+    }
+
+    if ( defined( $patron->email ) ) {
+        $email = qq(
+            <UserAddressInformation>
+                <ElectronicAddress>
+                    <ElectronicAddressType>
+                        <Scheme datatype="string">http://testing.now</Scheme>
+                        <Value datatype="string">mailto</Value>
+                    </ElectronicAddressType>
+                    <ElectronicAddressData datatype="string">)
+          . HTML::Entities::encode( $patron->email )
+          . qq(</ElectronicAddressData>
+                </ElectronicAddress>
+            </UserAddressInformation>);
+    }
+
+    $propername = $patron->first_given_name . " " . $patron->family_name;
+    $good_until = $patron->expire_date || "unknown";
+    $userprivid = $patron->profile;
+    my $userou   = $patron->home_ou->name;
+    my $userpriv = $patron->profile->name;
+
+    #} else {
+    #    do_lookup_user_error_stanza("PATRON_NOT_FOUND : $id");
+    #    die;
+    #}
+    my $uniqid = $patron->id;
+    my $visid  = $patron->card->barcode;
+    my $hd = <<LOOKUPUSERRESPONSE;
 Content-type: text/xml
 
 
 <!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
 <NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
-   <LookupUserResponse>
-       <ResponseHeader>
-           <FromAgencyId>
-               <UniqueAgencyId>
-                   <Scheme>$taidScheme</Scheme>
-                   <Value>$taidValue</Value>
-               </UniqueAgencyId>
-           </FromAgencyId>
-           <ToAgencyId>
-               <UniqueAgencyId>
+    <LookupUserResponse>
+        <ResponseHeader>
+            <FromAgencyId>
+                <UniqueAgencyId>
+                    <Scheme>$taidScheme</Scheme>
+                    <Value>$taidValue</Value>
+                </UniqueAgencyId>
+            </FromAgencyId>
+            <ToAgencyId>
+                <UniqueAgencyId>
                    <Scheme>$faidScheme</Scheme>
                    <Value>$faidValue</Value>
-               </UniqueAgencyId>
-           </ToAgencyId>
-       </ResponseHeader>
-       <UniqueUserId>
-           <UniqueAgencyId>
-               <Scheme>$taidScheme</Scheme>
-               <Value>$taidValue</Value>
-           </UniqueAgencyId>
-           <UserIdentifierValue>$id</UserIdentifierValue>
-       </UniqueUserId>
-       <UserOptionalFields>
-               <VisibleUserId>
-                       <VisibleUserIdentifierType>
-                               <Scheme datatype="string">http://blah.com</Scheme>
-                               <Value datatype="string">Barcode</Value>
-                       </VisibleUserIdentifierType>
-                       <VisibleUserIdentifier datatype="string">$id</VisibleUserIdentifier>
-               </VisibleUserId>
-               <NameInformation>
-                       <PersonalNameInformation>
-                               <UnstructuredPersonalUserName datatype="string">$propername</UnstructuredPersonalUserName>
-                       </PersonalNameInformation>
-               </NameInformation>
-               <UserPrivilege>
-                       <UniqueAgencyId>
-                               <Scheme datatype="string">$faidScheme</Scheme>
-                               <Value datatype="string">$faidValue</Value>
-                       </UniqueAgencyId>
-                       <AgencyUserPrivilegeType>
-                               <Scheme datatype="string">http://testing.purposes.only</Scheme>
-                                <Value datatype="string">$userpriv</Value>
-                       </AgencyUserPrivilegeType>
-                       <ValidToDate datatype="string">$good_until</ValidToDate>
-               </UserPrivilege> $email
-       </UserOptionalFields>
+                </UniqueAgencyId>
+            </ToAgencyId>
+        </ResponseHeader>
+        <UniqueUserId>
+            <UniqueAgencyId>
+                <Scheme>$taidScheme</Scheme>
+                <Value>$taidValue</Value>
+            </UniqueAgencyId>
+            <UserIdentifierValue>$uniqid</UserIdentifierValue>
+        </UniqueUserId>
+        <UserOptionalFields>
+            <VisibleUserId>
+                <VisibleUserIdentifierType>
+                    <Scheme datatype="string">http://blah.com</Scheme>
+                    <Value datatype="string">Barcode</Value>
+                </VisibleUserIdentifierType>
+                <VisibleUserIdentifier datatype="string">$visid</VisibleUserIdentifier>
+            </VisibleUserId>
+            <NameInformation>
+                <PersonalNameInformation>
+                    <UnstructuredPersonalUserName datatype="string">$propername</UnstructuredPersonalUserName>
+                </PersonalNameInformation>
+            </NameInformation>
+            <UserPrivilege>
+                <UniqueAgencyId>
+                    <Scheme datatype="string">$faidScheme</Scheme>
+                    <Value datatype="string">$faidValue</Value>
+                </UniqueAgencyId>
+                <AgencyUserPrivilegeType>
+                    <Scheme datatype="string">http://testing.purposes.only</Scheme>
+                    <Value datatype="string">$userprivid</Value>
+                </AgencyUserPrivilegeType>
+                <ValidToDate datatype="string">$good_until</ValidToDate>
+            </UserPrivilege> $email $block_stanza
+        </UserOptionalFields>
    </LookupUserResponse>
 </NCIPMessage>
 
 LOOKUPUSERRESPONSE
 
-logit($hd,(caller(0))[3]);
+    logit( $hd, ( caller(0) )[3] );
+    staff_log( $taidValue, $faidValue,
+            "LookupUser -> Patron Barcode : "
+          . $id
+          . " | Patron Id : "
+          . $uidValue
+          . " | User Name : "
+          . $propername
+          . " | User Priv : "
+          . $userpriv );
 }
 
-
 sub fail {
-my $error_msg = shift || "THIS IS THE DEFAULT NCIP RESP MSG";
-print "Content-type: text/xml\n\n";
+    my $error_msg =
+      shift || "THIS IS THE DEFAULT / DO NOT HANG III NCIP RESP MSG";
+    print "Content-type: text/xml\n\n";
 
-print <<ITEMREQ; 
+    print <<ITEMREQ;
 <!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
 <NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
     <ItemRequestedResponse>
         <ResponseHeader>
             <FromAgencyId>
                 <UniqueAgencyId>
-                    <Scheme>http://scheme.server.here/IRCIRCD?target=get_scheme_values&amp;scheme=UniqueAgencyId</Scheme>
+                    <Scheme>http://136.181.125.166:6601/IRCIRCD?target=get_scheme_values&amp;scheme=UniqueAgencyId</Scheme>
                     <Value></Value>
                 </UniqueAgencyId>
             </FromAgencyId>
             <ToAgencyId>
                 <UniqueAgencyId>
-                    <Scheme>http://scheme.server.here/IRCIRCD?target=get_scheme_values&amp;scheme=UniqueAgencyId</Scheme>
+                    <Scheme>http://136.181.125.166:6601/IRCIRCD?target=get_scheme_values&amp;scheme=UniqueAgencyId</Scheme>
                     <Value>$error_msg</Value>
                 </UniqueAgencyId>
             </ToAgencyId>
@@ -758,49 +923,58 @@ print <<ITEMREQ;
 </NCIPMessage>
 
 ITEMREQ
+
+    # XXX: we should log FromAgencyId and ToAgencyId values here, but they are not available to the code at this point
+    staff_log( '', '',
+        ( ( caller(0) )[3] . " -> " . $error_msg ) );
+    die;
 }
 
 sub do_lookup_user_error_stanza {
 
-my $error = shift;
-my $hd = <<LOOKUPPROB;
+    # XXX: we should include FromAgencyId and ToAgencyId values, but they are not available to the code at this point
+    my $error = shift;
+    my $hd    = <<LOOKUPPROB;
 Content-type: text/xml
 
 
 <!DOCTYPE NCIPMessage PUBLIC "-//NISO//NCIP DTD Version 1.0//EN" "http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
 <NCIPMessage version="http://www.niso.org/ncip/v1_0/imp1/dtd/ncip_v1_0.dtd">
-<LookupUserResponse>
-       <ResponseHeader>
-           <FromAgencyId>
-               <UniqueAgencyId>
-                   <Scheme>$taidScheme</Scheme>
-                   <Value>$taidValue</Value>
-               </UniqueAgencyId>
-           </FromAgencyId>
-           <ToAgencyId>
-               <UniqueAgencyId>
-                   <Scheme>$faidScheme</Scheme>
-                   <Value>$faidValue</Value>
-               </UniqueAgencyId>
-           </ToAgencyId>
-       </ResponseHeader>
+    <LookupUserResponse>
+        <ResponseHeader>
+            <FromAgencyId>
+                <UniqueAgencyId>
+                    <Scheme></Scheme>
+                    <Value></Value>
+                </UniqueAgencyId>
+            </FromAgencyId>
+            <ToAgencyId>
+                <UniqueAgencyId>
+                    <Scheme></Scheme>
+                    <Value></Value>
+                </UniqueAgencyId>
+            </ToAgencyId>
+        </ResponseHeader>
         <Problem>
-                <ProcessingError>
-                        <ProcessingErrorType>
-                                <Scheme>http://www.niso.org/ncip/v1_0/schemes/processingerrortype/lookupuserprocessingerror.scm</Scheme>
-                                <Value>$error</Value>
-                        </ProcessingErrorType>
-                        <ProcessingErrorElement>
-                                <ElementName>AuthenticationInput</ElementName>
-                        </ProcessingErrorElement></ProcessingError>
-                </ProcessingError>
-       </Problem>
-</LookupUserResponse>
+            <ProcessingError>
+                <ProcessingErrorType>
+                    <Scheme>http://www.niso.org/ncip/v1_0/schemes/processingerrortype/lookupuserprocessingerror.scm</Scheme>
+                    <Value>$error</Value>
+                </ProcessingErrorType>
+                <ProcessingErrorElement>
+                    <ElementName>AuthenticationInput</ElementName>
+                </ProcessingErrorElement>
+            </ProcessingError>
+        </Problem>
+    </LookupUserResponse>
 </NCIPMessage>
 
 LOOKUPPROB
 
-logit($hd,(caller(0))[3]);
+    logit( $hd, ( caller(0) )[3] );
+    # XXX: we should log FromAgencyId and ToAgencyId values here, but they are not available to the code at this point
+    staff_log( '', '', ( ( caller(0) )[3] . " -> " . $error ) );
+    die;
 }
 
 # Login to the OpenSRF system/Evergreen.
@@ -809,41 +983,41 @@ logit($hd,(caller(0))[3]);
 # seconds since 1/1/1970).
 sub login {
 
-my $bootstrap = '/openils/conf/opensrf_core.xml';
-my $uname = "USERNAMEHERE"; 
-my $password = "PASSWORDHERE";
-my $workstation = "REGISTEREDWORKSTATIONHERE";
+ # XXX: local opensrf core conf filename should be in config.
+ # XXX: STAFF account with ncip service related permissions should be in config.
+    my $bootstrap = '/openils/conf/opensrf_core.xml';
+    my $uname     = $conf->{auth}->{username};
+    my $password  = $conf->{auth}->{password};
 
-# Bootstrap the client
-OpenSRF::System->bootstrap_client(config_file => $bootstrap);
-my $idl = OpenSRF::Utils::SettingsClient->new->config_value("IDL");
-Fieldmapper->import(IDL => $idl);
+    # Bootstrap the client
+    OpenSRF::System->bootstrap_client( config_file => $bootstrap );
+    my $idl = OpenSRF::Utils::SettingsClient->new->config_value("IDL");
+    Fieldmapper->import( IDL => $idl );
 
-# Initialize CStoreEditor:
-OpenILS::Utils::CStoreEditor->init;
+    # Initialize CStoreEditor:
+    OpenILS::Utils::CStoreEditor->init;
 
-    my $seed = OpenSRF::AppSession
-        ->create('open-ils.auth')
-        ->request('open-ils.auth.authenticate.init', $uname)
-        ->gather(1);
+    my $seed = OpenSRF::AppSession->create('open-ils.auth')
+      ->request( 'open-ils.auth.authenticate.init', $uname )->gather(1);
 
     return undef unless $seed;
 
-    my $response = OpenSRF::AppSession
-        ->create('open-ils.auth')
-        ->request('open-ils.auth.authenticate.complete',
-                  { username => $uname,
-                    password => md5_hex($seed . md5_hex($password)),
-                    type => 'staff' })
-#                    workstation => $workstation })
-        ->gather(1);
+    my $response = OpenSRF::AppSession->create('open-ils.auth')->request(
+        'open-ils.auth.authenticate.complete',
+        {
+            username => $uname,
+            password => md5_hex( $seed . md5_hex($password) ),
+            type     => 'staff'
+        }
+    )->gather(1);
 
     return undef unless $response;
 
     my %result;
-    $result{'authtoken'} = $response->{payload}->{authtoken};
-    $result{'authtime'} = $response->{payload}->{authtime};
-    $result{'expiration'} = time() + $result{'authtime'} if (defined($result{'authtime'}));
+    $result{'authtoken'}  = $response->{payload}->{authtoken};
+    $result{'authtime'}   = $response->{payload}->{authtime};
+    $result{'expiration'} = time() + $result{'authtime'}
+      if ( defined( $result{'authtime'} ) );
     return %result;
 }
 
@@ -858,9 +1032,9 @@ OpenILS::Utils::CStoreEditor->init;
 # Returns
 # Nothing
 sub check_session_time {
-    if (time() > $session{'expiration'}) {
+    if ( time() > $session{'expiration'} ) {
         %session = login();
-        if (!%session) {
+        if ( !%session ) {
             die("Failed to reinitialize the session after expiration.");
         }
     }
@@ -869,8 +1043,10 @@ sub check_session_time {
 # Retrieve the logged in user.
 #
 sub get_session {
-    my $response = OpenSRF::AppSession->create('open-ils.auth')
-        ->request('open-ils.auth.session.retrieve', $session{authtoken})->gather(1);
+    my $response =
+      OpenSRF::AppSession->create('open-ils.auth')
+      ->request( 'open-ils.auth.session.retrieve', $session{authtoken} )
+      ->gather(1);
     return $response;
 }
 
@@ -882,14 +1058,14 @@ sub get_session {
 # Returns
 # Does not return anything
 sub logout {
-    if (time() < $session{'expiration'}) {
-        my $response = OpenSRF::AppSession
-            ->create('open-ils.auth')
-            ->request('open-ils.auth.session.delete', $session{authtoken})
-            ->gather(1);
+    if ( time() < $session{'expiration'} ) {
+        my $response =
+          OpenSRF::AppSession->create('open-ils.auth')
+          ->request( 'open-ils.auth.session.delete', $session{authtoken} )
+          ->gather(1);
         if ($response) {
-        #    fail("Logout successful. Good-bye.\n");
-       # strong.silent.success
+
+            # strong.silent.success
             exit(0);
         } else {
             fail("Logout unsuccessful. Good-bye, anyway.");
@@ -899,9 +1075,9 @@ sub logout {
 
 sub update_copy {
     check_session_time();
-    my ($copy,$status_id) = @_;
-    my $e = new_editor(authtoken=>$session{authtoken});
-    return $e->event->{textcode} unless ($e->checkauth);
+    my ( $copy, $status_id ) = @_;
+    my $e = new_editor( authtoken => $session{authtoken} );
+    return $e->event->{textcode} unless ( $e->checkauth );
     $e->xact_begin;
     $copy->status($status_id);
     return $e->event unless $e->update_asset_copy($copy);
@@ -912,9 +1088,9 @@ sub update_copy {
 # my paranoia re barcode on shipped items using visid for unique value
 sub update_copy_shipped {
     check_session_time();
-    my ($copy,$status_id,$barcode) = @_;
-    my $e = new_editor(authtoken=>$session{authtoken});
-    return $e->event->{textcode} unless ($e->checkauth);
+    my ( $copy, $status_id, $barcode ) = @_;
+    my $e = new_editor( authtoken => $session{authtoken} );
+    return $e->event->{textcode} unless ( $e->checkauth );
     $e->xact_begin;
     $copy->status($status_id);
     $copy->barcode($barcode);
@@ -935,27 +1111,29 @@ sub delete_copy {
     check_session_time();
     my ($copy) = @_;
 
-    my $e = new_editor(authtoken=>$session{authtoken});
-    return $e->event->{textcode} unless ($e->checkauth);
+    my $e = new_editor( authtoken => $session{authtoken} );
+    return $e->event->{textcode} unless ( $e->checkauth );
 
     # Get the calnumber
-    my $vol = $e->retrieve_asset_call_number($copy->call_number);
+    my $vol = $e->retrieve_asset_call_number( $copy->call_number );
     return $e->event->{textcode} unless ($vol);
 
     # Get the biblio.record_entry
-    my $bre = $e->retrieve_biblio_record_entry($vol->record);
+    my $bre = $e->retrieve_biblio_record_entry( $vol->record );
     return $e->event->{textcode} unless ($bre);
 
     # Delete everything in a transaction and rollback if anything fails.
+    # TODO: I think there is a utility function which handles all this
     $e->xact_begin;
-    my $r; # To hold results of editor calls
+    my $r;    # To hold results of editor calls
     $r = $e->delete_asset_copy($copy);
     unless ($r) {
         my $lval = $e->event->{textcode};
         $e->rollback;
         return $lval;
     }
-    my $list = $e->search_asset_copy({call_number => $vol->id, deleted => 'f'});
+    my $list =
+      $e->search_asset_copy( { call_number => $vol->id, deleted => 'f' } );
     unless (@$list) {
         $r = $e->delete_asset_call_number($vol);
         unless ($r) {
@@ -963,10 +1141,9 @@ sub delete_copy {
             $e->rollback;
             return $lval;
         }
-        $list = $e->search_asset_call_number({record => $bre->id, deleted => 'f'});
+        $list = $e->search_asset_call_number( { record => $bre->id, deleted => 'f' } );
         unless (@$list) {
-            $bre->deleted('t');
-            $r = $e->update_biblio_record_entry($bre);
+            $r = $e->delete_biblio_record_entry($bre);
             unless ($r) {
                 my $lval = $e->event->{textcode};
                 $e->rollback;
@@ -988,24 +1165,26 @@ sub delete_copy {
 sub copy_from_barcode {
     check_session_time();
     my ($barcode) = @_;
-    my $response = OpenSRF::AppSession->create('open-ils.search')
-        ->request('open-ils.search.asset.copy.find_by_barcode', $barcode)
-        ->gather(1);
+    my $response =
+      OpenSRF::AppSession->create('open-ils.search')
+      ->request( 'open-ils.search.asset.copy.find_by_barcode', $barcode )
+      ->gather(1);
     return $response;
 }
 
 sub locid_from_barcode {
     my ($barcode) = @_;
-    my $response = OpenSRF::AppSession->create('open-ils.search')
-        ->request('open-ils.search.biblio.find_by_barcode', $barcode)
-        ->gather(1);
+    my $response =
+      OpenSRF::AppSession->create('open-ils.search')
+      ->request( 'open-ils.search.biblio.find_by_barcode', $barcode )
+      ->gather(1);
     return $response->{ids}[0];
 }
 
 # Convert a MARC::Record to XML for Evergreen
 #
-# Stolen from Dyrcona's issa framework which copied
-# it from MVLC's Safari Load program which copied it 
+# Copied from Dyrcona's issa framework which copied
+# it from MVLC's Safari Load program which copied it
 # from some code in the Open-ILS example import scripts.
 #
 # Argument
@@ -1015,11 +1194,11 @@ sub locid_from_barcode {
 # String with XML for the MARC::Record as Evergreen likes it
 sub convert2marcxml {
     my $input = shift;
-    (my $xml = $input->as_xml_record()) =~ s/\n//sog;
+    ( my $xml = $input->as_xml_record() ) =~ s/\n//sog;
     $xml =~ s/^<\?xml.+\?\s*>//go;
     $xml =~ s/>\s+</></go;
     $xml =~ s/\p{Cc}//go;
-    $xml = OpenILS::Application::AppUtils->entityize($xml);
+    $xml = $U->entityize($xml);
     $xml =~ s/[\x00-\x1f]//go;
     return $xml;
 }
@@ -1036,76 +1215,88 @@ sub convert2marcxml {
 # event textcode on failure
 sub create_copy {
     check_session_time();
-    my ($title, $callnumber, $barcode, $copy_status_id) = @_;
+    my ( $title, $callnumber, $barcode, $copy_status_id, $medium_type ) = @_;
 
-    my $e = new_editor(authtoken=>$session{authtoken});
-    return $e->event->{textcode} unless ($e->checkauth);
+    my $e = new_editor( authtoken => $session{authtoken} );
+    return $e->event->{textcode} unless ( $e->checkauth );
 
-    my $r = $e->allowed(['CREATE_COPY', 'CREATE_MARC', 'CREATE_VOLUME']);
-    if (ref($r) eq 'HASH') {
+    my $r = $e->allowed( [ 'CREATE_COPY', 'CREATE_MARC', 'CREATE_VOLUME' ] );
+    if ( ref($r) eq 'HASH' ) {
         return $r->{textcode} . ' ' . $r->{ilsperm};
     }
 
     # Check if the barcode exists in asset.copy and bail if it does.
-    my $list = $e->search_asset_copy({deleted => 'f', barcode => $barcode});
+    my $list = $e->search_asset_copy( { deleted => 'f', barcode => $barcode } );
     if (@$list) {
-# can we update it, if it exists? only if it is an INN-Reach status item
+# in the future, can we update it, if it exists and only if it is an INN-Reach status item ?
         $e->finish;
-        fail('BARCODE_EXISTS');
+        fail( 'BARCODE_EXISTS ! Barcode : ' . $barcode );
+        die;
     }
 
     # Create MARC record
     my $record = MARC::Record->new();
     $record->encoding('UTF-8');
     $record->leader('00881nam a2200193 4500');
-    my $datespec = strftime("%Y%m%d%H%M%S.0", localtime);
+    my $datespec = strftime( "%Y%m%d%H%M%S.0", localtime );
     my @fields = ();
-    push(@fields, MARC::Field->new('005', $datespec));
-    push(@fields, MARC::Field->new('082', '0', '4', 'a' => $callnumber));
-    push(@fields, MARC::Field->new('245', '0', '0', 'a' => $title));
+    push( @fields, MARC::Field->new( '005', $datespec ) );
+    push( @fields, MARC::Field->new( '082', '0', '4', 'a' => $callnumber ) );
+    push( @fields, MARC::Field->new( '245', '0', '0', 'a' => $title ) );
     $record->append_fields(@fields);
 
     # Convert the record to XML
     my $xml = convert2marcxml($record);
 
-    my $bre = OpenSRF::AppSession->create('open-ils.cat')
-        ->request('open-ils.cat.biblio.record.xml.import', $session{authtoken}, $xml, 'System Local', 1)
-        ->gather(1);
-    return $bre->{textcode} if (ref($bre) eq 'HASH');
+    my $bre =
+      OpenSRF::AppSession->create('open-ils.cat')
+      ->request( 'open-ils.cat.biblio.record.xml.import',
+        $session{authtoken}, $xml, 'System Local', 1 )->gather(1);
+    return $bre->{textcode} if ( ref($bre) eq 'HASH' );
 
     # Create volume record
-    my $vol = OpenSRF::AppSession->create('open-ils.cat')
-        ->request('open-ils.cat.call_number.find_or_create', $session{authtoken}, $callnumber, $bre->id, 10)
-        ->gather(1);
-    return $vol->{textcode} if ($vol->{textcode});
+    my $vol =
+      OpenSRF::AppSession->create('open-ils.cat')
+      ->request( 'open-ils.cat.call_number.find_or_create', $session{authtoken}, $callnumber, $bre->id, 2 )   # XXX CUSTOMIZATION NEEDED XXX
+      ->gather(1);
+    return $vol->{textcode} if ( $vol->{textcode} );
 
     # Retrieve the user
     my $user = get_session;
+
     # Create copy record
     my $copy = Fieldmapper::asset::copy->new();
+    # XXX CUSTOMIZATION NEEDED XXX
+    # You will need to either create a circ mod for every expected medium type,
+    # OR you should create a single circ mod for all requests from the external
+    # system.
+    # Adjust these lines as needed.
+    #    $copy->circ_modifier(qq($medium_type)); # XXX CUSTOMIZATION NEEDED XXX
+    # OR
+    $copy->circ_modifier('DCB'); # XXX CUSTOMIZATION NEEDED XXX
     $copy->barcode($barcode);
-    $copy->call_number($vol->{acn_id});
-    $copy->circ_lib(10);
+    $copy->call_number( $vol->{acn_id} );
+    $copy->circ_lib(2); # XXX CUSTOMIZATION NEEDED XXX
     $copy->circulate('t');
     $copy->holdable('t');
     $copy->opac_visible('t');
     $copy->deleted('f');
     $copy->fine_level(2);
     $copy->loan_duration(2);
-    $copy->location(1);
+    $copy->location(156); # XXX CUSTOMIZATION NEEDED XXX
     $copy->status($copy_status_id);
-    $copy->editor('1002741');
-    $copy->creator('1002741');
+    $copy->editor('1');
+    $copy->creator('1');
 
     # Add the configured stat cat entries.
     #my @stat_cats;
-    #my $nodes = $xpath->find("stat_cat_entry");
+    #my $nodes = $xpath->find("/copy/stat_cat_entry");
     #foreach my $node ($nodes->get_nodelist) {
     #    next unless ($node->isa('XML::XPath::Node::Element'));
     #    my $stat_cat_id = $node->getAttribute('stat_cat');
     #    my $value = $node->string_value();
     #    # Need to search for an existing asset.stat_cat_entry
-        my $asce = $e->search_asset_stat_cat_entry({'stat_cat' => $stat_cat_id, 'value' => $value})->[0];
+    #        my $asce = $e->search_asset_stat_cat_entry({'stat_cat' => $stat_cat_id, 'value' => $value})->[0];
     #    unless ($asce) {
     #        # if not, create a new one and use its id.
     #        $asce = Fieldmapper::asset::stat_cat_entry->new();
@@ -1121,6 +1312,7 @@ sub create_copy {
 
     $e->xact_begin;
     $copy = $e->create_asset_copy($copy);
+
     #if (scalar @stat_cats) {
     #    foreach my $asce (@stat_cats) {
     #        my $ascecm = Fieldmapper::asset::stat_cat_entry_copy_map->new();
@@ -1143,82 +1335,83 @@ sub create_copy {
 #
 # Returns
 # textcode of the OSRF response.
-sub checkout
-{
+sub checkout {
     check_session_time();
-    my ($copy_barcode, $patron_barcode, $due_date) = @_;
+    my ( $copy_barcode, $patron_barcode, $due_date ) = @_;
 
     # Check for copy:
     my $copy = copy_from_barcode($copy_barcode);
-    unless (defined($copy) && blessed($copy)) {
-        return 'COPY_BARCODE_NOT_FOUND';
+    unless ( defined($copy) && blessed($copy) ) {
+        return 'COPY_BARCODE_NOT_FOUND : ' . $copy_barcode;
     }
 
     # Check for user
     my $uid = user_id_from_barcode($patron_barcode);
-    return 'PATRON_BARCODE_NOT_FOUND' if (ref($uid));
-
-    my $response = OpenSRF::AppSession->create('open-ils.circ')
-        ->request('open-ils.circ.checkout.full.override', $session{authtoken},
-                  { copy_barcode => $copy_barcode,
-                    patron_barcode => $patron_barcode,
-                   due_date => $due_date })
-        ->gather(1);
+    return 'PATRON_BARCODE_NOT_FOUND : ' . $patron_barcode if ( ref($uid) );
+
+    my $response = OpenSRF::AppSession->create('open-ils.circ')->request(
+        'open-ils.circ.checkout.full.override',
+        $session{authtoken},
+        {
+            copy_barcode => $copy_barcode,
+            patron_id    => $uid,
+            due_date     => $due_date
+        }
+    )->gather(1);
     return $response->{textcode};
 }
 
-sub renewal
-{
+sub renewal {
     check_session_time();
-    my ($copy_barcode, $due_date) = @_;
+    my ( $copy_barcode, $due_date ) = @_;
 
     # Check for copy:
     my $copy = copy_from_barcode($copy_barcode);
-    unless (defined($copy) && blessed($copy)) {
-        return 'COPY_BARCODE_NOT_FOUND';
+    unless ( defined($copy) && blessed($copy) ) {
+        return 'COPY_BARCODE_NOT_FOUND : ' . $copy_barcode;
     }
 
-
-    my $response = OpenSRF::AppSession->create('open-ils.circ')
-        ->request('open-ils.circ.renew', $session{authtoken},
-                  { copy_barcode => $copy_barcode,
-                   due_date => $due_date })
-        ->gather(1);
+    my $response = OpenSRF::AppSession->create('open-ils.circ')->request(
+        'open-ils.circ.renew.override',
+        $session{authtoken},
+        {
+            copy_barcode => $copy_barcode,
+            due_date     => $due_date
+        }
+    )->gather(1);
     return $response->{textcode};
 }
 
-# Check a copy in at an org_unit
+# Check a copy in
 #
 # Arguments
 # copy barcode
-# org_unit
 #
 # Returns
 # "SUCCESS" on success
 # textcode of a failed OSRF request
-# 'COPY_NOT_CHECKED_OUT' when the copy is not checked out or not
-# checked out to the user's work_ou
-sub checkin
-{
+# 'COPY_NOT_CHECKED_OUT' when the copy is not checked out
+
+sub checkin {
     check_session_time();
-    my ($barcode, $where) = @_;
+    my ($barcode) = @_;
 
     my $copy = copy_from_barcode($barcode);
-    return $copy->{textcode} unless (blessed $copy);
-
-    return 'COPY_NOT_CHECKED_OUT' unless ($copy->status == OILS_COPY_STATUS_CHECKED_OUT);
+    return $copy->{textcode} unless ( blessed $copy);
 
-    my $e = new_editor(authtoken=>$session{authtoken});
-    return $e->event->{textcode} unless ($e->checkauth);
+    return ("COPY_NOT_CHECKED_OUT $barcode")
+      unless ( $copy->status == OILS_COPY_STATUS_CHECKED_OUT );
 
-    my $circ = $e->search_action_circulation([ { target_copy => $copy->id, xact_finish => undef } ])->[0];
-    #return 'COPY_NOT_CHECKED_OUT' unless ($circ->circ_lib == $where->id);
-    return 'COPY_NOT_CHECKED_OUT' unless ($circ->circ_lib == 10);
+    my $e = new_editor( authtoken => $session{authtoken} );
+    return $e->event->{textcode} unless ( $e->checkauth );
 
-    my $r = OpenSRF::AppSession->create('open-ils.circ')
-        ->request('open-ils.circ.checkin', $session{authtoken}, { barcode => $barcode, void_overdues => 1 })
-        ->gather(1);
-    return 'SUCCESS' if ($r->{textcode} eq 'ROUTE_ITEM');
+    my $circ = $e->search_action_circulation(
+        [ { target_copy => $copy->id, xact_finish => undef } ] )->[0];
+    my $r =
+      OpenSRF::AppSession->create('open-ils.circ')
+      ->request( 'open-ils.circ.checkin.override',
+        $session{authtoken}, { force => 1, copy_id => $copy->id } )->gather(1);
+    return 'SUCCESS' if ( $r->{textcode} eq 'ROUTE_ITEM' );
     return $r->{textcode};
 }
 
@@ -1235,11 +1428,11 @@ sub user_id_from_barcode {
 
     my $response;
 
-    my $e = new_editor(authtoken=>$session{authtoken});
-    return $response unless ($e->checkauth);
+    my $e = new_editor( authtoken => $session{authtoken} );
+    return $response unless ( $e->checkauth );
 
-    my $card = $e->search_actor_card({barcode => $barcode, active => 't'});
-    return $e->event unless($card);
+    my $card = $e->search_actor_card( { barcode => $barcode, active => 't' } );
+    return $e->event unless ($card);
 
     $response = $card->[0]->usr if (@$card);
 
@@ -1248,7 +1441,7 @@ sub user_id_from_barcode {
     return $response;
 }
 
-# Place a hold for a patron.
+# Place a simple hold for a patron.
 #
 # Arguments
 # Target object appropriate for type of hold
@@ -1260,25 +1453,48 @@ sub user_id_from_barcode {
 # "HOLD_TYPE_NOT_SUPPORTED" if the hold type is not supported
 # (Currently only support 'T' and 'C')
 
+# simple hold should be removed and full holds sub should be used instead - pragmatic solution only
+
 sub place_simple_hold {
     check_session_time();
+
     #my ($type, $target, $patron, $pickup_ou) = @_;
-    my ($target, $patron) = @_;
-       # NOTE : switch "t" to an "f" to make inactive hold active
-       require '/usr/src/rel_2_1/Open-ILS/src/support-scripts/oils_header.pl';
-       use vars qw/ $apputils $memcache $user $authtoken $authtime /;
-       osrf_connect("/openils/conf/opensrf_core.xml");
-        oils_login("USERNAMEHERE", "PASSWORDHERE");
-       my $full_hold = '{"__c":"ahr","__p":[null,null,null,null,1,null,null,null,null,"T",null,null,"","3",null,"3",null,"'.$patron.'",1,"3","'.$target.'","'.$patron.'",null,null,null,null,null,null,"f",null]}';
-       my $f_hold_perl = OpenSRF::Utils::JSON->JSON2perl($full_hold);
-       my $resp = simplereq(CIRC(), 'open-ils.circ.holds.create', $authtoken, $f_hold_perl );
-       #oils_event_die($resp);
-       my $errors= "";
-       if (ref($resp) eq 'ARRAY' ) {
-                       ($errors .= "error : ".$_->{textcode}) for @$resp;
-                       return $errors;
-       }
-       elsif (ref($resp) ne 'HASH' )  { return "Hold placed! hold_id = ". $resp ."\n" }
+    my ( $target, $patron_id ) = @_;
+
+    # NOTE : switch "t" to an "f" to make inactive hold active
+    require '/openils/bin/oils_header.pl';    # XXX CUSTOMIZATION NEEDED XXX
+    use vars qw/ $apputils $memcache $user $authtoken $authtime /;
+
+ # XXX: local opensrf core conf filename should be in config.
+ # XXX: STAFF account with ncip service related permissions should be in config.
+    osrf_connect("/openils/conf/opensrf_core.xml");
+    oils_login( $conf->{auth}->{username}, $conf->{auth}->{password} );
+    my $ahr = Fieldmapper::action::hold_request->new();
+    $ahr->hold_type('C');
+    # The targeter doesn't like our special statuses, and changing the status after the targeter finishes is difficult because it runs asynchronously.  Our workaround is to create the hold frozen, unfreeze it, then run the targeter manually.
+    $ahr->target($target);
+    $ahr->usr($patron_id);
+    $ahr->requestor(1);     # XXX CUSTOMIZATION NEEDED XXX admin user (?)
+    $ahr->pickup_lib(2);    # XXX CUSTOMIZATION NEEDED XXX script user OU
+    $ahr->phone_notify('');
+    $ahr->email_notify(1);
+    $ahr->frozen('t');
+    my $resp = simplereq( CIRC(), 'open-ils.circ.holds.create', $authtoken, $ahr );
+    my $e = new_editor( xact => 1, authtoken => $session{authtoken} );
+    $ahr = $e->retrieve_action_hold_request($resp);    # refresh from db
+    $ahr->frozen('f');
+    $e->update_action_hold_request($ahr);
+    $e->commit;
+    $U->storagereq( 'open-ils.storage.action.hold_request.copy_targeter', undef, $ahr->id );
+
+    #oils_event_die($resp);
+    my $errors = "";
+    if ( ref($resp) eq 'ARRAY' ) {
+        ( $errors .= "error : " . $_->{textcode} ) for @$resp;
+        return $errors;
+    } elsif ( ref($resp) ne 'HASH' ) {
+        return "Hold placed! hold_id = " . $resp . "\n";
+    }
 }
 
 # Place a hold for a patron.
@@ -1294,72 +1510,88 @@ sub place_simple_hold {
 # textcode of a failed OSRF request
 # "HOLD_TYPE_NOT_SUPPORTED" if the hold type is not supported
 # (Currently only support 'T' and 'C')
-sub place_hold {
-    check_session_time();
-    my ($type, $target, $patron, $pickup_ou) = @_;
-
-    my $ou = org_unit_from_shortname($work_ou); # $work_ou is global
-    my $ahr = Fieldmapper::action::hold_request->new;
-    $ahr->hold_type($type);
-    if ($type eq 'C') {
-        # Check if we own the copy.
-        if ($ou->id == $target->circ_lib) {
-            # We own it, so let's place a copy hold.
-            $ahr->target($target->id);
-            $ahr->current_copy($target->id);
-        } else {
-            # We don't own it, so let's place a title hold instead.
-            my $bib = bre_from_barcode($target->barcode);
-            $ahr->target($bib->id);
-            $ahr->hold_type('T');
-        }
-    } elsif ($type eq 'T') {
-        $ahr->target($target);
-    } else {
-        return "HOLD_TYPE_NOT_SUPPORTED";
-    }
-    $ahr->usr($patron->id);
-    $ahr->pickup_lib($pickup_ou->id);
-    if (!$patron->email) {
-        $ahr->email_notify('f');
-        $ahr->phone_notify($patron->day_phone) if ($patron->day_phone);
-    } else {
-        $ahr->email_notify('t');
-    }
-
-    # We must have a title hold and we want to change the hold
-    # expiration date if we're sending the copy to the VC.
-    set_title_hold_expiration($ahr) if ($ahr->pickup_lib == $ou->id);
-
-    my $params = { pickup_lib => $ahr->pickup_lib, patronid => $ahr->usr, hold_type => $ahr->hold_type };
-
-    if ($ahr->hold_type eq 'C') {
-        $params->{copy_id} = $ahr->target;
-    } else {
-        $params->{titleid} = $ahr->target;
-    }
-
-    my $r = OpenSRF::AppSession->create('open-ils.circ')
-        ->request('open-ils.circ.title_hold.is_possible', $session{authtoken}, $params)
-            ->gather(1);
-
-    if ($r->{textcode}) {
-        return $r->{textcode};
-    } elsif ($r->{success}) {
-        $r = OpenSRF::AppSession->create('open-ils.circ')
-            ->request('open-ils.circ.holds.create.override', $session{authtoken}, $ahr)
-                ->gather(1);
-
-        my $returnValue = "SUCCESS";
-        if (ref($r) eq 'HASH') {
-            $returnValue = ($r->{textcode} eq 'PERM_FAILURE') ? $r->{ilsperm} : $r->{textcode};
-            $returnValue =~ s/\.override$// if ($r->{textcode} eq 'PERM_FAILURE');
-        }
-        return $returnValue;
-    } else {
-        return 'HOLD_NOT_POSSIBLE';
-    }
-}
+# XXX NOT USED OR WORKING, COMMENTING OUT FOR NOW
+#sub place_hold {
+#    check_session_time();
+#    my ( $type, $target, $patron, $pickup_ou ) = @_;
+#
+#    my $ou  = org_unit_from_shortname($work_ou);        # $work_ou is global
+#    my $ahr = Fieldmapper::action::hold_request->new;
+#    $ahr->hold_type($type);
+#    if ( $type eq 'C' ) {
+#
+#        # Check if we own the copy.
+#        if ( $ou->id == $target->circ_lib ) {
+#
+#            # We own it, so let's place a copy hold.
+#            $ahr->target( $target->id );
+#            $ahr->current_copy( $target->id );
+#        } else {
+#
+#            # We don't own it, so let's place a title hold instead.
+#            my $bib = bre_from_barcode( $target->barcode );
+#            $ahr->target( $bib->id );
+#            $ahr->hold_type('T');
+#        }
+#    } elsif ( $type eq 'T' ) {
+#        $ahr->target($target);
+#    } else {
+#        return "HOLD_TYPE_NOT_SUPPORTED";
+#    }
+#    $ahr->usr( user_id_from_barcode($id) );
+#
+#    #$ahr->pickup_lib($pickup_ou->id);
+#    $ahr->pickup_lib('3');
+#    if ( !$patron->email ) {
+#        $ahr->email_notify('f');
+#        $ahr->phone_notify( $patron->day_phone ) if ( $patron->day_phone );
+#    } else {
+#        $ahr->email_notify('t');
+#    }
+#
+#    # We must have a title hold and we want to change the hold
+#    # expiration date if we're sending the copy to the VC.
+#    set_title_hold_expiration($ahr) if ( $ahr->pickup_lib == $ou->id );
+#
+#    my $params = {
+#        pickup_lib => $ahr->pickup_lib,
+#        patronid   => $ahr->usr,
+#        hold_type  => $ahr->hold_type
+#    };
+#
+#    if ( $ahr->hold_type eq 'C' ) {
+#        $params->{copy_id} = $ahr->target;
+#    } else {
+#        $params->{titleid} = $ahr->target;
+#    }
+#
+#    my $r =
+#      OpenSRF::AppSession->create('open-ils.circ')
+#      ->request( 'open-ils.circ.title_hold.is_possible',
+#        $session{authtoken}, $params )->gather(1);
+#
+#    if ( $r->{textcode} ) {
+#        return $r->{textcode};
+#    } elsif ( $r->{success} ) {
+#        $r =
+#          OpenSRF::AppSession->create('open-ils.circ')
+#          ->request( 'open-ils.circ.holds.create.override',
+#            $session{authtoken}, $ahr )->gather(1);
+#
+#        my $returnValue = "SUCCESS";
+#        if ( ref($r) eq 'HASH' ) {
+#            $returnValue =
+#              ( $r->{textcode} eq 'PERM_FAILURE' )
+#              ? $r->{ilsperm}
+#              : $r->{textcode};
+#            $returnValue =~ s/\.override$//
+#              if ( $r->{textcode} eq 'PERM_FAILURE' );
+#        }
+#        return $returnValue;
+#    } else {
+#        return 'HOLD_NOT_POSSIBLE';
+#    }
+#}
 
 # Set the expiration date on title holds
 #
@@ -1368,14 +1600,15 @@ sub place_hold {
 #
 # Returns
 # Nothing
-sub set_title_hold_expiration {
-    my $hold = shift;
-    if ($title_holds->{unit} && $title_holds->{duration}) {
-        my $expiration = DateTime->now(time_zone => $tz);
-        $expiration->add($title_holds->{unit} => $title_holds->{duration});
-        $hold->expire_time($expiration->iso8601());
-    }
-}
+# XXX NOT USED OR WORKING, COMMENTING OUT FOR NOW
+#sub set_title_hold_expiration {
+#    my $hold = shift;
+#    if ( $title_holds->{unit} && $title_holds->{duration} ) {
+#        my $expiration = DateTime->now( time_zone => $tz );
+#        $expiration->add( $title_holds->{unit} => $title_holds->{duration} );
+#        $hold->expire_time( $expiration->iso8601() );
+#    }
+#}
 
 # Get actor.org_unit from the shortname
 #
@@ -1388,9 +1621,10 @@ sub set_title_hold_expiration {
 sub org_unit_from_shortname {
     check_session_time();
     my ($shortname) = @_;
-    my $ou = OpenSRF::AppSession->create('open-ils.actor')
-        ->request('open-ils.actor.org_unit.retrieve_by_shortname', $shortname)
-        ->gather(1);
+    my $ou =
+      OpenSRF::AppSession->create('open-ils.actor')
+      ->request( 'open-ils.actor.org_unit.retrieve_by_shortname', $shortname )
+      ->gather(1);
     return $ou;
 }
 
@@ -1404,9 +1638,11 @@ sub org_unit_from_shortname {
 sub flesh_user {
     check_session_time();
     my ($id) = @_;
-    my $response = OpenSRF::AppSession->create('open-ils.actor')
-        ->request('open-ils.actor.user.fleshed.retrieve', $session{'authtoken'}, $id,
-                   [ 'card', 'cards', 'standing_penalties', 'home_ou', 'profile' ])
-        ->gather(1);
+    my $response =
+      OpenSRF::AppSession->create('open-ils.actor')
+      ->request( 'open-ils.actor.user.fleshed.retrieve',
+        $session{'authtoken'}, $id,
+        [ 'card', 'cards', 'standing_penalties', 'home_ou', 'profile' ] )
+      ->gather(1);
     return $response;
 }