Quipu Online Account Renewal - Squashed
authorTerran McCanna <tmccanna@georgialibraries.org>
Thu, 5 Aug 2021 22:36:17 +0000 (18:36 -0400)
committerChris Sharp <csharp@georgialibraries.org>
Mon, 12 Dec 2022 15:26:00 +0000 (10:26 -0500)
Online Renewal - Start of working branch

- Creates placeholders for new English & Spanish pages
- Adds ability for those pages to load
- Create div on My Account main page & prefs page to hold renewal message or button
- Adds code to check whether or not patron is eligible to renew online or not:
* patron has not already had one temporary renewal
* patron account is still active
* patron account expiration date is no more than 30 days in the future
* patron account is not barred
* patron account does not have a staff-added blocking alert
* patron does not owe any fines
* patron is not in collections (even if patron pays fines, staff still need
to remove collections note)
* patron is in one of these perm groups: Patron (2), Friend (14), GLS (56),
Homebound (53), Trustee (22), Quipu (64), Digital Only (60)
* patron has a valid billing address
* patron has a valid day phone

NOTE: New standing penalty needs to be created called PATRON_TEMP_RENEWAL.
It should display a staff alert and have the label "Patron was given a 30-day temporary account renewal. Please archive this message after the account is fully renewed." It should not create any type of block on its own. The ID of
the new standing penalty needs to be updated in the Account.pm file.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Add standing penalty

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal: Flesh out patron info in API

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Create new API instead of piggybacking on vital_stats

New api: open-ils.actor.user.opac.renewal

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Create page to hold embedded form

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - First stab at adding erenew to Ecard.pm

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
typo fix

Signed-off-by: Chris Sharp <csharp@georgialibraries.org>
further typo fix

Signed-off-by: Chris Sharp <csharp@georgialibraries.org>
even further typo fix

Signed-off-by: Chris Sharp <csharp@georgialibraries.org>
even FURTHER typo fix

Signed-off-by: Chris Sharp <csharp@georgialibraries.org>
declare the variable, and update it if needed

Signed-off-by: Chris Sharp <csharp@georgialibraries.org>
declare the variable once, then update the values

Signed-off-by: Chris Sharp <csharp@georgialibraries.org>
Online Renewal - Remove old subroutines we don't use

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Add page routing to EGCatLoader

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Retrieve patron then update fields to push back

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Exceptions for temp renewal

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Fix msg declaration error

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Get URL path in a different way

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - fix typos

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Progress on writing quipu into to db

Still to do:
* Actor.pm - failing on standing penalties line 597
* sub update_addresses - creating separate addresses works if mailing & billing are different,
   but it is not checking the right checkbox
* writing new home ou is failing on terran-test, but should work on pines data
* after update, opac page doesn't refresh
* if this is a temporary (30 day) renewal, need to pass message to quipu telling patron to come to the library
* if temp renewal, need to add alert to patron account to inform staff to get proof of identity to do full renewal
* need to test voter registration survey on pines test server since I don't have that on my test server

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Show Updated Expire Date

Without this, the page loads the initial patron expiration date
and continues to show the button to renew the account.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Document which patron groups are eligible in code

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Now saving and responding okay

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
add column to permission.grp_tree to account for e-renew

Online Renewal - tweak SQL

- Parentheses on first SQL generated error.
- Set erenew default to FALSE instead of TRUE.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - See & update permission group setting through staff client

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Tweak new standing penalty

The ID of the standing penalty has to be under 100 to prevent
staff from manually adding it to patron accounts through the
client interface.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Add Standing Penalty when Temp Renewal

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Use standing penalty names instead of IDs

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - add temp renewal flag to quipu response

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Remove perm group ID references

Look up permission groups by name or by e-renewal eligibility flag
instead of by specific permission group ID.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Got surveys working

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Progress on updating addresses

(still issues with checkmarks when changing from 1 to 2
addresses or from 2 to 1 address)

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Got address changes to save in the right way

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - add date to quipu name keyword entry

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Add check for valid mailing address

Only allow renewal option if neither mailing nor billing
addresses have been marked invalid.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Cleanup

- Get rid of subroutine I didn't end up using
- Make sure a user is logged in before showing the renewal form.

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
Online Renewal - Prevent user from re-submitting renewal after complete

Signed-off-by: Terran McCanna <tmccanna@georgialibraries.org>
15 files changed:
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/eg2/src/app/staff/admin/server/perm-group-tree.component.html
Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/permission.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Account.pm
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Ecard.pm
Open-ILS/src/sql/Pg/006.schema.permissions.sql
Open-ILS/src/sql/Pg/950.data.seed-values.sql
Open-ILS/src/sql/Pg/upgrade/XXXX-quipu-standing_penalty.sql [new file with mode: 0644]
Open-ILS/src/sql/Pg/upgrade/XXXX.schema.erenew_column_pgt.sql [new file with mode: 0644]
Open-ILS/src/templates-bootstrap/opac/myopac/main.tt2
Open-ILS/src/templates-bootstrap/opac/myopac/prefs.tt2
Open-ILS/src/templates-bootstrap/opac/renew-account-sp.tt2 [new file with mode: 0644]
Open-ILS/src/templates-bootstrap/opac/renew-account.tt2 [new file with mode: 0644]

index ee7b13e..e62eb22 100644 (file)
@@ -8402,6 +8402,7 @@ SELECT  usr,
                        <field reporter:label="Required Permission" name="application_perm" reporter:datatype="text"/>
                        <field reporter:label="Is User Group" name="usergroup" reporter:datatype="bool"/>
                        <field reporter:label="Hold Priority" name="hold_priority" reporter:datatype="int"/>
+                       <field reporter:label="E-renew?" name="erenew" reporter:datatype="bool"/>
                </fields>
                <links>
                        <link field="parent" reltype="has_a" key="id" map="" class="pgt"/>
index fa9fc42..60ce9f6 100644 (file)
                 {{selected.callerData.usergroup() === 't'}}
               </div>
             </div>
+            <div class="row">
+              <div class="col-lg-4">
+                <label i18n>Online Account Renewal Allowed?: </label>
+              </div>
+              <div class="col-lg-8 font-weight-bold">
+                {{selected.callerData.erenew() == 't'}}
+              </div>
+            </div>
           </ng-template>
         </ngb-tab>
         <ngb-tab title="Group Permissions" i18n-title id="perm">
index 56df630..f808e66 100644 (file)
@@ -2059,6 +2059,69 @@ sub user_opac_vitals {
     };
 }
 
+# PINES ECARD RENEWAL INFO API
+__PACKAGE__->register_method(
+    method        => "user_opac_renewal",
+    api_name      => "open-ils.actor.user.opac.renewal",
+    argc          => 1,
+    authoritative => 1,
+    signature     => {
+        desc   => 'Returns minimal patron info for 3rd party renewal',
+        params => [
+            {desc => 'Authentication token',                          type => 'string'},
+            {desc => 'Optional User ID, for use in the staff client', type => 'number'}  # number?
+        ],
+        return => {
+            desc => "A user object."
+        }
+    }
+);
+
+sub user_opac_renewal {
+    my( $self, $client, $auth, $user_id ) = @_;
+
+    my $e = new_editor(authtoken=>$auth);
+    return $e->event unless $e->checkauth;
+
+    $user_id ||= $e->requestor->id;
+
+    my $user = $e->retrieve_actor_user([ $user_id, {
+        flesh => 1,
+        flesh_fields => {
+            au => ['card', 'billing_address', 'mailing_address']
+        }
+        }]);
+
+    return {
+        user => {
+            first_given_name  => $user->first_given_name,
+            second_given_name => $user->second_given_name,
+            family_name       => $user->family_name,
+            pref_first_given_name => $user->pref_first_given_name,
+            pref_second_given_name => $user->pref_second_given_name,
+            pref_family_name  => $user->pref_family_name,
+            day_phone         => $user->day_phone,
+            email             => $user->email,
+            home_ou           => $user->home_ou,
+            barcode           => $user->card->barcode,
+            physical_street1  => $user->billing_address->street1,
+            physical_street2  => $user->billing_address->street2,
+            physical_city     => $user->billing_address->city,
+            physical_post_code => $user->billing_address->post_code,
+            physical_county   => $user->billing_address->county,
+            physical_state    => $user->billing_address->state,
+            physical_country  => $user->billing_address->country,
+            mailing_street1   => $user->mailing_address->street1,
+            mailing_street2   => $user->mailing_address->street2,
+            mailing_city      => $user->mailing_address->city,
+            mailing_post_code => $user->mailing_address->post_code,
+            mailing_county    => $user->mailing_address->county,
+            mailing_state     => $user->mailing_address->state,
+            mailing_country   => $user->mailing_address->country
+        }
+    };
+}
+
 
 ##### a small consolidation of related method registrations
 my $common_params = [
index 7c7cab6..af9ada5 100644 (file)
@@ -16,7 +16,7 @@ use base qw/permission/;
 __PACKAGE__->table('permission_grp_tree');
 __PACKAGE__->columns(Primary => qw/id/);
 __PACKAGE__->columns(Essential => qw/name parent description perm_interval
-                     application_perm usergroup hold_priority/);
+                     application_perm usergroup hold_priority erenew/);
 #-------------------------------------------------------------------------------
 package permission::usr_grp_map;
 use base qw/permission/;
index d0a2d8a..55376ab 100644 (file)
@@ -186,10 +186,11 @@ sub load {
 
     $self->load_simple("myopac") if $path =~ m:opac/myopac:; # A default page for myopac parts
 
-    # maybe make these optional parts of load_patron_reg?
-    #return $self->load_ecard_form if $path =~ m|opac/ecard/form|;
+    # PINES - online account registration
     return $self->load_ecard_submit if $path =~ m|opac/ecard/submit|;
-    return $self->load_ecard_verify if $path =~ m|opac/ecard/verify|;
+
+    # PINES - online account renewal
+    return $self->load_simple("renew-account") if $path =~ m|opac/renew-account|;
 
     if($path =~ m|opac/login|) {
         return $self->load_login unless $self->editor->requestor; # already logged in?
index 8032aeb..786a912 100644 (file)
@@ -120,6 +120,19 @@ sub load_myopac_prefs {
     $self->prepare_extended_user_info;
     my $user = $self->ctx->{user};
 
+    # PINES - check whether or not to provide account renewal link
+    if ($self->ctx->{user}->billing_address) {
+        $self->ctx->{valid_billing_address} = $self->ctx->{user}->billing_address->valid;
+    } else {
+        $self->ctx->{valid_billing_address} = 0;
+    }
+    if ($self->ctx->{user}->mailing_address) {
+        $self->ctx->{valid_mailing_address} = $self->ctx->{user}->mailing_address->valid;
+    } else {
+        $self->ctx->{valid_mailing_address} = 0;
+    }
+    $self->check_account_exp();
+
     my $lock_usernames = $self->ctx->{get_org_setting}->($e->requestor->home_ou, 'opac.lock_usernames');
     if(defined($lock_usernames) and $lock_usernames == 1) {
         # Policy says no username changes
@@ -189,7 +202,6 @@ sub load_myopac_prefs_notify {
     my $self = shift;
     my $e = $self->editor;
 
-
     my $stat = $self->_load_user_with_prefs;
     return $stat if $stat;
 
@@ -2645,6 +2657,22 @@ sub load_myopac_main {
             pub => 't'
         })
     );
+
+    # PINES - need to make sure we're retrieving current info
+    $self->prepare_extended_user_info;
+    # PINES - check whether or not to provide account renewal link
+    if ($self->ctx->{user}->billing_address) {
+        $self->ctx->{valid_billing_address} = $self->editor->retrieve_actor_user_address($self->ctx->{user}->billing_address)->valid;
+    } else {
+        $self->ctx->{valid_billing_address} = 0;
+    }
+    if ($self->ctx->{user}->mailing_address) {
+        $self->ctx->{valid_mailing_address} = $self->editor->retrieve_actor_user_address($self->ctx->{user}->mailing_address)->valid;
+    } else {
+        $self->ctx->{valid_mailing_address} = 0;
+    }
+    $self->check_account_exp();
+
     return $self->prepare_fines($limit, $offset) || Apache2::Const::OK;
 }
 
@@ -3537,4 +3565,144 @@ sub load_password_reset {
     return Apache2::Const::OK;
 }
 
+# PINES - check whether patron has standing penalties that should block
+# online account renewal
+sub has_penalties {
+    my $self = shift;
+    my $ctx = $self->ctx;
+    my $user = $self->ctx->{user};
+    my $e = new_editor(xact => 1);
+    
+    #I'm sure there is a way to combine the following standing penalty checks, but this is working for now
+
+    #check for INVALID_PATRON_ADDRESS
+    my $findpenalty_address = $e->search_config_standing_penalty({name => 'INVALID_PATRON_ADDRESS'})->[0];
+    my $searchpenalty_address = $e->search_actor_user_standing_penalty({
+        usr => $user->id,
+        standing_penalty => $findpenalty_address->id,
+        '-or' => [
+            {stop_date => undef},
+            {stop_date => {'>' => 'now'}}
+        ]
+    });
+
+    #check for INVALID_PATRON_DAY_PHONE
+    my $findpenalty_phone = $e->search_config_standing_penalty({name => 'INVALID_PATRON_DAY_PHONE'})->[0];
+    my $searchpenalty_phone = $e->search_actor_user_standing_penalty({
+        usr => $user->id,
+        standing_penalty => $findpenalty_phone->id,
+        '-or' => [
+            {stop_date => undef},
+            {stop_date => {'>' => 'now'}}
+        ]
+    });
+
+    #check for PATRON_IN_COLLECTIONS
+    my $findpenalty_coll = $e->search_config_standing_penalty({name => 'PATRON_IN_COLLECTIONS'})->[0];
+    my $searchpenalty_coll = $e->search_actor_user_standing_penalty({
+        usr => $user->id,
+        standing_penalty => $findpenalty_coll->id,
+        '-or' => [
+            {stop_date => undef},
+            {stop_date => {'>' => 'now'}}
+        ]
+    });
+
+    #check for alerting block
+    my $findpenalty_alertblock = $e->search_config_standing_penalty({name => 'STAFF_CHR'})->[0];
+    my $searchpenalty_alertblock = $e->search_actor_user_standing_penalty({
+        usr => $user->id,
+        standing_penalty => $findpenalty_alertblock->id,
+        '-or' => [
+            {stop_date => undef},
+            {stop_date => {'>' => 'now'}}
+        ]
+    });
+
+    #check for PATRON_TEMP_RENEWAL
+    my $findpenalty_temp = $e->search_config_standing_penalty({name => 'PATRON_TEMP_RENEWAL'})->[0];
+    my $searchpenalty_temp = $e->search_actor_user_standing_penalty({
+        usr => $user->id,
+        standing_penalty => $findpenalty_temp->id,
+        '-or' => [
+            {stop_date => undef},
+            {stop_date => {'>' => 'now'}}
+        ]
+    });
+
+    if (@$searchpenalty_address || @$searchpenalty_coll || @$searchpenalty_phone || @$searchpenalty_alertblock) {
+        $ctx->{haspenalty} = 1;
+    } else {
+        $ctx->{haspenalty} = 0;
+    }
+
+    if (@$searchpenalty_temp) {
+        $ctx->{hastemprenew} = 1;
+    } else {
+        $ctx->{hastemprenew} = 0;
+    }
+
+    return;
+}
+
+# PINES - check whether or not to show account renewal link
+sub check_account_exp {
+    my $self = shift;
+    my $ctx = $self->ctx;
+    $self->update_dashboard_stats();
+
+    #make sure patron is in an eligible perm group for renewal
+    my $grp = new_editor()->retrieve_permission_grp_tree($ctx->{user}->profile);
+
+    if ($grp->erenew eq 't') {
+        $ctx->{eligible_permgroup} = 1;
+    } else {
+        $ctx->{eligible_permgroup} = 0;
+    }
+
+    #check for various standing penalties that would block an online renewal
+    $self->has_penalties();
+
+    #check for other problems that would block an online renewal
+    if ($ctx->{user}->active ne 't') { #user is no longer active
+        $ctx->{hasproblem} = 1;
+    } elsif ($ctx->{haspenalty} eq 1) { #user has a standing penalty block
+        $ctx->{hasproblem} = 1;
+    } elsif ($ctx->{user}->barred eq 't') { #user is barred
+        $ctx->{hasproblem} = 1;
+    } elsif ($ctx->{valid_billing_address} ne 't') { #user has invalid billing address
+        $ctx->{hasproblem} = 1;
+    } elsif ($ctx->{valid_mailing_address} ne 't') { #user has invalid mailing address
+        $ctx->{hasproblem} = 1;
+    } else {
+        $ctx->{hasproblem} = 0;
+    }
+
+    #determine which message to show (if any)
+    my $cache = OpenSRF::Utils::Cache->new('global');
+    $cache->put_cache('account_renew_ok','false',3600);
+
+    if ($ctx->{hastemprenew} eq 1) { #user already has active temp renewal
+        $ctx->{account_renew_message} = '<div style="border:2px solid green;padding:5px;">Your account
+        could only be temporarily renewed because your address changed. Please visit your nearest PINES
+        library with your current proof of address to complete your account renewal.</div>';
+    } elsif (DateTime->today->add(days=>30) lt $ctx->{user}->expire_date) {
+        #expiration date is too far in future - don't show message
+        $ctx->{account_renew_message} = '';
+    } elsif ($ctx->{hasproblem} eq 1 or $ctx->{eligible_permgroup} eq 0) { #see other problems above
+        $ctx->{account_renew_message} = '<div style="border:2px solid green;padding:5px;">Your account is
+        due for renewal, but it cannot be renewed online. Please visit your nearest PINES
+        library with your current ID and proof of address to update and renew your account.</div>';
+    } elsif ($ctx->{user_stats}->{fines}->{balance_owed} gt 0) { #user has fines
+        $ctx->{account_renew_message} = '<div style="border:2px solid green;padding:5px;">Your account
+        is due for renewal. Please pay your outstanding fines in order to renew your account.</div>';
+    } else {
+        $ctx->{account_renew_message} = '<span class="light_border"><a class="btn btn-sm btn-action"
+        href="/eg/opac/renew-account"><i class="fas fa-user-cog"></i>Click here to renew your account</a></span>';
+        $cache->put_cache('account_renew_ok','true',3600);
+    }
+
+    return 1;
+}
+
 1;
index f35c448..e903e90 100644 (file)
@@ -5,6 +5,7 @@ use OpenSRF::Utils::Logger qw/$logger/;
 use OpenSRF::Utils::JSON;
 use OpenSRF::Utils qw/:datetime/;
 use OpenILS::Utils::Fieldmapper;
+use OpenSRF::Utils::Cache;
 use OpenILS::Application::AppUtils;
 use OpenILS::Utils::CStoreEditor qw/:funcs/;
 use OpenILS::Event;
@@ -15,7 +16,39 @@ use Digest::MD5 qw(md5_hex);
 $Data::Dumper::Indent = 0;
 my $U = 'OpenILS::Application::AppUtils';
 
-my @api_fields = (
+my $update_type = 'register';
+
+my @api_fields_renew = (
+    {name => 'vendor_username', required => 1},
+    {name => 'vendor_password', required => 1},
+    {name => 'email', class => 'au'},
+    {name => 'day_phone', class => 'au', required => 1},
+    {name => 'home_ou', class => 'au'},
+    {name => 'pref_first_given_name', class => 'au'},
+    {name => 'pref_second_given_name', class => 'au'},
+    {name => 'pref_family_name', class => 'au'},
+    {name => 'physical_id', class => 'aua'},
+    {name => 'physical_street1', class => 'aua'},
+    {name => 'physical_street1_name'},
+    {name => 'physical_street2', class => 'aua'},
+    {name => 'physical_city', class => 'aua'},
+    {name => 'physical_post_code', class => 'aua'},
+    {name => 'physical_county', class => 'aua'},
+    {name => 'physical_state', class => 'aua'},
+    {name => 'physical_country', class => 'aua'},
+    {name => 'mailing_id', class => 'aua'},
+    {name => 'mailing_street1', class => 'aua'},
+    {name => 'mailing_street1_name'},
+    {name => 'mailing_street2', class => 'aua'},
+    {name => 'mailing_city', class => 'aua'},
+    {name => 'mailing_post_code', class => 'aua'},
+    {name => 'mailing_county', class => 'aua'},
+    {name => 'mailing_state', class => 'aua'},
+    {name => 'mailing_country', class => 'aua'},
+    {name => 'voter_registration', class => 'asvr'}
+);
+
+my @api_fields_register = (
     {name => 'vendor_username', required => 1},
     {name => 'vendor_password', required => 1},
     {name => 'first_given_name', class => 'au', required => 1},
@@ -30,9 +63,9 @@ my @api_fields = (
     {name => 'ident_type', class => 'au', required => 1},
     {name => 'ident_value', class => 'au', required => 1},
     {name => 'ident_value2',
-     class => 'au', 
-     notes => "AKA parent/guardian",
-     required_if => 'Patron is less than 18 years old'
+         class => 'au', 
+         notes => "AKA parent/guardian",
+         required_if => 'Patron is less than 18 years old'
     },
     {name => 'pref_first_given_name', class => 'au'},
     {name => 'pref_second_given_name', class => 'au'},
@@ -58,99 +91,6 @@ my @api_fields = (
     {name => 'in_house_registration', required => 1},
 );
 
-
-# TODO: wrap the following in a check for a library setting as to whether or not
-# to require emailed verification
-
-## Random 6-character alpha-numeric code that avoids look-alike characters
-## https://ux.stackexchange.com/questions/53341/are-there-any-letters-numbers-that-should-be-avoided-in-an-id
-## Also exclude vowels to avoid creating any real (potentially offensive) words.
-#my @code_chars = ('C','D','F','H','J'..'N','P','R','T','V','W','X','3','4','7','9');
-#sub generate_verify_code {
-#    my $string = '';
-#    $string .= $code_chars[rand @code_chars] for 1..6;
-#    return $string;
-#}
-#
-#
-## only if we're verifying the card via email
-#sub load_ecard_verify {
-#    my $self = shift;
-#    my $cgi = $self->cgi;
-#    $self->collect_header_footer;
-#
-#    # Loading the form.
-#    return Apache2::Const::OK if $cgi->request_method eq 'GET';
-#
-#    #$self->verify_ecard;
-#    return Apache2::Const::OK;
-#}
-#
-#sub verify_ecard {
-#    my $self = shift;
-#    my $cgi = $self->cgi;
-#    my $ctx = $self->ctx;
-#    $self->log_params;
-#
-#    my $verify_code = $ctx->{verify_code} = $cgi->param('verification_code');
-#    my $barcode = $ctx->{barcode} = $cgi->param('barcode');
-#
-#    $ctx->{verify_failed} = 1;
-#
-#    my $e = new_editor();
-#
-#    my $au = $e->search_actor_user({
-#        profile => $PROVISIONAL_ECARD_GRP,
-#        ident_type => $ECARD_VERIFY_IDENT,
-#        ident_value => $verify_code
-#    })->[0];
-#
-#    if (!$au) {
-#        $logger->warn(
-#            "ECARD: No provisional ecard found with code $verify_code");
-#        sleep 2; # Mitigate brute-force attacks
-#        return;
-#    }
-#
-#    my $card = $e->search_actor_card({
-#        usr => $au->id,
-#        barcode => $barcode
-#    })->[0];
-#
-#    if (!$card) {
-#        $logger->warn("ECARD: Failed to match verify code ".
-#            "($verify_code) with provided barcode ($barcode)");
-#        sleep 2; # Mitigate brute-force attacks
-#        return;
-#    }
-#
-#    # Verification looks good.  Update the account.
-#
-#    my $grp = new_editor()->retrieve_permission_grp_tree($FULL_ECARD_GRP);
-#
-#    $au->profile($grp->id);
-#    $au->expire_date(
-#        DateTime->now(time_zone => 'local')->add(
-#            seconds => interval_to_seconds($grp->perm_interval))->iso8601()
-#    );
-#
-#    $e->xact_begin;
-#
-#    unless ($e->update_actor_user($au)) {
-#        $logger->error("ECARD update failed for $barcode: " . $e->die_event);
-#        return;
-#    }
-#    
-#    $e->commit;
-#    $logger->info("ECARD: Update to full ecard succeeded for $barcode");
-#
-#    $ctx->{verify_success} = 1;
-#    $ctx->{verify_failed} = 0;
-#
-#    return;
-#}
-
-
 sub log_params {
     my $self = shift;
     my $cgi = $self->cgi;
@@ -172,7 +112,7 @@ sub handle_testmode_api {
 
     # Strip data we don't want to publish.
     my @doc_fields;
-    for my $field_info (@api_fields) {
+    for my $field_info (@api_fields_register) {
         my $doc_info = {};
         for my $info_key (keys %$field_info) {
             $doc_info->{$info_key} = $field_info->{$info_key} 
@@ -183,6 +123,7 @@ sub handle_testmode_api {
 
     $ctx->{response}->{messages} = [fields => \@doc_fields];
     $ctx->{response}->{status} = 'API_OK';
+
     return $self->compile_response;
 }
 
@@ -202,6 +143,7 @@ sub handle_datamode_api {
     }
 
     $ctx->{response}->{status} = 'DATA_OK';
+
     return $self->compile_response;
 }
 
@@ -210,6 +152,23 @@ sub load_ecard_submit {
     my $ctx = $self->ctx;
     my $cgi = $self->cgi;
 
+    #determine whether this is a new registration or a renewal
+    if ($cgi->param('patron_id') > 1) {
+        $update_type = 'renew';
+    } else {
+        $update_type = 'register';
+    }
+
+    #If this is a renewal, double-check that they are eligible to renew
+    my $cache = OpenSRF::Utils::Cache->new('global');
+    if ($update_type eq 'renew') {
+        if ($cache->get_cache("account_renew_ok") && $cache->get_cache("account_renew_ok") eq 'true') {
+        } else {
+            $logger->error("ERENEW - User not in correct status to renew account");
+            return $self->compile_response;
+        }
+    }
+
     $self->log_params;
 
     my $testmode = $cgi->param('testmode') || '';
@@ -237,20 +196,53 @@ sub load_ecard_submit {
     return $self->handle_testmode_api if $testmode eq 'API';
     return $self->handle_datamode_api($datamode) if $datamode;
 
-    return $self->compile_response unless $self->make_user;
-    return $self->compile_response unless $self->add_addresses;
-    return $self->compile_response unless $self->check_dupes;
-    return $self->compile_response unless $self->add_card;
-    return $self->compile_response unless $self->add_survey_responses;
-    return $self->compile_response unless $self->save_user;
-    return $self->compile_response unless $self->add_usr_settings;
-    return $self->compile_response if $ctx->{response}->{status};
-
-    $U->create_events_for_hook(
-        'au.create.ecard', $ctx->{user}, $ctx->{user}->home_ou);
+    # Accommodate reg vs renew
+    if ($update_type eq 'register') {
+        return $self->compile_response unless $self->make_user;
+        return $self->compile_response unless $self->add_addresses;
+        return $self->compile_response unless $self->check_dupes;
+        return $self->compile_response unless $self->add_card;
+        return $self->compile_response unless $self->add_survey_responses;
+        return $self->compile_response unless $self->save_user;
+        return $self->compile_response unless $self->add_usr_settings;
+        return $self->compile_response if $ctx->{response}->{status};
+
+        $U->create_events_for_hook(
+            'au.create.ecard', $ctx->{user}, $ctx->{user}->home_ou);
+    } else {
+        return $self->compile_response unless $self->update_user;
+        return $self->compile_response unless $self->update_addresses;
+        return $self->compile_response unless $self->add_survey_responses;
+        return $self->compile_response unless $self->save_user;
+        return $self->compile_response if $ctx->{response}->{status};
+    }
 
+    # Add extra info to response message
     $ctx->{response}->{status} = 'OK';
-    $ctx->{response}->{barcode} = $ctx->{user}->card->barcode;
+
+    if ($update_type eq 'renew') {
+        #New expiration date
+        $ctx->{response}->{expire_date} = $ctx->{user}->expire_date;
+        #Mark whether this is a temporary renewal or not
+        my $findpenalty_temp = $e->search_config_standing_penalty({name => 'PATRON_TEMP_RENEWAL'})->[0];
+        my $searchpenalty_temp = $e->search_actor_user_standing_penalty({
+            usr => $cgi->param('patron_id'),
+            standing_penalty => $findpenalty_temp->id,
+            '-or' => [
+                {stop_date => undef},
+                {stop_date => {'>' => 'now'}}
+            ]
+        });
+        if (@$searchpenalty_temp) {
+            $ctx->{response}->{temp_renew} = 1;
+        } else {
+            $ctx->{response}->{temp_renew} = 0;
+        }
+        #set renewal flag in cache to false to prevent user from refreshing the page and submitting again
+        $cache->put_cache('account_renew_ok','false',3600);
+    } else {
+        $ctx->{response}->{barcode} = $ctx->{user}->card->barcode;
+       }
 
     return $self->compile_response;
 }
@@ -292,28 +284,18 @@ sub verify_vendor_host {
     return 1;
 }
 
-
 sub compile_response {
     my $self = shift;
     my $ctx = $self->ctx;
+
     $self->apache->content_type("application/json; charset=utf-8");
     $ctx->{response} = OpenSRF::Utils::JSON->perl2JSON($ctx->{response});
     $logger->info("ECARD responding with " . $ctx->{response});
-    return Apache2::Const::OK;
-}
 
-my %keep_case = (usrname => 1, passwd => 1, email => 1);
-sub upperclense {
-    my $self = shift;
-    my $field = shift;
-    my $value = shift;
-    $value = uc($value) unless $keep_case{$field};
-    $value = lc($value) if $field eq 'email'; # force it
-    $value =~ s/(^\s*|\s*$)//g;
-    return $value;
+    return Apache2::Const::OK;
 }
 
-# Create actor.usr perl object and populate column data
+# Create actor.usr perl object and populate column data (for new registration)
 sub make_user {
     my $self = shift;
     my $ctx = $self->ctx;
@@ -325,6 +307,7 @@ sub make_user {
     $au->isnew(1);
     $au->net_access_level(1); # Filtered
     $au->name_keywords($in_house ? 'quipu_inhouse' : 'quipu_remote');
+
     my $home_ou = $cgi->param('home_ou');
 
     my $perm_grp = $U->ou_ancestor_setting_value(
@@ -340,7 +323,7 @@ sub make_user {
             seconds => interval_to_seconds($grp->perm_interval))->iso8601()
     );
 
-    for my $field_info (@api_fields) {
+    for my $field_info (@api_fields_register) {
         my $field = $field_info->{name};
         next unless $field_info->{class} eq 'au';
 
@@ -358,6 +341,7 @@ sub make_user {
 
         $val = undef if $field eq 'day_phone' && $val eq '--';
         $self->verify_dob($val) if $field eq 'dob' && $val;
+
         $au->$field($val);
     }
 
@@ -366,6 +350,84 @@ sub make_user {
     return $ctx->{user} = $au;
 }
 
+# If existing account, update instead of create
+sub update_user {
+
+    my $self = shift;
+    my @extra_flesh = @_;
+    my $e = $self->editor;
+    my $ctx = $self->ctx;
+    my $cgi = $self->cgi;
+
+    # Grab user id, retrieve patron info from db and create patron object
+    my $patron_id = $cgi->param('patron_id');
+
+    my $au = $self->editor->retrieve_actor_user([$patron_id, 
+        {
+            flesh => 1,
+            flesh_fields => {
+                au => ['billing_address', 'mailing_address', 'groups', 'permissions', 'standing_penalties']
+            }
+        }
+    ]);
+    #indicate that this is an update, not a new record
+    $au->isnew(0);
+    
+    # Replace values in patron object with new data
+
+    # Need to append new keyword for use in reports later
+    my $orig_kw = $au->name_keywords;
+    my $dt = DateTime->now;
+    my $dty = $dt->year;
+    my $dtm = $dt->month;
+    if ($orig_kw ne '') {
+        $au->name_keywords("$orig_kw quipu_renew_$dty$dtm");
+    } else {
+        $au->name_keywords("quipu_renew_$dty$dtm");
+    }
+
+    # Temp renewal is only 30 days, otherwise use perm_interval
+    # If perm group is Homebound or GLS, allow full renewal
+    my $temp_renewal = $cgi->param('temp_renewal');
+    my $grp = new_editor()->retrieve_permission_grp_tree($au->profile);
+
+    if ($temp_renewal eq '1' && $grp->name ne 'GLS' && $grp->name ne 'Homebound') {
+        $au->expire_date(
+            DateTime->now(time_zone => 'local')->add(
+                seconds => interval_to_seconds('30 days'))->iso8601()
+        );
+        # Add temp renewal standing penalty to account
+        $self->apply_temp_renewal_penalty;
+    } else {
+        $au->expire_date(
+            DateTime->now(time_zone => 'local')->add(
+                seconds => interval_to_seconds($grp->perm_interval))->iso8601()
+        );
+    }
+
+    # loop through fields submitted by quipu
+    for my $field_info (@api_fields_renew) {
+        my $field = $field_info->{name};
+        next unless $field_info->{class} eq 'au';
+
+        my $val = $cgi->param($field);
+
+        if ($field_info->{required} && !$val) {
+            my $msg = "Value required for field: '$field'";
+            $ctx->{response}->{status} = 'INVALID_PARAMS';
+            push(@{$ctx->{response}->{messages}}, $msg);
+            $logger->error("E-RENEW $msg");
+        }
+
+        $val = undef if $field eq 'day_phone' && $val eq '--';
+        $val = $au->home_ou if $field eq 'home_ou' && $val eq '';
+
+        $au->$field($val);
+    }
+
+    return $ctx->{user} = $au;
+}
+
 # Card generation must occur after the user is saved in the DB.
 sub add_card {
     my $self = shift;
@@ -447,16 +509,6 @@ sub verify_dob {
     return 1;
 }
 
-# returns true if the addresses contain all of the same values.
-sub addrs_match {
-    my ($self, $addr1, $addr2) = @_;
-    for my $field ($addr1->real_fields) {
-        return 0 if ($addr1->$field() || '') ne ($addr2->$field() || '');
-    }
-    return 1;
-}
-
-
 sub add_addresses {
     my $self = shift;
     my $cgi = $self->cgi;
@@ -484,7 +536,7 @@ sub add_addresses {
 
     # Confirm we have values for all of the required fields.
     # Apply values to our in-progress address object.
-    for my $field_info (@api_fields) {
+    for my $field_info (@api_fields_register) {
         my $field = $field_info->{name};
         next unless $field =~ /physical|mailing/;
         next if $field =~ /street1_/;
@@ -518,6 +570,90 @@ sub add_addresses {
     return 1;
 }
 
+sub update_addresses {
+    my $self = shift;
+    my $cgi = $self->cgi;
+    my $ctx = $self->ctx;
+    my $e = $ctx->{editor};
+    my $user = $ctx->{user};
+
+    my $physical_addr = Fieldmapper::actor::user_address->new;
+    $physical_addr->id($user->billing_address->id);
+    $physical_addr->usr($user->id);
+    $physical_addr->address_type('PHYSICAL');
+    $physical_addr->within_city_limits($user->billing_address->within_city_limits);
+    $physical_addr->valid('t');
+    $physical_addr->pending('f');
+
+    my $mailing_addr = Fieldmapper::actor::user_address->new;
+    $mailing_addr->id($user->mailing_address->id);
+    $mailing_addr->usr($user->id);
+    $mailing_addr->address_type('MAILING');
+    $mailing_addr->within_city_limits($user->mailing_address->within_city_limits);
+    $mailing_addr->valid('t');
+    $mailing_addr->pending('f');
+
+    # Confirm we have values for all of the required fields.
+    # Apply values to our in-progress address object.
+    for my $field_info (@api_fields_renew) {
+        my $field = $field_info->{name};
+        next unless $field =~ /physical|mailing/;
+        next if $field =~ /street1_/;
+
+        my $val = $cgi->param($field);
+
+        if ($field_info->{required} && !$val) {
+            my $msg = "Value required for field: '$field'";
+            $ctx->{response}->{status} = 'INVALID_PARAMS';
+            push(@{$ctx->{response}->{messages}}, $msg);
+            $logger->error("E-RENEW $msg");
+        }
+
+        if ($field =~ /physical/) {
+            (my $col_field = $field) =~ s/physical_//g;
+            $physical_addr->$col_field($val) if $val;
+        } else {
+            (my $col_field = $field) =~ s/mailing_//g;
+            $mailing_addr->$col_field($val) if $val;
+        }
+    }
+
+    # Determine what exactly to do with addresses
+    if ($physical_addr->id eq $mailing_addr->id && $physical_addr->street1 eq $mailing_addr->street1) {
+        # if one address & stays at one address, just update it (don't need to do both physical & mailing)
+        $mailing_addr->isnew(0);
+        $mailing_addr->ischanged(1);
+    } elsif ($physical_addr->id eq $mailing_addr->id && $physical_addr->street1 ne $mailing_addr->street1) {
+        # if one address splitting to two addresses, update the first and create a second address entry
+        $physical_addr->isnew(0);
+        $physical_addr->ischanged(1);
+        $mailing_addr->isnew(1);
+        $mailing_addr->id(-1);
+    } elsif ($physical_addr->id ne $mailing_addr->id && $physical_addr->street1 eq $mailing_addr->street1) {
+        # if there were previously 2 addresses, but there is only one address now, use the updated single address entry for both
+        $physical_addr->isnew(0);
+        $physical_addr->ischanged(1);
+        $mailing_addr->isnew(0);
+        $mailing_addr->ischanged(1);
+        $mailing_addr->id($physical_addr->id);
+    } else {
+        # otherwise, update existing entries
+        $physical_addr->isnew(0);
+        $physical_addr->ischanged(1);
+        $mailing_addr->isnew(0);
+        $mailing_addr->ischanged(1);
+    }
+
+    # exit if there were any errors above.
+    return undef if $ctx->{response}->{status}; 
+
+    $user->billing_address($physical_addr);
+    $user->mailing_address($mailing_addr);
+    $user->addresses([$physical_addr, $mailing_addr]);
+
+    return 1;
+}
+
 sub add_usr_settings {
     my $self = shift;
     my $cgi = $self->cgi;
@@ -542,9 +678,10 @@ sub add_survey_responses {
     my $answer = $cgi->param('voter_registration');
 
     my $survey_response = Fieldmapper::action::survey_response->new;
+
     $survey_response->id(-1);
     $survey_response->isnew(1);
-    $survey_response->survey(1); # voter registration survey
+    $survey_response->survey(1);
     $survey_response->question(1);
     $survey_response->answer($answer);
 
@@ -552,35 +689,6 @@ sub add_survey_responses {
     return 1;
 }
 
-# TODO: this is KCLS-specific, but maybe we can make it something
-# generic for adding stat cats to the patron
-
-#sub add_stat_cats {
-#    my $self = shift;
-#    my $cgi = $self->cgi;
-#    my $user = $self->ctx->{user};
-#
-#    my $ds_map = Fieldmapper::actor::stat_cat_entry_user_map->new;
-#    $ds_map->isnew(1);
-#    $ds_map->stat_cat(12);
-#    $ds_map->stat_cat_entry('KCLS');
-#
-#    my $events = $cgi->param('events_mailing');
-#    my $em_map = Fieldmapper::actor::stat_cat_entry_user_map->new;
-#    $em_map->isnew(1);
-#    $em_map->stat_cat(3);
-#    $em_map->stat_cat_entry($events ? 'Y' : 'N');
-#
-#    my $foundation = $cgi->param('foundation_mailing');
-#    my $fm_map = Fieldmapper::actor::stat_cat_entry_user_map->new;
-#    $fm_map->isnew(1);
-#    $fm_map->stat_cat(4);
-#    $fm_map->stat_cat_entry($foundation ? 'Y' : 'N');
-#
-#    $user->stat_cat_entries([$ds_map, $em_map, $fm_map]);
-#    return 1;
-#}
-
 # Returns true if no dupes found, false if dupes are found.
 sub check_dupes {
     my $self = shift;
@@ -614,41 +722,6 @@ sub check_dupes {
 
     $logger->info("ECARD found potential duplicate patrons: @$ids");
 
-#    if (my $streetname = $self->cgi->param('physical_street1_name')) {
-#        # We found matching patrons.  Perform a secondary check on the
-#        # address street name only.
-#
-#        $logger->info("ECARD secondary search on street name: $streetname");
-#
-#        my $addr_ids = $e->search_actor_user_address(
-#            {   usr => $ids,
-#                street1 => {'~*' => "(^| )$streetname( |\$)"}
-#            }, {idlist => 1}
-#        );
-#
-#        if (@$addr_ids) {
-#            # we don't really care what patrons match at this point,
-#            # only whether a match is found.
-#            $ids = [1];
-#            $logger->info("ECARD secondary address check match(es) ".
-#                "found on address(es) @$addr_ids");
-#
-#        } else {
-#            $ids = [];
-#            $logger->info(
-#                "ECARD secondary address check found no matches");
-#        }
-#
-#    } else {
-#        $ids = [];
-#        # unclear if this is a possibility -- err on the side of allowing
-#        # the registration.
-#        $logger->info("ECARD found possible patron match but skipping ".
-#            "secondary street name check -- no street name was provided");
-#    }
-#
-#    return 1 if @$ids == 0;
-
     $ctx->{response}->{status} = 'DUPLICATE';
     $ctx->{response}->{messages} = ['first_given_name', 
         'family_name', 'dob'];
@@ -661,6 +734,7 @@ sub save_user {
     my $ctx = $self->ctx;
     my $cgi = $self->cgi;
     my $user = $ctx->{user};
+    my $update_type = $user->isnew;
 
     my $resp = $U->simplereq(
         'open-ils.actor',
@@ -671,11 +745,18 @@ sub save_user {
     $resp = {textcode => 'UNKNOWN_ERROR'} unless $resp;
 
     if ($U->is_event($resp)) {
+        my $msg = '';
 
-        my $msg = "Error creating user account: " . $resp->{textcode};
-        $logger->error("ECARD: $msg");
+        if ($update_type eq '1') {
+            $msg = "Error creating user account: " . $resp->{textcode};
+            $logger->error("ECARD: $msg");
+            $ctx->{response}->{status} = 'CREATE_ERR';
+        } else {
+            $msg = "Error updating user account: " . $resp->{textcode};
+            $logger->error("E-RENEW: $msg");
+            $ctx->{response}->{status} = 'UPDATE_ERR';
+        }
 
-        $ctx->{response}->{status} = 'CREATE_ERR';
         $ctx->{response}->{messages} = [{msg => $msg, pid => $$}];
 
         return 0;
@@ -685,5 +766,48 @@ sub save_user {
     return 1;
 }
 
+sub apply_temp_renewal_penalty {
+
+    my $self = shift;
+    my $ctx = $self->ctx;
+    my $cgi = $self->cgi;
+    my $patron_id = $cgi->param('patron_id');
+
+    my $e = new_editor(xact => 1);
+    my $ptype = $e->search_config_standing_penalty({name => 'PATRON_TEMP_RENEWAL'})->[0];
+
+    my $penalty = Fieldmapper::actor::user_standing_penalty->new;
+    $penalty->usr($patron_id);
+    $penalty->org_unit(1);
+    $penalty->standing_penalty($ptype->id);
+
+    my $aum = Fieldmapper::actor::usr_message->new;
+    $aum->create_date('now');
+    $aum->sending_lib(1);
+    $aum->title('Temporary Account Renewal');
+    $aum->usr($penalty->usr);
+    $aum->message('Patron renewed online with an address change so was given a 30-day
+    temporary account renewal. Please archive this message after the address is
+    verified and the renewal date extended.');
+    $aum->pub(0);
+
+    $aum = $e->create_actor_usr_message($aum);
+    unless($aum) {
+        $e->rollback;
+        return 0;
+    }
+
+    $penalty->usr_message($aum->id);
+
+    unless($e->create_actor_user_standing_penalty($penalty)) {
+        $e->rollback;
+        return 0;
+    }
+
+    $e->commit;
+    return 1;
+}
+
+
 1;
 
index 05d38a6..c1f1622 100644 (file)
@@ -39,7 +39,8 @@ CREATE TABLE permission.grp_tree (
        perm_interval           INTERVAL DEFAULT '3 years'::interval NOT NULL,
        description             TEXT,
        application_perm        TEXT,
-       hold_priority       INT   NOT NULL DEFAULT 0
+       hold_priority       INT   NOT NULL DEFAULT 0,
+       erenew          BOOL NOT NULL DEFAULT TRUE
 );
 CREATE INDEX grp_tree_parent_idx ON permission.grp_tree (parent);
 
index 828d560..1cbbf70 100644 (file)
@@ -91,7 +91,8 @@ INSERT INTO config.standing_penalty (id, name, label, staff_alert, org_depth) VA
         TRUE,
         0
     );
-
+-- Temp renewal penalty must be under 100 to prevent staff from manually adding it through client interface
+INSERT INTO config.standing_penalty (id, name, label, staff_alert, org_depth) VALUES (90, 'PATRON_TEMP_RENEWAL', 'Patron was given a 30-day temporary account renewal. Please archive this message after the account is fully renewed.', TRUE, 0);
 
 SELECT SETVAL('config.standing_penalty_id_seq', 100);
 
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX-quipu-standing_penalty.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX-quipu-standing_penalty.sql
new file mode 100644 (file)
index 0000000..e7d82fd
--- /dev/null
@@ -0,0 +1,11 @@
+BEGIN;
+
+-- ID has to be under 100 in order to prevent it from appearing as a dropdown in the patron editor.
+
+INSERT INTO config.standing_penalty (id, name, label, staff_alert, org_depth) 
+VALUES (90, 'PATRON_TEMP_RENEWAL',
+       'Patron was given a 30-day temporary account renewal. 
+       Please archive this message after the account is fully renewed.', TRUE, 0
+       );
+
+COMMIT;
\ No newline at end of file
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.erenew_column_pgt.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.erenew_column_pgt.sql
new file mode 100644 (file)
index 0000000..cf58401
--- /dev/null
@@ -0,0 +1,17 @@
+BEGIN;
+
+ALTER TABLE permission.grp_tree ADD COLUMN erenew BOOL;
+
+COMMIT;
+
+BEGIN;
+
+UPDATE permission.grp_tree SET erenew = FALSE;
+
+COMMIT;
+
+BEGIN;
+
+ALTER TABLE permission.grp_tree ALTER COLUMN erenew SET NOT NULL;
+
+COMMIT;
index cc07f66..8854de0 100755 (executable)
                 <div style="padding-bottom:10px;">[% l("PINES Account Tips") %]</div>
                 <div class="row">
                     <div class="col-12">
-                     <span [% IF ctx.expired_card %]class="danger"[% END %]>
-                        [% l("Account Expiration Date") %]: 
+                        <span [% IF ctx.expired_card %]class="danger"[% END %]>
+                            [% l("Account Expiration Date") %]:
                             [% date.format(ctx.parse_datetime(ctx.user.expire_date), DATE_FORMAT) %]
                         </span>
                     </div>
-                    <div class="col-12">
-                     [% IF ctx.expired_card %]
-                        <span>
-                            <em>
-                            [% l("<br>Your library card has expired.<br>Please contact a librarian to resolve this issue.", fmt_expire_date) %]
-                            </em>
-                        </span>
-                        [% END %]
+                    <div class="col-12" style="padding-bottom:20px;padding-top:20px;">
+                        [% ctx.account_renew_message %]
                     </div>
-                    <br>
                     <div class="col-12">
                      <a href="[% mkurl(ctx.opac_root _ '/myopac/circs') %]"
                             title="[% l('View My Checked Out Items') %]">
index 8a73a7b..0fa4cfe 100755 (executable)
                     [% ELSE %]
                         [% date.format(ctx.parse_datetime(ctx.user.expire_date), DATE_FORMAT) %]
                     [% END %]
+                    <div class="col-12" style="padding:20px 0px 20px 0px;">
+                        [% ctx.account_renew_message %]
+                    </div>
                 </td>
                 <td></td>
             </tr>
diff --git a/Open-ILS/src/templates-bootstrap/opac/renew-account-sp.tt2 b/Open-ILS/src/templates-bootstrap/opac/renew-account-sp.tt2
new file mode 100644 (file)
index 0000000..ec5e051
--- /dev/null
@@ -0,0 +1,35 @@
+[%- PROCESS "opac/parts/header.tt2";
+    PROCESS "opac/parts/org_selector.tt2";
+    WRAPPER "opac/parts/base.tt2";
+    INCLUDE "opac/parts/topnav.tt2";
+    ctx.page_title = l("Renew Your Library Card");
+%]
+
+<!-- eCARD scripts here -->
+<script id="eRenewServer" src="https://ecard.quipugroup.net/js/eRenewEmbed.js"></script>
+<script>loadQGeRenew(48)</script>
+
+<h2 class="sr-only">[% l('Renew Your Library Card') %]</h2>
+<div id="content-wrapper">
+    <div id="main-content-register">
+        <div class="common-full-pad"></div>
+            <p style="font-size:.8em;">(<a href="/eg/opac/renew-account">English</a> | Español)</p>
+            
+            <!-- eCARD div here: -->
+            <input type="hidden" id="patronID" value="[% ctx.user.id %]" />
+            <div id="eRenew" data-language="sp" data-branchid=""></div>
+
+            
+            <!-- eCARD requires JavaScript in order to display the registration form -->
+            <!-- The following will detect if JavaScript is enabled on the patron's browser -->
+            <noscript>
+            <h2 style="color:red;">Warning - JavaScript Required</h2>
+            <p>For full functionality of this web page it is necessary to enable JavaScript in your browser. For more information on most browsers, try <a href="http://www.enable-javascript.com/" target="_blank">How to enable JavaScript</a> OR <a href="http://activatejavascript.org/en/instructions" target="_blank">activatejavascript.org</a><
+            </p>
+            </noscript>
+            </div>
+        
+        <div class="common-full-pad"></div>    
+    </div>
+</div>
+[%- END %]
diff --git a/Open-ILS/src/templates-bootstrap/opac/renew-account.tt2 b/Open-ILS/src/templates-bootstrap/opac/renew-account.tt2
new file mode 100644 (file)
index 0000000..0059a28
--- /dev/null
@@ -0,0 +1,38 @@
+[%- PROCESS "opac/parts/header.tt2";
+    PROCESS "opac/parts/org_selector.tt2";
+    WRAPPER "opac/parts/base.tt2";
+    INCLUDE "opac/parts/topnav.tt2";
+    ctx.page_title = l("Renew Your Library Card");
+%]
+
+[% IF ctx.user %]
+<!-- eCARD scripts here -->
+<script id="eRenewServer" src="https://ecard.quipugroup.net/js/eRenewEmbed.js"></script>
+<script>loadQGeRenew(48)</script>
+
+<h2 class="sr-only">[% l('Renew Your Library Card') %]</h2>
+
+<div id="content-wrapper">
+    <div id="main-content-register">
+        <div class="common-full-pad"></div>
+            <p style="font-size:.8em;">(English | <a href="/eg/opac/renew-account-sp">Español</a>)</p>
+            
+            <!-- eCARD div here: -->
+            <input type="hidden" id="patronID" value="[% ctx.user.id %]" />
+            <div id="eRenew" data-language="en" data-branchid=""></div>
+
+            
+            <!-- eCARD requires JavaScript in order to display the registration form -->
+            <!-- The following will detect if JavaScript is enabled on the patron's browser -->
+            <noscript>
+            <h2 style="color:red;">Warning - JavaScript Required</h2>
+            <p>For full functionality of this web page it is necessary to enable JavaScript in your browser. For more information on most browsers, try <a href="http://www.enable-javascript.com/" target="_blank">How to enable JavaScript</a> OR <a href="http://activatejavascript.org/en/instructions" target="_blank">activatejavascript.org</a><
+            </p>
+            </noscript>
+            </div>
+        
+        <div class="common-full-pad"></div>    
+    </div>
+</div>
+[% END %]
+[%- END %]