[open-ils-commits] [GIT] Evergreen ILS branch master updated. a1120eaed85ed29f055cd4612a3bd47166e7076a

Evergreen Git git at git.evergreen-ils.org
Wed Mar 2 01:02:44 EST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  a1120eaed85ed29f055cd4612a3bd47166e7076a (commit)
       via  712f588999162d8444d8a24cda7436702d50f107 (commit)
       via  6987fc32ef72a641d24922850e603b156ff06f64 (commit)
      from  8a5406b3d5651d6e837a0c27ed41457b8fe0492e (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a1120eaed85ed29f055cd4612a3bd47166e7076a
Author: Jake Litrell <jake at masslnc.org>
Date:   Tue Mar 1 17:22:28 2016 -0500

    LP#1312699: Minor modifications to patron checkout history deletions
    
    Minor modifications to make patron checkout history deletions work with
    the new table.  open-ils.actor.history.circ.clear
    extended to take an optional list of circ_ids, to limit what's deleted
    from the history.
    
    Signed-off-by: Jake Litrell <jake at masslnc.org>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
index 2bb874b..873ad3b 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
@@ -4217,6 +4217,7 @@ __PACKAGE__->register_method(
         desc   => 'Delete all user circ history entries for the calling user',
         params => [
             { desc => 'Authentication token',  type => 'string'},
+            { desc => "Options hash. 'circ_ids' is an arrayref of circulation IDs to delete", type => 'object' },
         ],
         return => {
             desc => q/1 on success, event on error/,
@@ -4278,8 +4279,12 @@ sub user_circ_history {
         $limits{limit} = $options->{limit} if defined $options->{limit};
     }
 
+    my $circ_id_list = $options->{circ_ids} ? $options->{circ_ids} : undef;
+
     my $circs = $e->search_action_user_circ_history([
-        {usr => $e->requestor->id},
+        {   usr => $e->requestor->id,
+            id  => {'in' => $circ_id_list},
+        },
         {   # order newest to oldest by default
             order_by => {auch => 'xact_start DESC'},
             %limits
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
index 9de2eec..945c9f2 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
@@ -1544,7 +1544,6 @@ sub handle_circ_renew {
     return @responses;
 }
 
-
 sub load_myopac_circs {
     my $self = shift;
     my $e = $self->editor;
@@ -1652,31 +1651,26 @@ sub fetch_user_circ_history {
 }
 
 sub handle_circ_update {
-    my $self = shift;
-    my $action = shift;
+    my $self     = shift;
+    my $action   = shift;
     my $circ_ids = shift;
-    my $e = $self->editor;
-    my $url;
 
-    my @circ_ids = ($circ_ids) ? @$circ_ids : $self->cgi->param('circ_id'); # for non-_all actions
+    my $circ_ids //= [$self->cgi->param('circ_id')];
 
-    my $cstore_ses = OpenSRF::AppSession->create('open-ils.cstore');
-    $cstore_ses->connect();
-    $cstore_ses->request('open-ils.cstore.transaction.begin')->gather(1);
+    if ($action =~ /delete/) {
+        my $options = {
+            circ_ids => $circ_ids,
+        };
 
-    if($action =~ /delete/) {
-        for my $circ_id (@circ_ids) {
-            my $circ = $cstore_ses->request(
-                'open-ils.cstore.direct.action.circulation.retrieve', $circ_id)->gather(1);
-            $circ->hide_from_usr_history(1);
-            my $resp = $cstore_ses->request(
-                'open-ils.cstore.direct.action.circulation.update', $circ)->gather(1);
-        }
+        $U->simplereq(
+            'open-ils.actor',
+            'open-ils.actor.history.circ.clear',
+            $self->editor->authtoken,
+            $options
+        );
     }
 
-    $cstore_ses->request('open-ils.cstore.transaction.commit')->gather(1);
-    $cstore_ses->disconnect();
-    return undef;
+    return;
 }
 
 # TODO: action.usr_visible_holds does not return cancelled holds.  Should it?
diff --git a/Open-ILS/src/templates/opac/myopac/circ_history.tt2 b/Open-ILS/src/templates/opac/myopac/circ_history.tt2
index abe007d..675dff9 100644
--- a/Open-ILS/src/templates/opac/myopac/circ_history.tt2
+++ b/Open-ILS/src/templates/opac/myopac/circ_history.tt2
@@ -193,12 +193,12 @@
                         </td>
                         <td>[% circ.circ.target_copy.barcode | html %]</td>
                         <td>[% circ.circ.target_copy.call_number.label | html %]</td>
-        </form>
                     </tr>
                 [% END %]
             </tbody>
         </table>
     </div>
+    </form>
     [% END %]
 </div>
 [% END %]

commit 712f588999162d8444d8a24cda7436702d50f107
Author: Jake Litrell <jake at masslnc.org>
Date:   Tue Mar 1 16:42:35 2016 -0500

    LP#1312699: Whitespace cleanup.
    
    Signed-off-by: Jake Litrell <jake at masslnc.org>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
index 80da51b..2bb874b 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
@@ -203,7 +203,7 @@ sub user_settings {
             $settings{$_} = get_setting($e, $user_id, $_) for @$setting;
             return \%settings;
         } else {
-            return get_setting($e, $user_id, $setting);    
+            return get_setting($e, $user_id, $setting);
         }
     } else {
         my $s = $e->search_actor_user_setting({usr => $user_id});
@@ -217,7 +217,7 @@ __PACKAGE__->register_method(
     api_name  => "open-ils.actor.org_unit_setting.values.ranged.retrieve",
     signature => {
         desc   => "Retrieves all org unit settings for the given org_id, up to whatever limit " .
-                  "is implied for retrieving OU settings by the authenticated users' permissions.",
+                "is implied for retrieving OU settings by the authenticated users' permissions.",
         params => [
             {desc => 'Authentication token',   type => 'string'},
             {desc => 'Org unit ID',            type => 'number'},
@@ -239,7 +239,7 @@ sub ranged_ou_settings {
     # start at the context org and capture the setting value
     # without clobbering settings we've already captured
     for my $this_org_id (@$org_list) {
-        
+
         my @sets = grep { $_->org_unit == $this_org_id } @$settings;
 
         for my $set (@sets) {
@@ -282,8 +282,8 @@ __PACKAGE__->register_method(
 );
 
 # ------------------------------------------------------------------
-# Attempts to find the org setting value for a given org.  if not 
-# found at the requested org, searches up the org tree until it 
+# Attempts to find the org setting value for a given org.  if not
+# found at the requested org, searches up the org tree until it
 # finds a parent that has the requested setting.
 # when found, returns { org => $id, value => $value }
 # otherwise, returns NULL
@@ -357,12 +357,12 @@ __PACKAGE__->register_method(
     signature => {
         desc   => q/
             Update an existing user, or create a new one.  Related objects,
-            like cards, addresses, survey responses, and stat cats, 
+            like cards, addresses, survey responses, and stat cats,
             can be updated by attaching them to the user object in their
             respective fields.  For examples, the billing address object
-            may be inserted into the 'billing_address' field, etc.  For each 
-            attached object, indicate if the object should be created, 
-            updated, or deleted using the built-in 'isnew', 'ischanged', 
+            may be inserted into the 'billing_address' field, etc.  For each
+            attached object, indicate if the object should be created,
+            updated, or deleted using the built-in 'isnew', 'ischanged',
             and 'isdeleted' fields on the object.
         /,
         params => [
@@ -379,7 +379,7 @@ sub update_patron {
     my $e = new_editor(xact => 1, authtoken => $auth);
     return $e->event unless $e->checkauth;
 
-    $logger->info($patron->isnew ? "Creating new patron..." : 
+    $logger->info($patron->isnew ? "Creating new patron..." :
         "Updating Patron: " . $patron->id);
 
     my $evt = check_group_perm($e, $e->requestor, $patron);
@@ -393,9 +393,9 @@ sub update_patron {
 
     # unflesh the real items on the patron
     $patron->card( $patron->card->id ) if(ref($patron->card));
-    $patron->billing_address( $patron->billing_address->id ) 
+    $patron->billing_address( $patron->billing_address->id )
         if(ref($patron->billing_address));
-    $patron->mailing_address( $patron->mailing_address->id ) 
+    $patron->mailing_address( $patron->mailing_address->id )
         if(ref($patron->mailing_address));
 
     # create/update the patron first so we can use his id
@@ -425,7 +425,7 @@ sub update_patron {
             my $perm = $U->is_true($old_patron->barred) ? 'UNBAR_PATRON' : 'BAR_PATRON';
             return $e->die_event unless $e->allowed($perm, $patron->home_ou);
 
-            $barred_hook = $U->is_true($new_patron->barred) ? 
+            $barred_hook = $U->is_true($new_patron->barred) ?
                 'au.barred' : 'au.unbarred';
         }
     }
@@ -461,13 +461,13 @@ sub update_patron {
 
     my $tses = OpenSRF::AppSession->create('open-ils.trigger');
     if($patron->isnew) {
-        $tses->request('open-ils.trigger.event.autocreate', 
+        $tses->request('open-ils.trigger.event.autocreate',
             'au.create', $new_patron, $new_patron->home_ou);
     } else {
-        $tses->request('open-ils.trigger.event.autocreate', 
+        $tses->request('open-ils.trigger.event.autocreate',
             'au.update', $new_patron, $new_patron->home_ou);
 
-        $tses->request('open-ils.trigger.event.autocreate', $barred_hook, 
+        $tses->request('open-ils.trigger.event.autocreate', $barred_hook,
             $new_patron, $new_patron->home_ou) if $barred_hook;
     }
 
@@ -482,9 +482,9 @@ sub apply_invalid_addr_penalty {
     # grab the invalid address penalty if set
     my $penalties = OpenILS::Utils::Penalty->retrieve_usr_penalties($e, $patron->id, $patron->home_ou);
 
-    my ($addr_penalty) = grep 
+    my ($addr_penalty) = grep
         { $_->standing_penalty->name eq 'INVALID_PATRON_ADDRESS' } @$penalties;
-    
+
     # do we enforce invalid address penalty
     my $enforce = $U->ou_ancestor_setting_value(
         $patron->home_ou, 'circ.patron_invalid_address_apply_penalty') || 0;
@@ -500,12 +500,12 @@ sub apply_invalid_addr_penalty {
         $e->commit;
 
     } elsif($enforce and $addr_count > 0 and !$addr_penalty) {
-        
+
         my $ptype = $e->retrieve_config_standing_penalty(29) or return $e->die_event;
         my $depth = $ptype->org_depth;
         my $ctx_org = $U->org_unit_ancestor_at_depth($patron->home_ou, $depth) if defined $depth;
         $ctx_org = $patron->home_ou unless defined $ctx_org;
-        
+
         my $penalty = Fieldmapper::actor::user_standing_penalty->new;
         $penalty->usr($patron->id);
         $penalty->org_unit($ctx_org);
@@ -571,7 +571,7 @@ sub _add_patron {
     my $e          = shift;
     my $patron      = shift;
 
-    return (undef, $e->die_event) unless 
+    return (undef, $e->die_event) unless
         $e->allowed('CREATE_USER', $patron->home_ou);
 
     my $ex = $e->search_actor_user(
@@ -592,14 +592,14 @@ sub check_group_perm {
     my( $e, $requestor, $patron ) = @_;
     my $evt;
 
-    # first let's see if the requestor has 
+    # first let's see if the requestor has
     # priveleges to update this user in any way
     if( ! $patron->isnew ) {
         my $p = $e->retrieve_actor_user($patron->id);
 
         # If we are the requestor (trying to update our own account)
         # and we are not trying to change our profile, we're good
-        if( $p->id == $requestor->id and 
+        if( $p->id == $requestor->id and
                 $p->profile == $patron->profile ) {
             return undef;
         }
@@ -609,7 +609,7 @@ sub check_group_perm {
         return $evt if $evt;
     }
 
-    # They are allowed to edit this patron.. can they put the 
+    # They are allowed to edit this patron.. can they put the
     # patron into the group requested?
     $evt = group_perm_failed($e, $requestor, $patron);
     return $evt if $evt;
@@ -689,11 +689,11 @@ sub _check_dup_ident {
     return undef unless $patron->ident_value;
 
     my $search = {
-        ident_type  => $patron->ident_type, 
+        ident_type  => $patron->ident_type,
         ident_value => $patron->ident_value,
     };
 
-    $logger->debug("patron update searching for dup ident values: " . 
+    $logger->debug("patron update searching for dup ident values: " .
         $patron->ident_type . ':' . $patron->ident_value);
 
     $search->{id} = {'!=' => $patron->id} if $patron->id and $patron->id > 0;
@@ -732,7 +732,7 @@ sub _add_update_addresses {
             $new_patron->billing_address($address->id());
             $new_patron->ischanged(1);
         }
-    
+
         if( $patron->mailing_address() and
             $patron->mailing_address() == $current_id ) {
             $new_patron->mailing_address($address->id());
@@ -749,7 +749,7 @@ sub _add_update_addresses {
             return (undef, $evt) if $evt;
 
             # we need to get the new id
-            if( $patron->billing_address() and 
+            if( $patron->billing_address() and
                     $patron->billing_address() == $current_id ) {
                 $new_patron->billing_address($address->id());
                 $logger->info("setting billing addr to $current_id");
@@ -784,7 +784,7 @@ sub _add_update_addresses {
 
             $evt = _delete_address($e, $address);
             return (undef, $evt) if $evt;
-        } 
+        }
     }
 
     return ( $new_patron, undef );
@@ -901,7 +901,7 @@ sub _add_survey_responses {
 
         $_->usr($new_patron->id) for (@$responses);
 
-        my $evt = $U->simplereq( "open-ils.circ", 
+        my $evt = $U->simplereq( "open-ils.circ",
             "open-ils.circ.survey.submit.user_id", $responses );
 
         return (undef, $evt) if defined($U->event_code($evt));
@@ -939,7 +939,7 @@ sub _clear_badcontact_penalties {
     my @penalties_to_clear;
     my ($field, $penalty_name);
 
-    # For each field that might have an associated bad contact penalty, 
+    # For each field that might have an associated bad contact penalty,
     # check for such penalties and add them to the to-clear list if that
     # field has changed.
     while (($field, $penalty_name) = each(%$PNM)) {
@@ -1143,7 +1143,7 @@ sub get_user_by_id {
     my $e = new_editor(authtoken=>$auth);
     return $e->event unless $e->checkauth;
     my $user = $e->retrieve_actor_user($id) or return $e->event;
-    return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);   
+    return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
     return $user;
 }
 
@@ -1164,7 +1164,7 @@ __PACKAGE__->register_method(
 my $ident_types;
 sub get_user_ident_types {
     return $ident_types if $ident_types;
-    return $ident_types = 
+    return $ident_types =
         new_editor()->retrieve_all_config_identification_type();
 }
 
@@ -1197,7 +1197,7 @@ sub search_org_unit {
 
     my $list = OpenILS::Application::AppUtils->simple_scalar_request(
         "open-ils.cstore",
-        "open-ils.cstore.direct.actor.org_unit.search.atomic", 
+        "open-ils.cstore.direct.actor.org_unit.search.atomic",
         { $field => $value } );
 
     return $list;
@@ -1209,7 +1209,7 @@ sub search_org_unit {
 __PACKAGE__->register_method(
     method  => "get_org_tree",
     api_name    => "open-ils.actor.org_tree.retrieve",
-    argc        => 0, 
+    argc        => 0,
     note        => "Returns the entire org tree structure",
 );
 
@@ -1234,7 +1234,7 @@ sub get_org_descendants {
         my @trees;
         for my $i (0..scalar(@$org_unit)-1) {
             my $list = $U->simple_scalar_request(
-                "open-ils.storage", 
+                "open-ils.storage",
                 "open-ils.storage.actor.org_unit.descendants.atomic",
                 $org_unit->[$i], $depth->[$i] );
             push(@trees, $U->build_org_tree($list));
@@ -1243,7 +1243,7 @@ sub get_org_descendants {
 
     } else {
         my $orglist = $apputils->simple_scalar_request(
-                "open-ils.storage", 
+                "open-ils.storage",
                 "open-ils.storage.actor.org_unit.descendants.atomic",
                 $org_unit, $depth );
         return $U->build_org_tree($orglist);
@@ -1260,7 +1260,7 @@ __PACKAGE__->register_method(
 sub get_org_ancestors {
     my( $self, $client, $org_unit, $depth ) = @_;
     my $orglist = $apputils->simple_scalar_request(
-            "open-ils.storage", 
+            "open-ils.storage",
             "open-ils.storage.actor.org_unit.ancestors.atomic",
             $org_unit, $depth );
     return $U->build_org_tree($orglist);
@@ -1275,7 +1275,7 @@ __PACKAGE__->register_method(
 my $user_standings;
 sub get_standings {
     return $user_standings if $user_standings;
-    return $user_standings = 
+    return $user_standings =
         $apputils->simple_scalar_request(
             "open-ils.cstore",
             "open-ils.cstore.direct.config.standing.search.atomic",
@@ -1316,7 +1316,7 @@ __PACKAGE__->register_method(
     # seeing results fairly quickly
     max_chunk_size => 4096, # bundling
 
-    # api_level => 2, 
+    # api_level => 2,
     # pending opensrf work -- also, not sure if needed since we're not
     # actaully creating an alternate vesrion, only offering to return a
     # different format.
@@ -1328,7 +1328,7 @@ __PACKAGE__->register_method(
 );
 
 sub patron_adv_search {
-    my( $self, $client, $auth, $search_hash, $search_limit, 
+    my( $self, $client, $auth, $search_hash, $search_limit,
         $search_sort, $include_inactive, $search_ou, $flesh_fields, $offset) = @_;
 
     # API params sanity checks.
@@ -1366,8 +1366,8 @@ sub patron_adv_search {
     }
 
     my $ids = $U->storagereq(
-        "open-ils.storage.actor.user.crazy_search", $search_hash, 
-        $search_limit, $search_sort, $include_inactive, 
+        "open-ils.storage.actor.user.crazy_search", $search_hash,
+        $search_limit, $search_sort, $include_inactive,
         $e->requestor->ws_ou, $search_ou, $opt_boundary, $offset);
 
     return $ids unless $self->api_name =~ /fleshed/;
@@ -1405,7 +1405,7 @@ __PACKAGE__->register_method(
     method    => "update_passwd",
     api_name  => "open-ils.actor.user.password.update",
     signature => {
-        desc   => "Update the operator's password", 
+        desc   => "Update the operator's password",
         params => [
             { desc => 'Authentication token', type => 'string' },
             { desc => 'New password',         type => 'string' },
@@ -1419,7 +1419,7 @@ __PACKAGE__->register_method(
     method    => "update_passwd",
     api_name  => "open-ils.actor.user.username.update",
     signature => {
-        desc   => "Update the operator's username", 
+        desc   => "Update the operator's username",
         params => [
             { desc => 'Authentication token', type => 'string' },
             { desc => 'New username',         type => 'string' },
@@ -1433,7 +1433,7 @@ __PACKAGE__->register_method(
     method    => "update_passwd",
     api_name  => "open-ils.actor.user.email.update",
     signature => {
-        desc   => "Update the operator's email address", 
+        desc   => "Update the operator's email address",
         params => [
             { desc => 'Authentication token', type => 'string' },
             { desc => 'New email address',    type => 'string' },
@@ -1473,7 +1473,7 @@ sub update_passwd {
         if( $api =~ /username/o ) {
 
             # make sure no one else has this username
-            my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1}); 
+            my $exist = $e->search_actor_user({usrname=>$new_val},{idlist=>1});
             if (@$exist) {
                 $e->rollback;
                 return new OpenILS::Event('USERNAME_EXISTS');
@@ -1601,7 +1601,7 @@ __PACKAGE__->register_method(
     authoritative => 1,
     signature => {
         desc => q/
-            Returns a set of org unit IDs which represent the highest orgs in 
+            Returns a set of org unit IDs which represent the highest orgs in
             the org tree where the user has the requested permission.  The
             purpose of this method is to return the smallest set of org units
             which represent the full expanse of the user's ability to perform
@@ -1610,7 +1610,7 @@ __PACKAGE__->register_method(
         params => [
             {desc => 'authtoken', type => 'string'},
             {desc => 'permission name', type => 'string'},
-            {desc => q/user id, optional.  If present, check perms for 
+            {desc => q/user id, optional.  If present, check perms for
                 this user instead of the logged in user/, type => 'number'},
         ],
         return => {desc => 'An array of org IDs'}
@@ -1658,15 +1658,15 @@ __PACKAGE__->register_method(
         'VIEW_PERMISSION' rights at the home org unit of the target user
         @param authtoken The login session key
         @param userid The id of the user in question
-        @param perms An array of perm names to check 
-        @return An array of orgId's  representing the org unit 
+        @param perms An array of perm names to check
+        @return An array of orgId's  representing the org unit
         highest in the org tree within which the user has the requested permission
         The arrah of orgId's has matches the order of the perms array
     /);
 
 sub check_user_perms4 {
     my( $self, $client, $authtoken, $userid, $perms ) = @_;
-    
+
     my( $staff, $target, $org, $evt );
 
     ( $staff, $target, $evt ) = $apputils->checkses_requestor(
@@ -1690,7 +1690,7 @@ __PACKAGE__->register_method(
     authoritative => 1,
     signature     => {
         desc   => 'Returns a short summary of the users total open fines, '  .
-                  'excluding voided fines Params are login_session, user_id' ,
+                'excluding voided fines Params are login_session, user_id' ,
         params => [
             {desc => 'Authentication token', type => 'string'},
             {desc => 'User ID',              type => 'string'}  # number?
@@ -1709,7 +1709,7 @@ sub user_fines_summary {
 
     if( $user_id ne $e->requestor->id ) {
         my $user = $e->retrieve_actor_user($user_id) or return $e->event;
-        return $e->event unless 
+        return $e->event unless
             $e->allowed('VIEW_USER_FINES_SUMMARY', $user->home_ou);
     }
 
@@ -1724,8 +1724,8 @@ __PACKAGE__->register_method(
     authoritative => 1,
     signature     => {
         desc   => 'Returns a short summary of the users vital stats, including '  .
-                  'identification information, accumulated balance, number of holds, ' .
-                  'and current open circulation stats' ,
+                'identification information, accumulated balance, number of holds, ' .
+                'and current open circulation stats' ,
         params => [
             {desc => 'Authentication token',                          type => 'string'},
             {desc => 'Optional User ID, for use in the staff client', type => 'number'}  # number?
@@ -1820,7 +1820,7 @@ foreach (keys %methods) {
             params => $common_params,
             return => {
                 desc => "List of objects, or event on error.  Each object is a hash containing: transaction, circ, record. "
-                      . 'These represent the relevant (mbts) transaction, attached circulation and title pointed to in the circ, respectively.',
+                    . 'These represent the relevant (mbts) transaction, attached circulation and title pointed to in the circ, respectively.',
             }
         }
     );
@@ -1873,7 +1873,7 @@ sub user_transactions {
 
     my $user = $e->retrieve_actor_user($user_id) or return $e->event;
 
-    return $e->event unless 
+    return $e->event unless
         $e->requestor->id == $user_id or
         $e->allowed('VIEW_USER_TRANSACTIONS', $user->home_ou);
 
@@ -1887,7 +1887,7 @@ sub user_transactions {
     $method = "$method.authoritative" if $api =~ /authoritative/;
     my ($trans) = $self->method_lookup($method)->run($auth, $user_id, $type, $filter, $options);
 
-    if($api =~ /total/o) { 
+    if($api =~ /total/o) {
         my $total = 0.0;
         $total += $_->balance_owed for @$trans;
         return $total;
@@ -1898,7 +1898,7 @@ sub user_transactions {
 
     my @resp;
     for my $t (@$trans) {
-            
+
         if( $t->xact_type ne 'circulation' ) {
             push @resp, {transaction => $t};
             next;
@@ -1908,8 +1908,8 @@ sub user_transactions {
         push @resp, {transaction => $t, %$circ_data};
     }
 
-    return \@resp; 
-} 
+    return \@resp;
+}
 
 
 __PACKAGE__->register_method(
@@ -1993,13 +1993,13 @@ __PACKAGE__->register_method(
     argc          => 1,
     notes         => q/
         Returns hold ready vs. total counts.
-        If a context org unit is provided, a third value 
+        If a context org unit is provided, a third value
         is returned with key 'behind_desk', which reports
-        how many holds are ready at the pickup library 
+        how many holds are ready at the pickup library
         with the behind_desk flag set to true.
     /
 );
-    
+
 sub hold_request_count {
     my( $self, $client, $authtoken, $user_id, $ctx_org ) = @_;
     my $e = new_editor(authtoken => $authtoken);
@@ -2022,13 +2022,13 @@ sub hold_request_count {
         }
     });
 
-    my @ready = grep { 
+    my @ready = grep {
         $_->{current_shelf_lib} and # avoid undef warnings
-        $_->{pickup_lib} eq $_->{current_shelf_lib} 
+        $_->{pickup_lib} eq $_->{current_shelf_lib}
     } @$holds;
 
-	my $resp = { 
-        total => scalar(@$holds), 
+    my $resp = {
+        total => scalar(@$holds),
         ready => scalar(@ready)
     };
 
@@ -2052,16 +2052,16 @@ __PACKAGE__->register_method(
     argc          => 2,
     signature     => {
         desc => "For a given user, returns a structure of circulations objects sorted by out, overdue, lost, claims_returned, long_overdue. "
-              . "A list of IDs are returned of each type.  Circs marked lost, long_overdue, and claims_returned will not be 'finished' "
-              . "(i.e., outstanding balance or some other pending action on the circ). "
-              . "The .count method also includes a 'total' field which sums all open circs.",
+            . "A list of IDs are returned of each type.  Circs marked lost, long_overdue, and claims_returned will not be 'finished' "
+            . "(i.e., outstanding balance or some other pending action on the circ). "
+            . "The .count method also includes a 'total' field which sums all open circs.",
         params => [
             { desc => 'Authentication Token', type => 'string'},
             { desc => 'User ID',              type => 'string'},
         ],
         return => {
             desc => 'Returns event on error, or an object with ID lists, like: '
-                  . '{"out":[12552,451232], "claims_returned":[], "long_overdue":[23421] "overdue":[], "lost":[]}'
+                . '{"out":[12552,451232], "claims_returned":[], "long_overdue":[23421] "overdue":[], "lost":[]}'
         },
     }
 );
@@ -2159,7 +2159,7 @@ sub checked_in_with_fines {
     # money is owed on these items and they are checked in
     my $open = $e->search_action_circulation(
         {
-            usr             => $userid, 
+            usr             => $userid,
             xact_finish     => undef,
             checkin_time    => { "!=" => undef },
         }
@@ -2191,9 +2191,9 @@ sub _sigmaker {
         api_name  => "open-ils.actor.user.transactions.$api",
         signature => {
             desc   => "For a given User ID, returns a list of billable transaction" .
-                      ($ids ? " id" : '') .
-                      "s$desc, optionally filtered by type and/or fields in money.billable_xact_summary.  " .
-                      "The VIEW_USER_TRANSACTIONS permission is required to view another user's transactions",
+                    ($ids ? " id" : '') .
+                    "s$desc, optionally filtered by type and/or fields in money.billable_xact_summary.  " .
+                    "The VIEW_USER_TRANSACTIONS permission is required to view another user's transactions",
             params => [
                 {desc => 'Authentication token',        type => 'string'},
                 {desc => 'User ID',                     type => 'number'},
@@ -2274,8 +2274,8 @@ sub user_transaction_history {
     }
 
     my $options_clause = { order_by => { mbt => 'xact_start DESC' } };
-    $options_clause->{'limit'} = $options->{'limit'} if $options->{'limit'}; 
-    $options_clause->{'offset'} = $options->{'offset'} if $options->{'offset'}; 
+    $options_clause->{'limit'} = $options->{'limit'} if $options->{'limit'};
+    $options_clause->{'offset'} = $options->{'offset'} if $options->{'offset'};
 
     my $mbts = $e->search_money_billable_transaction_summary(
         [   { usr => $userid, @xact_finish, %$filter },
@@ -2288,7 +2288,7 @@ sub user_transaction_history {
 
     my @resp;
     for my $t (@$mbts) {
-            
+
         if( $t->xact_type ne 'circulation' ) {
             push @resp, {transaction => $t};
             next;
@@ -2298,7 +2298,7 @@ sub user_transaction_history {
         push @resp, {transaction => $t, %$circ_data};
     }
 
-    return \@resp; 
+    return \@resp;
 }
 
 
@@ -2309,7 +2309,7 @@ __PACKAGE__->register_method(
     argc     => 1,
     notes    => "Returns a list of permissions"
 );
-    
+
 sub user_perms {
     my( $self, $client, $authtoken, $user ) = @_;
 
@@ -2373,15 +2373,15 @@ __PACKAGE__->register_method(
     api_name => "open-ils.actor.groups.tree.retrieve",
     notes    => "Returns a list of user groups"
 );
-    
+
 sub retrieve_groups_tree {
     my( $self, $client ) = @_;
     return new_editor()->search_permission_grp_tree(
         [
             { parent => undef},
-            {   
+            {
                 flesh               => -1,
-                flesh_fields    => { pgt => ["children"] }, 
+                flesh_fields    => { pgt => ["children"] },
                 order_by            => { pgt => 'name'}
             }
         ]
@@ -2394,7 +2394,7 @@ __PACKAGE__->register_method(
     api_name => "open-ils.actor.user.set_groups",
     notes    => "Adds a user to one or more permission groups"
 );
-    
+
 sub add_user_to_groups {
     my( $self, $client, $authtoken, $userid, $groups ) = @_;
 
@@ -2409,7 +2409,7 @@ sub add_user_to_groups {
     $apputils->simplereq(
         'open-ils.storage',
         'open-ils.storage.direct.permission.usr_grp_map.mass_delete', { usr => $userid } );
-        
+
     for my $group (@$groups) {
         my $link = Fieldmapper::permission::usr_grp_map->new;
         $link->grp($group);
@@ -2440,7 +2440,7 @@ sub get_user_perm_groups {
     return $apputils->simplereq(
         'open-ils.cstore',
         'open-ils.cstore.direct.permission.usr_grp_map.search.atomic', { usr => $userid } );
-}   
+}
 
 
 __PACKAGE__->register_method(
@@ -2472,7 +2472,7 @@ sub get_user_work_ous {
 
     # client just wants a list of org IDs
     return $U->get_user_work_ou_ids($e, $userid);
-}   
+}
 
 
 
@@ -2507,17 +2507,17 @@ sub register_workstation {
     if( $existing ) {
 
         if( $self->api_name =~ /override/o && ($oargs->{all} || grep { $_ eq 'WORKSTATION_NAME_EXISTS' } @{$oargs->{events}}) ) {
-            # workstation with the given name exists.  
+            # workstation with the given name exists.
 
             if($owner ne $existing->owning_lib) {
                 # if necessary, update the owning_lib of the workstation
 
                 $logger->info("changing owning lib of workstation ".$existing->id.
                     " from ".$existing->owning_lib." to $owner");
-                return $e->die_event unless 
-                    $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib); 
+                return $e->die_event unless
+                    $e->allowed('UPDATE_WORKSTATION', $existing->owning_lib);
 
-                return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner); 
+                return $e->die_event unless $e->allowed('UPDATE_WORKSTATION', $owner);
 
                 $existing->owning_lib($owner);
                 return $e->die_event unless $e->update_actor_workstation($existing);
@@ -2525,7 +2525,7 @@ sub register_workstation {
                 $e->commit;
 
             } else {
-                $logger->info(  
+                $logger->info(
                     "attempt to register an existing workstation.  returning existing ID");
             }
 
@@ -2562,7 +2562,7 @@ sub workstation_list {
     my %results;
 
     for my $o (@orgs) {
-        return $e->event 
+        return $e->event
             unless $e->allowed('REGISTER_WORKSTATION', $o);
         $results{$o} = $e->search_actor_workstation({owning_lib=>$o});
     }
@@ -2601,7 +2601,7 @@ sub fetch_patron_note {
             return $evt if $evt;
         }
         return $U->cstorereq(
-            'open-ils.cstore.direct.actor.usr_note.search.atomic', 
+            'open-ils.cstore.direct.actor.usr_note.search.atomic',
             { usr => $patronid, pub => 't' } );
     }
 
@@ -2629,7 +2629,7 @@ sub create_user_note {
     my $user = $e->retrieve_actor_user($note->usr)
         or return $e->die_event;
 
-    return $e->die_event unless 
+    return $e->die_event unless
         $e->allowed('UPDATE_USER',$user->home_ou);
 
     $note->creator($e->requestor->id);
@@ -2657,9 +2657,9 @@ sub delete_user_note {
         or return $e->die_event;
     my $user = $e->retrieve_actor_user($note->usr)
         or return $e->die_event;
-    return $e->die_event unless 
+    return $e->die_event unless
         $e->allowed('UPDATE_USER', $user->home_ou);
-    
+
     $e->delete_actor_usr_note($note) or return $e->die_event;
     $e->commit;
     return 1;
@@ -2681,7 +2681,7 @@ sub update_user_note {
     return $e->die_event unless $e->checkauth;
     my $patron = $e->retrieve_actor_user($note->usr)
         or return $e->die_event;
-    return $e->die_event unless 
+    return $e->die_event unless
         $e->allowed('UPDATE_USER', $patron->home_ou);
     $e->update_actor_user_note($note)
         or return $e->die_event;
@@ -2834,8 +2834,8 @@ sub session_safe_token {
 
     # add more user fields as needed
     $cache->put_cache(
-        "safe-token-user-$safe_token", {   
-            id => $e->requestor->id, 
+        "safe-token-user-$safe_token", {
+            id => $e->requestor->id,
             home_ou_shortname => $e->retrieve_actor_org_unit(
                 $e->requestor->home_ou)->shortname,
         },
@@ -2903,8 +2903,8 @@ sub apply_penalty {
     return $e->die_event unless $e->allowed('UPDATE_USER', $user->home_ou);
 
     my $ptype = $e->retrieve_config_standing_penalty($penalty->standing_penalty) or return $e->die_event;
-    
-    my $ctx_org = 
+
+    my $ctx_org =
         (defined $ptype->org_depth) ?
         $U->org_unit_ancestor_at_depth($penalty->org_unit, $ptype->org_depth) :
         $penalty->org_unit;
@@ -3041,13 +3041,13 @@ sub new_flesh_user {
         $user->addresses([]) unless @{$user->addresses};
         # don't expose "replaced" addresses by default
         $user->addresses([grep {$_->id >= 0} @{$user->addresses}]);
-    
+
         if( ref $user->billing_address ) {
             unless( grep { $user->billing_address->id == $_->id } @{$user->addresses} ) {
                 push( @{$user->addresses}, $user->billing_address );
             }
         }
-    
+
         if( ref $user->mailing_address ) {
             unless( grep { $user->mailing_address->id == $_->id } @{$user->addresses} ) {
                 push( @{$user->addresses}, $user->mailing_address );
@@ -3059,7 +3059,7 @@ sub new_flesh_user {
         # grab the user penalties ranged for this location
         $user->standing_penalties(
             $e->search_actor_user_standing_penalty([
-                {   usr => $id, 
+                {   usr => $id,
                     '-or' => [
                         {stop_date => undef},
                         {stop_date => {'>' => 'now'}}
@@ -3078,21 +3078,21 @@ sub new_flesh_user {
 
         # max number to return for simple patron fleshing
         my $limit = $U->ou_ancestor_setting_value(
-            $e->requestor->ws_ou, 
+            $e->requestor->ws_ou,
             'circ.patron.usr_activity_retrieve.max');
 
         my $opts = {
             flesh => 1,
             flesh_fields => {auact => ['etype']},
-            order_by => {auact => 'event_time DESC'}, 
+            order_by => {auact => 'event_time DESC'},
         };
 
         # 0 == none, <0 == return all
         $limit = 1 unless defined $limit;
         $opts->{limit} = $limit if $limit > 0;
 
-        $user->usr_activity( 
-            ($limit == 0) ? 
+        $user->usr_activity(
+            ($limit == 0) ?
                 [] : # skip the DB call
                 $e->search_actor_usr_activity([{usr => $user->id}, $opts])
         );
@@ -3136,10 +3136,10 @@ __PACKAGE__->register_method(
 sub user_opt_in_enabled {
     my($self, $conn) = @_;
     my $sc = OpenSRF::Utils::SettingsClient->new;
-    return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true'; 
+    return 1 if lc($sc->config_value(share => user => 'opt_in')) eq 'true';
     return 0;
 }
-    
+
 
 __PACKAGE__->register_method(
     method    => 'user_opt_in_at_org',
@@ -3168,7 +3168,7 @@ sub user_opt_in_at_org {
 
     # get the boundary setting
     my $opt_boundary = $U->ou_ancestor_setting_value($e->requestor->ws_ou,'org.patron_opt_boundary');
- 
+
     # auto opt in if user falls within the opt boundary
     my $opt_orgs = $U->get_org_descendants($ws_org, $opt_boundary);
 
@@ -3195,17 +3195,17 @@ sub create_user_opt_in_at_org {
 
     my $e = new_editor(authtoken => $auth, xact=>1);
     return $e->die_event unless $e->checkauth;
-   
+
     # if a specific org unit wasn't passed in, get one based on the defaults;
     if(!$org_id){
         my $wsou = $e->requestor->ws_ou;
         # get the default opt depth
-        my $opt_depth = $U->ou_ancestor_setting_value($wsou,'org.patron_opt_default'); 
+        my $opt_depth = $U->ou_ancestor_setting_value($wsou,'org.patron_opt_default');
         # get the org unit at that depth
-        my $org = $e->json_query({ 
+        my $org = $e->json_query({
             from => [ 'actor.org_unit_ancestor_at_depth', $wsou, $opt_depth ]})->[0];
         $org_id = $org->{id};
-    } 
+    }
     if (!$org_id) {
         # fall back to the workstation OU, the pre-opt-in-boundary way
         $org_id = $e->requestor->ws_ou;
@@ -3254,7 +3254,7 @@ __PACKAGE__->register_method (
     method      => 'verify_user_password',
     api_name    => 'open-ils.actor.verify_user_password',
     signature   => q/
-        Given a barcode or username and the MD5 encoded password, 
+        Given a barcode or username and the MD5 encoded password,
         returns 1 if the password is correct.  Returns 0 otherwise.
     /
 );
@@ -3278,7 +3278,7 @@ sub verify_user_password {
         $user = $user_by_username;
     }
     return 0 if (!$user);
-    return 0 if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id); 
+    return 0 if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
     return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
     return $U->verify_migrated_user_password(
         $e, $user_by_username->id, $password, 1);
@@ -3327,7 +3327,7 @@ sub retrieve_usr_id_via_barcode_or_usrname {
         $user = $user_by_username;
     }
     return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if (!$user);
-    return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id); 
+    return OpenILS::Event->new( 'ACTOR_USER_NOT_FOUND' ) if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
     return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
     return $user->id;
 }
@@ -3339,7 +3339,7 @@ __PACKAGE__->register_method (
     signature   => {
         desc => q/
             Given a list of source users and destination user, transfer all data from the source
-            to the dest user and delete the source user.  All user related data is 
+            to the dest user and delete the source user.  All user related data is
             transferred, including circulations, holds, bookbags, etc.
         /
     }
@@ -3370,10 +3370,10 @@ sub merge_users {
             return $e->die_event unless $e->allowed('MERGE_USERS', $master_user->home_ou);
         }
 
-        return $e->die_event unless 
+        return $e->die_event unless
             $e->json_query({from => [
-                'actor.usr_merge', 
-                $src_id, 
+                'actor.usr_merge',
+                $src_id,
                 $master_id,
                 $del_addrs,
                 $del_cards,
@@ -3400,7 +3400,7 @@ sub approve_user_address {
     my $e = new_editor(xact => 1, authtoken => $auth);
     return $e->die_event unless $e->checkauth;
     if(ref $addr) {
-        # if the caller passes an address object, assume they want to 
+        # if the caller passes an address object, assume they want to
         # update it first before approving it
         $e->update_actor_user_address($addr) or return $e->die_event;
     } else {
@@ -3411,7 +3411,7 @@ sub approve_user_address {
     my $result = $e->json_query({from => ['actor.approve_pending_address', $addr->id]})->[0]
         or return $e->die_event;
     $e->commit;
-    return [values %$result]->[0]; 
+    return [values %$result]->[0];
 }
 
 
@@ -3438,7 +3438,7 @@ sub retrieve_friends {
         return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
     }
 
-    return OpenILS::Application::Actor::Friends->retrieve_friends(  
+    return OpenILS::Application::Actor::Friends->retrieve_friends(
         $e, $user_id, $options);
 }
 
@@ -3463,7 +3463,7 @@ sub apply_friend_perms {
     }
 
     for my $perm (@perms) {
-        my $evt = 
+        my $evt =
             OpenILS::Application::Actor::Friends->apply_friend_perm(
                 $e, $user_id, $delegate_id, $perm);
         return $evt if $evt;
@@ -3522,7 +3522,7 @@ sub user_events {
     my $user_field = 'usr';
 
     $filters ||= {};
-    $filters->{target} = { 
+    $filters->{target} = {
         select => { $obj_type => ['id'] },
         from => $obj_type,
         where => {usr => $user_id}
@@ -3534,7 +3534,7 @@ sub user_events {
     }
 
     my $ses = OpenSRF::AppSession->create('open-ils.trigger');
-    my $req = $ses->request('open-ils.trigger.events_by_target', 
+    my $req = $ses->request('open-ils.trigger.events_by_target',
         $obj_type, $filters, {atevdef => ['reactor', 'validator']}, 2);
 
     while(my $resp = $req->recv) {
@@ -3579,7 +3579,7 @@ sub copy_events {
     $copy_field = 'current_copy' if $obj_type eq 'ahr';
 
     $filters ||= {};
-    $filters->{target} = { 
+    $filters->{target} = {
         select => { $obj_type => ['id'] },
         from => $obj_type,
         where => {$copy_field => $copy_id}
@@ -3587,13 +3587,13 @@ sub copy_events {
 
 
     my $ses = OpenSRF::AppSession->create('open-ils.trigger');
-    my $req = $ses->request('open-ils.trigger.events_by_target', 
+    my $req = $ses->request('open-ils.trigger.events_by_target',
         $obj_type, $filters, {atevdef => ['reactor', 'validator']}, 2);
 
     while(my $resp = $req->recv) {
         my $val = $resp->content;
         my $tgt = $val->target;
-        
+
         my $user = $e->retrieve_actor_user($tgt->usr);
         if($e->requestor->id != $user->id) {
             return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
@@ -3677,7 +3677,7 @@ __PACKAGE__->register_method (
     method      => 'really_delete_user',
     api_name    => 'open-ils.actor.user.delete',
     signature   => q/
-        It anonymizes all personally identifiable information in actor.usr. By calling actor.usr_purge_data() 
+        It anonymizes all personally identifiable information in actor.usr. By calling actor.usr_purge_data()
         it also purges related data from other tables, sometimes by transferring it to a designated destination user.
         The usrname field (along with first_given_name and family_name) is updated to id '-PURGED-' now().
         dest_usr_id is only required when deleting a user that performs staff functions.
@@ -3742,26 +3742,26 @@ sub user_payments {
     return $e->die_event unless $e->checkauth;
 
     my $user = $e->retrieve_actor_user($user_id) or return $e->event;
-    return $e->event unless 
+    return $e->event unless
         $e->requestor->id == $user_id or
         $e->allowed('VIEW_USER_TRANSACTIONS', $user->home_ou);
 
     # Find all payments for all transactions for user $user_id
     my $query = {
-        select => {mp => ['id']}, 
-        from => 'mp', 
+        select => {mp => ['id']},
+        from => 'mp',
         where => {
             xact => {
                 in => {
-                    select => {mbt => ['id']}, 
-                    from => 'mbt', 
+                    select => {mbt => ['id']},
+                    from => 'mbt',
                     where => {usr => $user_id}
-                }   
+                }
             }
         },
         order_by => [
             { # by default, order newest payments first
-                class => 'mp', 
+                class => 'mp',
                 field => 'payment_ts',
                 direction => 'desc'
             }, {
@@ -3780,7 +3780,7 @@ sub user_payments {
     if(defined $filters->{where}) {
         foreach (keys %{$filters->{where}}) {
             # don't allow the caller to expand the result set to other users
-            $query->{where}->{$_} = $filters->{where}->{$_} unless $_ eq 'xact'; 
+            $query->{where}->{$_} = $filters->{where}->{$_} unless $_ eq 'xact';
         }
     }
 
@@ -3826,7 +3826,7 @@ __PACKAGE__->register_method (
     signature   => q/
         Returns all users that have an overall negative balance
         @param auth Authentication token
-        @param org_id The context org unit as an ID or list of IDs.  This will be the home 
+        @param org_id The context org unit as an ID or list of IDs.  This will be the home
         library of the user.  If no org_unit is specified, no org unit filter is applied
     /
 );
@@ -3839,29 +3839,29 @@ sub negative_balance_users {
     return $e->die_event unless $e->allowed('VIEW_USER', $org_id);
 
     my $query = {
-        select => { 
-            mous => ['usr', 'balance_owed'], 
-            au => ['home_ou'], 
+        select => {
+            mous => ['usr', 'balance_owed'],
+            au => ['home_ou'],
             mbts => [
                 {column => 'last_billing_ts', transform => 'max', aggregate => 1},
                 {column => 'last_payment_ts', transform => 'max', aggregate => 1},
             ]
-        }, 
-        from => { 
-            mous => { 
-                au => { 
-                    fkey => 'usr', 
-                    field => 'id', 
-                    join => { 
-                        mbts => { 
-                            key => 'id', 
-                            field => 'usr' 
-                        } 
-                    } 
-                } 
-            } 
-        }, 
-        where => {'+mous' => {balance_owed => {'<' => 0}}} 
+        },
+        from => {
+            mous => {
+                au => {
+                    fkey => 'usr',
+                    field => 'id',
+                    join => {
+                        mbts => {
+                            key => 'id',
+                            field => 'usr'
+                        }
+                    }
+                }
+            }
+        },
+        where => {'+mous' => {balance_owed => {'<' => 0}}}
     };
 
     $query->{from}->{mous}->{au}->{filter}->{home_ou} = $org_id if $org_id;
@@ -3914,19 +3914,19 @@ sub request_password_reset {
         my $card = $e->search_actor_card([
             {barcode => $user_id},
             {flesh => 1, flesh_fields => {ac => ['usr']}}])->[0];
-        if (!$card) { 
+        if (!$card) {
             $e->die_event;
             return OpenILS::Event->new('ACTOR_USER_NOT_FOUND');
         }
         $user = $card->usr;
     }
-    
+
     # If the user doesn't have an email address, we can't help them
     if (!$user->email) {
         $e->die_event;
         return OpenILS::Event->new('PATRON_NO_EMAIL_ADDRESS');
     }
-    
+
     my $email_must_match = $U->ou_ancestor_setting_value($user->home_ou, 'circ.password_reset_request_requires_matching_email');
     if ($email_must_match) {
         if (lc($user->email) ne lc($email)) {
@@ -3986,7 +3986,7 @@ sub _reset_password_request {
     # TODO Check to see if the user is in a password-reset-restricted group
 
     # Otherwise, go ahead and try to get the user.
- 
+
     # Check the number of active requests for this user
     $active_requests = $e->json_query({
         from => 'aupr',
@@ -4116,10 +4116,10 @@ sub commit_password_reset {
 sub check_password_strength_default {
     my $password = shift;
     # Use the default set of checks
-    if ( (length($password) < 7) or 
-            ($password !~ m/.*\d+.*/) or 
+    if ( (length($password) < 7) or
+            ($password !~ m/.*\d+.*/) or
             ($password !~ m/.*[A-Za-z]+.*/)
-       ) {
+    ) {
         return 0;
     }
     return 1;
@@ -4145,8 +4145,8 @@ __PACKAGE__->register_method(
         desc   => 'Streams the set of "cust" objects that are used as opt-in settings for event definitions',
         params => [
             { desc => 'Authentication token',  type => 'string'},
-            { 
-                desc => 'Org Unit ID.  (optional).  If no org ID is present, the home_ou of the requesting user is used', 
+            {
+                desc => 'Org Unit ID.  (optional).  If no org ID is present, the home_ou of the requesting user is used',
                 type => 'number'
             },
         ],
@@ -4164,7 +4164,7 @@ sub event_def_opt_in_settings {
     return $e->event unless $e->checkauth;
 
     if(defined $org_id and $org_id != $e->requestor->home_ou) {
-        return $e->event unless 
+        return $e->event unless
             $e->allowed(['VIEW_USER_SETTING_TYPE', 'ADMIN_USER_SETTING_TYPE'], $org_id);
     } else {
         $org_id = $e->requestor->home_ou;
@@ -4172,8 +4172,8 @@ sub event_def_opt_in_settings {
 
     # find all config.user_setting_type's related to event_defs for the requested org unit
     my $types = $e->json_query({
-        select => {cust => ['name']}, 
-        from => {atevdef => 'cust'}, 
+        select => {cust => ['name']},
+        from => {atevdef => 'cust'},
         where => {
             '+atevdef' => {
                 owner => $U->get_org_ancestors($org_id), # context org plus parents
@@ -4183,7 +4183,7 @@ sub event_def_opt_in_settings {
     });
 
     if(@$types) {
-        $conn->respond($_) for 
+        $conn->respond($_) for
             @{$e->search_config_usr_setting_type({name => [map {$_->{name}} @$types]})};
     }
 
@@ -4288,7 +4288,7 @@ sub user_circ_history {
     ]);
 
     if ($for_print) {
-        return $U->fire_object_event(undef, 
+        return $U->fire_object_event(undef,
             'circ.format.history.print', $circs, $e->requestor->home_ou);
     }
 
@@ -4299,12 +4299,12 @@ sub user_circ_history {
 
         if ($for_email) {
             # events will be fired from action_trigger_runner
-            $U->create_events_for_hook('circ.format.history.email', 
+            $U->create_events_for_hook('circ.format.history.email',
                 $circ, $e->editor->home_ou, undef, undef, 1);
 
         } elsif ($for_clear) {
 
-            $e->delete_action_user_circ_history($circ) 
+            $e->delete_action_user_circ_history($circ)
                 or return $e->die_event;
 
         } else {
@@ -4402,7 +4402,7 @@ sub user_visible_holds {
         offset => $$options{offset}
 
         # TODO: I only want IDs. code below didn't get me there
-        # {"select":{"au":[{"column":"id", "result_field":"id", 
+        # {"select":{"au":[{"column":"id", "result_field":"id",
         # "transform":"action.usr_visible_circs"}]}, "where":{"id":10}, "from":"au"}
     },{
         substream => 1
@@ -4485,7 +4485,7 @@ __PACKAGE__->register_method(
         return => {
             desc   => q/The retrieved or updated saved search object, or id of a deleted object; Event on error/,
             class  => 'auss'
-        }   
+        }
     }
 );
 
@@ -4502,7 +4502,7 @@ __PACKAGE__->register_method(
         return => {
             desc   => q/The saved search object, Event on error/,
             class  => 'auss'
-        }   
+        }
     }
 );
 
@@ -4677,7 +4677,7 @@ sub address_alert_test {
 
     # map the json_query hashes to real objects
     return [
-        map {$e->retrieve_actor_address_alert($_)} 
+        map {$e->retrieve_actor_address_alert($_)}
             (map {$_->{id}} @$alerts)
     ];
 }
@@ -4820,7 +4820,7 @@ __PACKAGE__->register_method(
                 type => "number"}
         ],
         return => {
-            desc => "Entry fleshed with query on Create, Retrieve, and Uupdate.  1 on Delete", 
+            desc => "Entry fleshed with query on Create, Retrieve, and Uupdate.  1 on Delete",
             type => "object"
         }
     }
@@ -4836,7 +4836,7 @@ sub filter_group_entry_crud {
     if (ref $arg) {
 
         if ($arg->isnew) {
-            
+
             my $grp = $e->retrieve_actor_search_filter_group($arg->grp)
                 or return $e->die_event;
 
@@ -4906,7 +4906,7 @@ sub filter_group_entry_crud {
         ]) or return $e->die_event;
 
         return $e->die_event unless $e->allowed(
-            ['ADMIN_SEARCH_FILTER_GROUP', 'VIEW_SEARCH_FILTER_GROUP'], 
+            ['ADMIN_SEARCH_FILTER_GROUP', 'VIEW_SEARCH_FILTER_GROUP'],
             $entry->grp->owner);
 
         $e->rollback;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
index 5ae325c..9de2eec 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
@@ -20,7 +20,7 @@ sub prepare_extended_user_info {
     my $e = $self->editor;
 
     # are we already in a transaction?
-    my $local_xact = !$e->{xact_id}; 
+    my $local_xact = !$e->{xact_id};
     $e->xact_begin if $local_xact;
 
     # keep the original user object so we can restore
@@ -47,7 +47,7 @@ sub prepare_extended_user_info {
     $self->ctx->{user}->addresses([
         grep {$_->id > 0} @{$self->ctx->{user}->addresses} ]);
 
-    return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR 
+    return Apache2::Const::HTTP_INTERNAL_SERVER_ERROR
         unless $self->ctx->{user};
 
     return;
@@ -101,7 +101,7 @@ sub local_avail_concern {
     return (0, 0);
 }
 
-# context additions: 
+# context additions:
 #   user : au object, fleshed
 sub load_myopac_prefs {
     my $self = shift;
@@ -133,7 +133,7 @@ sub load_myopac_prefs {
         }
     }
 
-    return Apache2::Const::OK unless 
+    return Apache2::Const::OK unless
         $pending_addr or $replace_addr or $delete_pending;
 
     my @form_fields = qw/address_type street1 street2 city county state country post_code/;
@@ -156,13 +156,13 @@ sub load_myopac_prefs {
 
     } elsif( $delete_pending ) {
         $paddr = $e->retrieve_actor_user_address($delete_pending);
-        return Apache2::Const::HTTP_BAD_REQUEST unless 
+        return Apache2::Const::HTTP_BAD_REQUEST unless
             $paddr and $paddr->usr == $user->id and $U->is_true($paddr->pending);
         $paddr->isdeleted(1);
     }
 
     my $resp = $U->simplereq(
-        'open-ils.actor', 
+        'open-ils.actor',
         'open-ils.actor.user.address.pending.cud',
         $e->authtoken, $paddr);
 
@@ -172,7 +172,7 @@ sub load_myopac_prefs {
     }
 
     # in light of these changes, re-fetch latest data
-    $e->xact_begin; 
+    $e->xact_begin;
     $self->prepare_extended_user_info;
     $e->rollback;
 
@@ -198,7 +198,7 @@ sub load_myopac_prefs_notify {
 
     my %settings;
     my $set_map = $self->ctx->{user_setting_map};
- 
+
     foreach my $key (qw/
         opac.default_phone
         opac.default_sms_notify
@@ -227,11 +227,11 @@ sub load_myopac_prefs_notify {
 
     # Send the modified settings off to be saved
     $U->simplereq(
-        'open-ils.actor', 
+        'open-ils.actor',
         'open-ils.actor.patron.settings.update',
         $self->editor->authtoken, undef, \%settings);
 
-    # re-fetch user prefs 
+    # re-fetch user prefs
     $self->ctx->{updated_user_settings} = \%settings;
     return $self->_load_user_with_prefs || Apache2::Const::OK;
 }
@@ -256,8 +256,8 @@ sub fetch_optin_prefs {
     my $user_set = $U->simplereq(
         'open-ils.actor',
         'open-ils.actor.patron.settings.retrieve',
-        $e->authtoken, 
-        $e->requestor->id, 
+        $e->authtoken,
+        $e->requestor->id,
         [map {$_->name} @$opt_ins]
     );
 
@@ -304,7 +304,7 @@ sub load_myopac_messages {
     if ($fetch_all) {
         # fetch all the messages
         ($ctx->{patron_messages_count}, $messages) =
-            $self->_fetch_user_messages($pcrud, $offset, $limit);    
+            $self->_fetch_user_messages($pcrud, $offset, $limit);
     }
 
     $pcrud->kill_me;
@@ -317,7 +317,7 @@ sub load_myopac_messages {
             message     => $aum->message,
             create_date => $aum->create_date,
             is_read     => defined($aum->read_date) ? 1 : 0,
-            library     => $aum->sending_lib->name, 
+            library     => $aum->sending_lib->name,
         };
     }
 
@@ -495,7 +495,7 @@ sub update_optin_prefs {
 
     # remove now-false settings
     for my $pref (grep { $_->{value} } @$user_prefs) {
-        $newsets{$pref->{cust}->name} = undef 
+        $newsets{$pref->{cust}->name} = undef
             unless grep { $_ eq $pref->{cust}->name } @settings;
     }
 
@@ -506,7 +506,7 @@ sub update_optin_prefs {
 
     # update the local prefs to match reality
     for my $pref (@$user_prefs) {
-        $pref->{value} = $newsets{$pref->{cust}->name} 
+        $pref->{value} = $newsets{$pref->{cust}->name}
             if exists $newsets{$pref->{cust}->name};
     }
 
@@ -519,7 +519,7 @@ sub _load_user_with_prefs {
     return $stat if $stat; # not-OK
 
     $self->ctx->{user_setting_map} = {
-        map { $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) } 
+        map { $_->name => OpenSRF::Utils::JSON->JSON2perl($_->value) }
             @{$self->ctx->{user}->settings}
     };
 
@@ -591,7 +591,7 @@ sub load_myopac_prefs_settings {
         'circ.holds.behind_desk_pickup_supported');
 
     if ($bdous) {
-        my $setting = 
+        my $setting =
             $e->retrieve_config_usr_setting_type(
                 'circ.holds_behind_desk');
 
@@ -604,8 +604,8 @@ sub load_myopac_prefs_settings {
     return Apache2::Const::OK
         unless $self->cgi->request_method eq 'POST';
 
-    # some setting values from the form don't match the 
-    # required value/format for the db, so they have to be 
+    # some setting values from the form don't match the
+    # required value/format for the db, so they have to be
     # individually translated.
 
     my %settings;
@@ -642,7 +642,7 @@ sub load_myopac_prefs_settings {
 
             if (!$hist_clear_confirmed) {
                 # when clearing circ history, only warn if history data exists.
-    
+
                 if ($clear_circ_history) {
 
                     if ($self->fetch_user_circ_history(0, 1)->[0]) {
@@ -655,8 +655,8 @@ sub load_myopac_prefs_settings {
                     my $one_hold = $e->json_query({
                         select => {
                             au => [{
-                                column => 'id', 
-                                transform => 'action.usr_visible_holds', 
+                                column => 'id',
+                                transform => 'action.usr_visible_holds',
                                 result_field => 'id'
                             }]
                         },
@@ -693,11 +693,11 @@ sub load_myopac_prefs_settings {
 
     # Send the modified settings off to be saved
     $U->simplereq(
-        'open-ils.actor', 
+        'open-ils.actor',
         'open-ils.actor.patron.settings.update',
         $self->editor->authtoken, undef, \%settings);
 
-    # re-fetch user prefs 
+    # re-fetch user prefs
     $self->ctx->{updated_user_settings} = \%settings;
     return $self->_load_user_with_prefs || Apache2::Const::OK;
 }
@@ -755,8 +755,8 @@ sub fetch_user_holds {
         my $circ = OpenSRF::AppSession->create('open-ils.circ');
 
         $hold_ids = $circ->request(
-            'open-ils.circ.holds.id_list.retrieve.authoritative', 
-            $e->authtoken, 
+            'open-ils.circ.holds.id_list.retrieve.authoritative',
+            $e->authtoken,
             $e->requestor->id,
             $available
         )->gather(1);
@@ -791,7 +791,7 @@ sub fetch_user_holds {
             last unless $hold_id;
             my $ses = OpenSRF::AppSession->create('open-ils.circ');
             my $req = $ses->request(
-                'open-ils.circ.hold.details.retrieve', 
+                'open-ils.circ.hold.details.retrieve',
                 $e->authtoken, $hold_id, $args);
             push(@ses, {ses => $ses, req => $req});
         }
@@ -825,13 +825,13 @@ sub fetch_user_holds {
 
                     my $filter_data = $U->simplereq(
                         'open-ils.circ',
-                        'open-ils.circ.mmr.holds.filters.authoritative.atomic', 
+                        'open-ils.circ.mmr.holds.filters.authoritative.atomic',
                         $hold->target, $filter_org, [$hold->id]
                     );
 
-                    $blob->{metarecord_filters} = 
+                    $blob->{metarecord_filters} =
                         $filter_data->[0]->{metarecord};
-                    $blob->{metarecord_selected_filters} = 
+                    $blob->{metarecord_selected_filters} =
                         $filter_data->[1]->{hold};
                 } else {
 
@@ -884,7 +884,7 @@ sub handle_hold_update {
         }
 
     } elsif ($action =~ /activate|suspend/) {
-        
+
         my $vlist = [];
         for my $hold_id (@hold_ids) {
             my $vals = {id => $hold_id};
@@ -901,7 +901,7 @@ sub handle_hold_update {
         }
 
         my $resp = $circ->request('open-ils.circ.hold.update.batch.atomic', $e->authtoken, undef, $vlist)->gather(1);
-        $self->ctx->{hold_suspend_post_capture} = 1 if 
+        $self->ctx->{hold_suspend_post_capture} = 1 if
             grep {$U->event_equals($_, 'HOLD_SUSPEND_AFTER_CAPTURE')} @$resp;
 
     } elsif ($action eq 'edit') {
@@ -945,7 +945,7 @@ sub load_myopac_holds {
     my $self = shift;
     my $e = $self->editor;
     my $ctx = $self->ctx;
-    
+
     my $limit = $self->cgi->param('limit') || 15;
     my $offset = $self->cgi->param('offset') || 0;
     my $action = $self->cgi->param('action') || '';
@@ -1057,8 +1057,8 @@ sub load_place_hold {
         M => sub {
             # target metarecords
             my $mrecs = $e->batch_retrieve_metabib_metarecord([
-                \@targets, 
-                {flesh => 1, flesh_fields => {mmr => ['master_record']}}], 
+                \@targets,
+                {flesh => 1, flesh_fields => {mmr => ['master_record']}}],
                 {substream => 1}
             );
 
@@ -1070,11 +1070,11 @@ sub load_place_hold {
                     'open-ils.circ',
                     'open-ils.circ.mmr.holds.filters.authoritative', $mr->id, $ou_id);
 
-                my $holdable_formats = 
+                my $holdable_formats =
                     $self->compile_holdable_formats($mr->id);
 
                 push(@hold_data, $data_filler->({
-                    target => $mr, 
+                    target => $mr,
                     record => $mr->master_record,
                     holdable_formats => $holdable_formats,
                     metarecord_filters => $filter_data->{metarecord}
@@ -1091,25 +1091,25 @@ sub load_place_hold {
                 my ($rec) = grep {$_->id eq $id} @$recs;
 
                 # NOTE: if tpac ever supports locked-down pickup libs,
-                # we'll need to pass a pickup_lib param along with the 
+                # we'll need to pass a pickup_lib param along with the
                 # record to filter the set of monographic parts.
                 my $parts = $U->simplereq(
                     'open-ils.search',
-                    'open-ils.search.biblio.record_hold_parts', 
+                    'open-ils.search.biblio.record_hold_parts',
                     {record => $rec->id}
                 );
 
-                # T holds on records that have parts are OK, but if the record has 
-                # no non-part copies, the hold will ultimately fail.  When that 
+                # T holds on records that have parts are OK, but if the record has
+                # no non-part copies, the hold will ultimately fail.  When that
                 # happens, require the user to select a part.
                 my $part_required = 0;
                 if (@$parts) {
                     my $np_copies = $e->json_query({
-                        select => { acp => [{column => 'id', transform => 'count', alias => 'count'}]}, 
-                        from => {acp => {acn => {}, acpm => {type => 'left'}}}, 
+                        select => { acp => [{column => 'id', transform => 'count', alias => 'count'}]},
+                        from => {acp => {acn => {}, acpm => {type => 'left'}}},
                         where => {
                             '+acp' => {deleted => 'f'},
-                            '+acn' => {deleted => 'f', record => $rec->id}, 
+                            '+acn' => {deleted => 'f', record => $rec->id},
                             '+acpm' => {id => undef}
                         }
                     });
@@ -1132,7 +1132,7 @@ sub load_place_hold {
                 }
             ], {substream => 1});
 
-            for my $id (@targets) { 
+            for my $id (@targets) {
                 my ($vol) = grep {$_->id eq $id} @$vols;
                 push(@hold_data, $data_filler->({target => $vol, record => $vol->record}));
             }
@@ -1148,7 +1148,7 @@ sub load_place_hold {
                 }
             ], {substream => 1});
 
-            for my $id (@targets) { 
+            for my $id (@targets) {
                 my ($copy) = grep {$_->id eq $id} @$copies;
                 push(@hold_data, $data_filler->({target => $copy, record => $copy->call_number->record}));
             }
@@ -1163,7 +1163,7 @@ sub load_place_hold {
                 }
             ], {substream => 1});
 
-            for my $id (@targets) { 
+            for my $id (@targets) {
                 my ($iss) = grep {$_->id eq $id} @$isses;
                 push(@hold_data, $data_filler->({target => $iss, record => $iss->subscription->record_entry}));
             }
@@ -1197,7 +1197,7 @@ sub load_place_hold {
         # find the real hold target
 
         $usr = $U->simplereq(
-            'open-ils.actor', 
+            'open-ils.actor',
             "open-ils.actor.user.retrieve_id_by_barcode_or_username",
             $e->authtoken, $cgi->param("hold_usr"));
 
@@ -1207,21 +1207,21 @@ sub load_place_hold {
         }
     }
 
-    # target_id is the true target_id for holds placement.  
+    # target_id is the true target_id for holds placement.
     # needed for attempt_hold_placement()
     # With the exception of P-type holds, target_id == target->id.
     $_->{target_id} = $_->{target}->id for @hold_data;
 
     if ($ctx->{hold_type} eq 'T') {
 
-        # Much like quantum wave-particles, P-type holds pop into 
+        # Much like quantum wave-particles, P-type holds pop into
         # and out of existence at the user's whim.  For our purposes,
-        # we treat such holds as T(itle) holds with a selected_part 
-        # designation.  When the time comes to pass the hold information 
-        # off for holds possibility testing and placement, make it look 
+        # we treat such holds as T(itle) holds with a selected_part
+        # designation.  When the time comes to pass the hold information
+        # off for holds possibility testing and placement, make it look
         # like a real P-type hold.
         my (@p_holds, @t_holds);
-        
+
         for my $idx (0..$#parts) {
             my $hdata = $hold_data[$idx];
             if (my $part = $parts[$idx]) {
@@ -1242,11 +1242,11 @@ sub load_place_hold {
         $self->attempt_hold_placement($usr, $pickup_lib, $ctx->{hold_type}, @hold_data);
     }
 
-    # NOTE: we are leaving the staff-placed patron barcode cookie 
-    # in place.  Otherwise, it's not possible to place more than 
-    # one hold for the patron within a staff/patron session.  This 
-    # does leave the barcode to linger longer than is ideal, but 
-    # normal staff work flow will cause the cookie to be replaced 
+    # NOTE: we are leaving the staff-placed patron barcode cookie
+    # in place.  Otherwise, it's not possible to place more than
+    # one hold for the patron within a staff/patron session.  This
+    # does leave the barcode to linger longer than is ideal, but
+    # normal staff work flow will cause the cookie to be replaced
     # with each new patron anyway.
     # TODO: See about getting the staff client to clear the cookie
 
@@ -1261,12 +1261,12 @@ sub attempt_hold_placement {
     my $ctx = $self->ctx;
     my $e = $self->editor;
 
-    # First see if we should warn/block for any holds that 
+    # First see if we should warn/block for any holds that
     # might have locally available items.
     for my $hdata (@hold_data) {
         my ($local_block, $local_alert) = $self->local_avail_concern(
             $hdata->{target_id}, $hold_type, $pickup_lib);
-    
+
         if ($local_block) {
             $hdata->{hold_failed} = 1;
             $hdata->{hold_local_block} = 1;
@@ -1295,17 +1295,17 @@ sub attempt_hold_placement {
         # map each set to the ID of the target.
         my $holdable_formats = {};
         if ($hold_type eq 'M') {
-            $holdable_formats->{$_->{target_id}} = 
+            $holdable_formats->{$_->{target_id}} =
                 $_->{holdable_formats} for @hold_data;
         }
 
         my $bses = OpenSRF::AppSession->create('open-ils.circ');
-        my $breq = $bses->request( 
-            $method, 
-            $e->authtoken, 
-            $data_filler->({   
+        my $breq = $bses->request(
+            $method,
+            $e->authtoken,
+            $data_filler->({
                 patronid => $usr,
-                pickup_lib => $pickup_lib, 
+                pickup_lib => $pickup_lib,
                 hold_type => $hold_type,
                 holdable_formats_map => $holdable_formats
             }),
@@ -1331,14 +1331,14 @@ sub attempt_hold_placement {
                 $hdata->{hold_failed_event} = $result;
 
             } else {
-                
+
                 if(not ref $result and $result > 0) {
                     # successul hold returns the hold ID
 
-                    $hdata->{hold_success} = $result; 
-    
+                    $hdata->{hold_success} = $result;
+
                 } else {
-                    # hold-specific failure event 
+                    # hold-specific failure event
                     $hdata->{hold_failed} = 1;
 
                     if (ref $result eq 'HASH') {
@@ -1351,7 +1351,7 @@ sub attempt_hold_placement {
                             $hdata->{could_override} = $self->editor->allowed( $theTextcode );
                             $hdata->{age_protect} = 1;
                         } else {
-                            $hdata->{could_override} = $result->{place_unfillable} || 
+                            $hdata->{could_override} = $result->{place_unfillable} ||
                                 $self->test_could_override($hdata->{hold_failed_event});
                         }
                     } elsif (ref $result eq 'ARRAY') {
@@ -1387,15 +1387,15 @@ sub compile_holdable_formats {
     my $cgi = $self->cgi;
 
     # exit early if not needed
-    return undef unless 
-        grep /metarecord_formats_|metarecord_langs_/, 
+    return undef unless
+        grep /metarecord_formats_|metarecord_langs_/,
         $cgi->param;
 
     # CGI params are based on the MR id, since during hold placement
-    # we have no old ID.  During hold edit, map the hold ID back to 
+    # we have no old ID.  During hold edit, map the hold ID back to
     # the metarecod target.
-    $mr_id = 
-        $e->retrieve_action_hold_request($hold_id)->target 
+    $mr_id =
+        $e->retrieve_action_hold_request($hold_id)->target
         unless $mr_id;
 
     my $format_attr = $self->ctx->{get_cgf}->(
@@ -1419,13 +1419,13 @@ sub compile_holdable_formats {
     my $blob = {};
     if (@selected_formats) {
         $blob->{0} = [
-            map { {_attr => $format_attr, _val => $_} } 
+            map { {_attr => $format_attr, _val => $_} }
             @selected_formats
         ];
     }
     if (@selected_langs) {
         $blob->{1} = [
-            map { {_attr => 'item_lang', _val => $_} } 
+            map { {_attr => 'item_lang', _val => $_} }
             @selected_langs
         ];
     }
@@ -1490,9 +1490,9 @@ sub fetch_user_circs {
     my @circs;
     for my $circ (@$circs) {
         push(@circs, {
-            circ => $circ, 
-            marc_xml => ($flesh and $circ->target_copy->call_number->id != -1) ? 
-                XML::LibXML->new->parse_string($circ->target_copy->call_number->record->marc) : 
+            circ => $circ,
+            marc_xml => ($flesh and $circ->target_copy->call_number->id != -1) ?
+                XML::LibXML->new->parse_string($circ->target_copy->call_number->record->marc) :
                 undef  # pre-cat copy, use the dummy title/author instead
         });
     }
@@ -1525,7 +1525,7 @@ sub handle_circ_renew {
     for my $circ (@$circs) {
 
         my $evt = $U->simplereq(
-            'open-ils.circ', 
+            'open-ils.circ',
             'open-ils.circ.renew',
             $self->editor->authtoken,
             {
@@ -1535,7 +1535,7 @@ sub handle_circ_renew {
             }
         );
 
-        # TODO return these, then insert them into the circ data 
+        # TODO return these, then insert them into the circ data
         # blob that is shoved into the template for each circ
         # so the template won't have to match them
         push(@responses, {copy => $circ->{circ}->target_copy, evt => $evt});
@@ -1603,8 +1603,8 @@ sub load_myopac_circ_history {
     return Apache2::Const::OK;
 }
 
-# if 'flesh' is set, copy data etc. is loaded and the return value is 
-# a hash of 'circ' and 'marc_xml'.  Othwerwise, it's just a list of 
+# if 'flesh' is set, copy data etc. is loaded and the return value is
+# a hash of 'circ' and 'marc_xml'.  Othwerwise, it's just a list of
 # auch objects.
 sub fetch_user_circ_history {
     my ($self, $flesh, $limit, $offset) = @_;
@@ -1640,10 +1640,10 @@ sub fetch_user_circ_history {
     my @circs;
     for my $circ (@$circs) {
         push(@circs, {
-            circ => $circ, 
-            marc_xml => ($circ->target_copy->call_number->id != -1) ? 
+            circ => $circ,
+            marc_xml => ($circ->target_copy->call_number->id != -1) ?
                 XML::LibXML->new->parse_string(
-                    $circ->target_copy->call_number->record->marc) : 
+                    $circ->target_copy->call_number->record->marc) :
                 undef  # pre-cat copy, use the dummy title/author instead
         });
     }
@@ -1692,8 +1692,8 @@ sub load_myopac_hold_history {
     my $hold_ids = $e->json_query({
         select => {
             au => [{
-                column => 'id', 
-                transform => 'action.usr_visible_holds', 
+                column => 'id',
+                transform => 'action.usr_visible_holds',
                 result_field => 'id'
             }]
         },
@@ -1740,7 +1740,7 @@ sub load_myopac_payments {
         my $min_ts = DateTime->now(
             "time_zone" => DateTime::TimeZone->new("name" => "local"),
         )->subtract("seconds" => interval_to_seconds($max_age))->iso8601();
-        
+
         $logger->info("XXX min_ts: $min_ts");
         $args->{"where"} = {"payment_ts" => {">=" => $min_ts}};
     }
@@ -1769,7 +1769,7 @@ sub load_myopac_pay_init {
         return $stat if $stat;
         @payment_xacts =
             map { $_->{xact}->id } (
-                @{$self->ctx->{fines}->{circulation}}, 
+                @{$self->ctx->{fines}->{circulation}},
                 @{$self->ctx->{fines}->{grocery}}
         );
     }
@@ -1785,7 +1785,7 @@ sub load_myopac_pay_init {
     /);
 
     my $cache_args = {
-        cc_args => $cc_args, 
+        cc_args => $cc_args,
         user => $self->ctx->{user}->id,
         xacts => \@payment_xacts
     };
@@ -1798,8 +1798,8 @@ sub load_myopac_pay_init {
 
     # after we render the processing page, we quickly redirect to submit
     # the actual payment.  The refresh url contains the payment token.
-    # It also contains the list of xact IDs, which allows us to clear the 
-    # cache at the earliest possible time while leaving a trace of which 
+    # It also contains the list of xact IDs, which allows us to clear the
+    # cache at the earliest possible time while leaving a trace of which
     # transactions we were processing, so the UI can bring the user back
     # to the payment form w/ the same xacts if the payment fails.
 
@@ -1828,7 +1828,7 @@ sub load_myopac_pay {
     my @payment_xacts = @{$cache_args->{xacts}};
     my $cc_args = $cache_args->{cc_args};
 
-    # as an added security check, verify the user submitting 
+    # as an added security check, verify the user submitting
     # the form is the same as the user whose data was cached
     return Apache2::Const::HTTP_BAD_REQUEST unless
         $cache_args->{user} == $self->ctx->{user}->id;
@@ -1859,8 +1859,8 @@ sub load_myopac_pay {
 
     unless ($resp->{"textcode"}) {
         $self->ctx->{printable_receipt} = $U->simplereq(
-           "open-ils.circ", "open-ils.circ.money.payment_receipt.print",
-           $self->editor->authtoken, $resp->{payments}
+        "open-ils.circ", "open-ils.circ.money.payment_receipt.print",
+        $self->editor->authtoken, $resp->{payments}
         );
     }
 
@@ -1871,8 +1871,8 @@ sub load_myopac_receipt_print {
     my $self = shift;
 
     $self->ctx->{printable_receipt} = $U->simplereq(
-       "open-ils.circ", "open-ils.circ.money.payment_receipt.print",
-       $self->editor->authtoken, [$self->cgi->param("payment")]
+    "open-ils.circ", "open-ils.circ.money.payment_receipt.print",
+    $self->editor->authtoken, [$self->cgi->param("payment")]
     );
 
     return Apache2::Const::OK;
@@ -1885,8 +1885,8 @@ sub load_myopac_receipt_email {
     # question has an email address, so we do.
     if ($self->ctx->{user}->email) {
         $self->ctx->{email_receipt_result} = $U->simplereq(
-           "open-ils.circ", "open-ils.circ.money.payment_receipt.email",
-           $self->editor->authtoken, [$self->cgi->param("payment")]
+        "open-ils.circ", "open-ils.circ.money.payment_receipt.email",
+        $self->editor->authtoken, [$self->cgi->param("payment")]
         );
     } else {
         $self->ctx->{email_receipt_result} =
@@ -1913,7 +1913,7 @@ sub prepare_fines {
 
     my $cstore = OpenSRF::AppSession->create('open-ils.cstore');
 
-    # TODO: This should really be a ML call, but the existing calls 
+    # TODO: This should really be a ML call, but the existing calls
     # return an excessive amount of data and don't offer streaming
 
     my %paging = ($limit or $offset) ? (limit => $limit, offset => $offset) : ();
@@ -1979,7 +1979,7 @@ sub prepare_fines {
                 xact => $mobts,
                 last_grocery_billing => $last_billing,
                 marc_xml => $marc_xml
-            } 
+            }
         );
     }
 
@@ -2028,7 +2028,7 @@ sub load_myopac_update_email {
     # needed for most up-to-date email address
     if (my $r = $self->prepare_extended_user_info) { return $r };
 
-    return Apache2::Const::OK 
+    return Apache2::Const::OK
         unless $self->cgi->request_method eq 'POST';
 
     unless($email =~ /.+\@.+\..+/) { # TODO better regex?
@@ -2037,8 +2037,8 @@ sub load_myopac_update_email {
     }
 
     my $stat = $U->simplereq(
-        'open-ils.actor', 
-        'open-ils.actor.user.email.update', 
+        'open-ils.actor',
+        'open-ils.actor.user.email.update',
         $e->authtoken, $email, $current_pw);
 
     if($U->event_equals($stat, 'INCORRECT_PASSWORD')) {
@@ -2093,7 +2093,7 @@ sub load_myopac_update_username {
         return $self->generic_redirect($url);
     }
 
-    return Apache2::Const::OK 
+    return Apache2::Const::OK
         unless $self->cgi->request_method eq 'POST';
 
     unless($username and $username !~ /\s/) { # any other username restrictions?
@@ -2117,8 +2117,8 @@ sub load_myopac_update_username {
     if($username ne $e->requestor->usrname) {
 
         my $evt = $U->simplereq(
-            'open-ils.actor', 
-            'open-ils.actor.user.username.update', 
+            'open-ils.actor',
+            'open-ils.actor.user.username.update',
             $e->authtoken, $username, $current_pw);
 
         if($U->event_equals($evt, 'INCORRECT_PASSWORD')) {
@@ -2143,7 +2143,7 @@ sub load_myopac_update_password {
     my $e = $self->editor;
     my $ctx = $self->ctx;
 
-    return Apache2::Const::OK 
+    return Apache2::Const::OK
         unless $self->cgi->request_method eq 'POST';
 
     my $current_pw = $self->cgi->param('current_pw') || '';
@@ -2168,8 +2168,8 @@ sub load_myopac_update_password {
     }
 
     my $evt = $U->simplereq(
-        'open-ils.actor', 
-        'open-ils.actor.user.password.update', 
+        'open-ils.actor',
+        'open-ils.actor.user.password.update',
         $e->authtoken, $new_pw, $current_pw);
 
 
@@ -2326,8 +2326,8 @@ sub load_myopac_bookbags {
                 }
             }
 
-            # we're done with our CStoreEditor.  Rollback here so 
-            # later calls don't cause a timeout, resulting in a 
+            # we're done with our CStoreEditor.  Rollback here so
+            # later calls don't cause a timeout, resulting in a
             # transaction rollback under the covers.
             $e->rollback;
 
@@ -2349,7 +2349,7 @@ sub load_myopac_bookbags {
 
             my (undef, @recs) = $self->get_records_and_facets(
                 [ map {$_->target_biblio_record_entry->id} @$items ],
-                undef, 
+                undef,
                 {
                     flesh => '{mra,holdings_xml,acp,exclude_invisible_acn}',
                     flesh_depth => 1,
@@ -2383,7 +2383,7 @@ sub load_myopac_bookbags {
         }
     }
 
-    # this rollback may be a dupe, but that's OK because 
+    # this rollback may be a dupe, but that's OK because
     # cstoreditor ignores dupe rollbacks
     $e->rollback;
 
@@ -2443,7 +2443,7 @@ sub load_myopac_bookbag_update {
                     $item->bucket($list_id);
                     $item->target_biblio_record_entry($add_rec);
                     $success = $U->simplereq('open-ils.actor',
-                                             'open-ils.actor.container.item.create', $e->authtoken, 'biblio', $item);
+                                            'open-ils.actor.container.item.create', $e->authtoken, 'biblio', $item);
                     last unless $success;
                 }
             }
@@ -2462,7 +2462,7 @@ sub load_myopac_bookbag_update {
                 @hold_recs = map { $_->target_biblio_record_entry } @$items;
             }
         }
-                
+
         return Apache2::Const::OK unless @hold_recs;
         $logger->info("placing holds from list page on: @hold_recs");
 
@@ -2479,12 +2479,12 @@ sub load_myopac_bookbag_update {
 
         $list = $e->retrieve_container_biblio_record_entry_bucket($list_id);
 
-        return Apache2::Const::HTTP_BAD_REQUEST unless 
+        return Apache2::Const::HTTP_BAD_REQUEST unless
             $list and $list->owner == $e->requestor->id;
     }
 
     if($action eq 'delete') {
-        $success = $U->simplereq('open-ils.actor', 
+        $success = $U->simplereq('open-ils.actor',
             'open-ils.actor.container.full_delete', $e->authtoken, 'biblio', $list_id);
         if ($success) {
             # We check to see if we're deleting the user's default list.
@@ -2504,21 +2504,21 @@ sub load_myopac_bookbag_update {
     } elsif($action eq 'show') {
         unless($U->is_true($list->pub)) {
             $list->pub('t');
-            $success = $U->simplereq('open-ils.actor', 
+            $success = $U->simplereq('open-ils.actor',
                 'open-ils.actor.container.update', $e->authtoken, 'biblio', $list);
         }
 
     } elsif($action eq 'hide') {
         if($U->is_true($list->pub)) {
             $list->pub('f');
-            $success = $U->simplereq('open-ils.actor', 
+            $success = $U->simplereq('open-ils.actor',
                 'open-ils.actor.container.update', $e->authtoken, 'biblio', $list);
         }
 
     } elsif($action eq 'rename') {
         if($name) {
             $list->name($name);
-            $success = $U->simplereq('open-ils.actor', 
+            $success = $U->simplereq('open-ils.actor',
                 'open-ils.actor.container.update', $e->authtoken, 'biblio', $list);
         }
 
@@ -2527,7 +2527,7 @@ sub load_myopac_bookbag_update {
             my $item = Fieldmapper::container::biblio_record_entry_bucket_item->new;
             $item->bucket($list_id);
             $item->target_biblio_record_entry($add_rec);
-            $success = $U->simplereq('open-ils.actor', 
+            $success = $U->simplereq('open-ils.actor',
                 'open-ils.actor.container.item.create', $e->authtoken, 'biblio', $item);
             last unless $success;
         }
@@ -2712,7 +2712,7 @@ sub load_myopac_circ_history_export {
     my $circs = $self->fetch_user_circ_history;
 
     $self->ctx->{csv} = $U->fire_object_event(
-        undef, 
+        undef,
         'circ.format.history.csv', $circs,
         $self->editor->requestor->home_ou
     );
@@ -2740,16 +2740,16 @@ sub load_password_reset {
             if ($pwd1 eq $pwd2) {
 
                 my $response = $U->simplereq(
-                    'open-ils.actor', 
+                    'open-ils.actor',
                     'open-ils.actor.patron.password_reset.commit',
                     $uuid, $pwd1);
 
                 $logger->info("patron password reset response " . Dumper($response));
 
                 if ($U->event_code($response)) { # non-success event
-                    
+
                     my $code = $response->{textcode};
-                    
+
                     if ($code eq 'PATRON_NOT_AN_ACTIVE_PASSWORD_RESET_REQUEST') {
                         $ctx->{pwreset} = {style => 'error', status => 'NOT_ACTIVE'};
                     }
@@ -2779,7 +2779,7 @@ sub load_password_reset {
         push(@params, $email) if $email;
 
         $U->simplereq(
-            'open-ils.actor', 
+            'open-ils.actor',
             'open-ils.actor.patron.password_reset.request', @params);
 
         $ctx->{pwreset} = {status => 'REQUEST_SUCCESS'};
diff --git a/Open-ILS/src/templates/opac/myopac/circ_history.tt2 b/Open-ILS/src/templates/opac/myopac/circ_history.tt2
index e686b80..abe007d 100644
--- a/Open-ILS/src/templates/opac/myopac/circ_history.tt2
+++ b/Open-ILS/src/templates/opac/myopac/circ_history.tt2
@@ -9,7 +9,7 @@
 
 <h3 class="sr-only">[% l('History of Checked Out Items') %]</h3>
 <div style="padding:0px;">
-    
+
     <div id="acct_checked_tabs">
         <div class="align">
             <a href='[% mkurl('circs',{},1) %]'>[% l("Current Items Checked Out") %]</a>
@@ -19,7 +19,7 @@
         </div>
     </div>
 
-    [% 
+    [%
     # In the sorting case, the size is the size of ALL the circ items.  In the non-sorting case,
     # the size is simply the size of the chunk passed in.  See the TODO below for the still-lingering
     # bug.
@@ -38,14 +38,14 @@
                 [% IF offset == 0 %] class='invisible' [% END %]><span class="nav_arrow_fix">◄</span>[% l('Previous') %]</a>
             [%# TODO: get total to prevent paging off then end of the list.. %]
             <a href='[% mkurl('circ_history', {limit => limit, offset => (offset + limit)}) %]'
-               [% IF no_next %] class='invisible' [% END %] >[% l('Next') %]<span class="nav_arrow_fix">►</span></a>
+            [% IF no_next %] class='invisible' [% END %] >[% l('Next') %]<span class="nav_arrow_fix">►</span></a>
         </span>
         <div class="float-left">
             <form action="[% mkurl(ctx.opac_root _ '/myopac/circ_history/export') %]" method="post">
                 <div>
                     [%- INCLUDE "opac/parts/preserve_params.tt2" %]
                     [% IF ctx.circs.size > 0 %]
-                    <input type="hidden" name="filename" value="[% l('circ_history.csv') %]"/> 
+                    <input type="hidden" name="filename" value="[% l('circ_history.csv') %]"/>
                     <button type="submit">[% l('Download CSV') %]</button>
                     [% END %]
                 </div>
@@ -102,71 +102,71 @@
                 [%# Copy the ctx.circs into a local array, then add a SORT field
                     that contains the value to sort on.  Since we need the item attrs,
                     invoke it and save the result in ATTRS.
-		%]
-		[% 
+        %]
+        [%
                 circ_items = ctx.circs;  # Array assignment
 
                 FOR circ IN circ_items;
                     circ.ATTRS = {marc_xml => circ.marc_xml};
                     PROCESS get_marc_attrs args=circ.ATTRS;
-		
+
                     SWITCH sort_field;
 
-                       CASE "sort_title";
-                          circ.SORTING = circ.ATTRS.sort_title;
+                    CASE "sort_title";
+                        circ.SORTING = circ.ATTRS.sort_title;
 
-                       CASE "author";
-                          circ.SORTING = circ.ATTRS.author;
+                    CASE "author";
+                        circ.SORTING = circ.ATTRS.author;
 
-                       CASE "checkout";
-                          circ.SORTING = circ.circ.xact_start;
+                    CASE "checkout";
+                        circ.SORTING = circ.circ.xact_start;
 
-                       CASE "due";
-                          circ.SORTING = circ.circ.due_date;
+                    CASE "due";
+                        circ.SORTING = circ.circ.due_date;
 
-                       CASE "returned";
-                          circ.SORTING = circ.circ.checkin_time;
+                    CASE "returned";
+                        circ.SORTING = circ.circ.checkin_time;
 
-                       CASE "barcode";
-                          circ.SORTING = circ.circ.target_copy.barcode;
+                    CASE "barcode";
+                        circ.SORTING = circ.circ.target_copy.barcode;
 
-                       CASE "callnum";
-                          circ.SORTING = circ.circ.target_copy.call_number.label;
+                    CASE "callnum";
+                        circ.SORTING = circ.circ.target_copy.call_number.label;
 
-                       CASE;
-                          sort_field = "";
+                    CASE;
+                        sort_field = "";
                     END; # SWITCH
                 END; #FOR circ
 
                 IF (sort_field != "sort_title");
-                   deemphasize_class = "";
+                deemphasize_class = "";
                 ELSE;
-                   deemphasize_class = " class=\"sort_deemphasize\"";
+                deemphasize_class = " class=\"sort_deemphasize\"";
                 END;
-                       
+
                 # Apply sorting to circ_items
                 IF (sort_field);
-                   circ_items = circ_items.sort("SORTING");
-                   IF (CGI.param("sort_type") == "desc");
-                      circ_items = circ_items.reverse;
-                   END;
+                circ_items = circ_items.sort("SORTING");
+                IF (CGI.param("sort_type") == "desc");
+                    circ_items = circ_items.reverse;
+                END;
 
-                   # Shorten the circ_items list per offset/limit/cout
-                   hi = offset + limit - 1;
-                   hi = hi > circ_items.max ? circ_items.max : hi;
+                # Shorten the circ_items list per offset/limit/cout
+                hi = offset + limit - 1;
+                hi = hi > circ_items.max ? circ_items.max : hi;
 
-                   circ_items = circ_items.slice(offset, hi);
+                circ_items = circ_items.slice(offset, hi);
                 END;
 
                 # circ_items list is now sorted.  Traverse and dump the information.
 
                 FOR circ IN circ_items; %]
                     <tr>
-			<td align="center" style="text-align:center;">
-				<input type="checkbox" name="circ_id" value="[% circ.circ.id %]" />
-			</td>
+            <td align="center" style="text-align:center;">
+                <input type="checkbox" name="circ_id" value="[% circ.circ.id %]" />
+            </td>
                         <td>
-                            <a href="[% mkurl(ctx.opac_root _ '/record/' _ 
+                            <a href="[% mkurl(ctx.opac_root _ '/record/' _
                                 circ.circ.target_copy.call_number.record.id, {}, 1) %]"
                                 name="[% l('Catalog record') %]"><span[%- deemphasize_class -%]>
                                 [%- circ.ATTRS.title.substr(0,circ.ATTRS.nonfiling_characters) | html %]</span>
@@ -185,8 +185,8 @@
                             [% date.format(ctx.parse_datetime(circ.circ.due_date),DATE_FORMAT); %]
                         </td>
                         <td>
-                            [% IF circ.circ.checkin_time; 
-                                    date.format(ctx.parse_datetime(circ.circ.checkin_time),DATE_FORMAT); 
+                            [% IF circ.circ.checkin_time;
+                                    date.format(ctx.parse_datetime(circ.circ.checkin_time),DATE_FORMAT);
                                 ELSE; %]
                                 <span style='color:blue;'>*</span><!-- meh -->
                             [% END; %]

commit 6987fc32ef72a641d24922850e603b156ff06f64
Author: Dan Pearl <dpearl at cwmars.org>
Date:   Tue Oct 20 17:05:07 2015 -0400

    LP#1312699 - Add feature to allow user to edit their checkout history.
    
    In the checkout history page, a new column and action selector is provided to allow
    the paton to indicate items they would just as soon not want to see again in the
    history list for whatever reason.  NOTE: This is not a PURGE function; it simply
    suppresses display of items in the history list (and exported history files).
    Internally, the circulations are kept by Evergreen for several reasons which are
    not affected by this functionality.
    
    Signed-off-by: Dan Pearl <dpearl at cwmars.org>
    Signed-off-by: Josh Stompro <stomproj at larl.org>
    Signed-off-by: Jake Litrell <jake at masslnc.org>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
index ec0bada..5ae325c 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
@@ -1585,6 +1585,10 @@ sub load_myopac_circ_history {
     my $ctx = $self->ctx;
     my $limit = $self->cgi->param('limit') || 15;
     my $offset = $self->cgi->param('offset') || 0;
+    my $action = $self->cgi->param('action') || '';
+
+    my $circ_handle_result;
+    $circ_handle_result = $self->handle_circ_update($action) if $action;
 
     $ctx->{circ_history_limit} = $limit;
     $ctx->{circ_history_offset} = $offset;
@@ -1647,6 +1651,34 @@ sub fetch_user_circ_history {
     return \@circs;
 }
 
+sub handle_circ_update {
+    my $self = shift;
+    my $action = shift;
+    my $circ_ids = shift;
+    my $e = $self->editor;
+    my $url;
+
+    my @circ_ids = ($circ_ids) ? @$circ_ids : $self->cgi->param('circ_id'); # for non-_all actions
+
+    my $cstore_ses = OpenSRF::AppSession->create('open-ils.cstore');
+    $cstore_ses->connect();
+    $cstore_ses->request('open-ils.cstore.transaction.begin')->gather(1);
+
+    if($action =~ /delete/) {
+        for my $circ_id (@circ_ids) {
+            my $circ = $cstore_ses->request(
+                'open-ils.cstore.direct.action.circulation.retrieve', $circ_id)->gather(1);
+            $circ->hide_from_usr_history(1);
+            my $resp = $cstore_ses->request(
+                'open-ils.cstore.direct.action.circulation.update', $circ)->gather(1);
+        }
+    }
+
+    $cstore_ses->request('open-ils.cstore.transaction.commit')->gather(1);
+    $cstore_ses->disconnect();
+    return undef;
+}
+
 # TODO: action.usr_visible_holds does not return cancelled holds.  Should it?
 sub load_myopac_hold_history {
     my $self = shift;
diff --git a/Open-ILS/src/templates/opac/myopac/circ_history.tt2 b/Open-ILS/src/templates/opac/myopac/circ_history.tt2
index 5339b25..e686b80 100644
--- a/Open-ILS/src/templates/opac/myopac/circ_history.tt2
+++ b/Open-ILS/src/templates/opac/myopac/circ_history.tt2
@@ -58,11 +58,37 @@
     <div class="warning_box">[% l('There are no items in your circulation history.') %]</div>
     [% ELSE %]
 
+        <form method="post" id="circ-form"
+            onsubmit="return confirm('[% l("Are you sure you wish to delete the selected item(s)?") %]');">
+        <table cellpadding='0' cellspacing='0' class="item_list_padding">
+            <tr>
+                <td>
+                    <select name="action">
+                        <option value="delete">[% l('Delete Selected Titles') %]</option>
+                    </select>
+                </td>
+                <td style="padding-left:9px;">
+                    <input type="submit"
+                        value="[% l('Go') %]"
+                        alt="[% l('Go') %]" title="[% l('Go') %]"
+                        class="opac-button" />
+                </td>
+                <!--
+                <td style="padding-left:5px;">
+                    <a href="#"><img alt="[% l('Deleting Help') %]"
+                        src="[% ctx.media_prefix %]/images/question-mark.png" /></a>
+                </td>
+                -->
+            </tr>
+        </table>
     <div id='checked_main'>
         <table id="acct_checked_main_header"
             title="[% l('History of Items Checked Out') %]">
             <thead>
                 <tr>
+                    <th align="center">
+                        <input type="checkbox" onclick="var inputs=document.getElementsByTagName('input'); for (i = 0; i < inputs.length; i++) { if (inputs[i].name == 'circ_id' && !inputs[i].disabled) inputs[i].checked = this.checked;}"/>
+                    </th>
                     <th>[% sort_head("sort_title", l("Title")) %]</th>
                     <th>[% sort_head("author", l("Author")) %]</th>
                     <th>[% sort_head("checkout", l("Checkout Date")) %]</th>
@@ -136,6 +162,9 @@
 
                 FOR circ IN circ_items; %]
                     <tr>
+			<td align="center" style="text-align:center;">
+				<input type="checkbox" name="circ_id" value="[% circ.circ.id %]" />
+			</td>
                         <td>
                             <a href="[% mkurl(ctx.opac_root _ '/record/' _ 
                                 circ.circ.target_copy.call_number.record.id, {}, 1) %]"
@@ -164,6 +193,7 @@
                         </td>
                         <td>[% circ.circ.target_copy.barcode | html %]</td>
                         <td>[% circ.circ.target_copy.call_number.label | html %]</td>
+        </form>
                     </tr>
                 [% END %]
             </tbody>
diff --git a/docs/RELEASE_NOTES_NEXT/OPAC/edit_circ_history b/docs/RELEASE_NOTES_NEXT/OPAC/edit_circ_history
new file mode 100644
index 0000000..ea4c60c
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/OPAC/edit_circ_history
@@ -0,0 +1,10 @@
+Editable Borrowing History
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+You can delete titles that you do not wish to appear in your Check Out History. 
+
+ * In "My Account", click on the "Items Checked Out" tab, then the "Check Out History" sub-tab.
+ * Check off the items you wish to conceal.
+ * Click the Go button next to the "Delete Selected Titles" drop-down box.
+ * Click OK in the pop-up to confirm your deletion.  Choose carefully, as there is no "undo".
+
+Deleted titles will also not appear in the downloaded CSV file.

-----------------------------------------------------------------------

Summary of changes:
 .../src/perlmods/lib/OpenILS/Application/Actor.pm  |  379 ++++++++++----------
 .../lib/OpenILS/WWW/EGCatLoader/Account.pm         |  292 ++++++++-------
 .../src/templates/opac/myopac/circ_history.tt2     |  104 ++++--
 docs/RELEASE_NOTES_NEXT/OPAC/edit_circ_history     |   10 +
 4 files changed, 428 insertions(+), 357 deletions(-)
 create mode 100644 docs/RELEASE_NOTES_NEXT/OPAC/edit_circ_history


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list