<field name="name" reporter:datatype="text"/>
<field name="normal" reporter:datatype="interval"/>
<field name="shrt" reporter:datatype="interval"/>
+ <field name="max_auto_renewals" reporter:datatype="int" />
</fields>
<links>
</links>
<field reporter:label="Shelving Location" name="copy_location" reporter:datatype="link"/>
<field reporter:label="Archived Patron Stat-Cat Entries" name="aaactsc_entries" oils_persist:virtual="true" reporter:datatype="link"/>
<field reporter:label="Archived Copy Stat-Cat Entries" name="aaasc_entries" oils_persist:virtual="true" reporter:datatype="link"/>
+ <field reporter:label="Auto Renewal" name="auto_renewal" reporter:datatype="bool"/>
+ <field reporter:label="Remaining Auto Renewals" name="auto_renewal_remaining" reporter:datatype="int" />
</fields>
<links>
<link field="billable_transaction" reltype="might_have" key="id" map="" class="mbt"/>
<event code='7028' textcode='PATRON_CIRC_MISMATCH'>
<desc xml:lang="en-US">Potentially notified patron does not own the circulation.</desc>
</event>
+ <event code='7029' textcode='MAX_AUTO_RENEWALS_REACHED'>
+ <desc xml:lang="en-US">Circulation has no more auto-renewals remaining</desc>
+ </event>
<!-- ================================================================ -->
signature => q/@see open-ils.circ.renew/,
);
+__PACKAGE__->register_method(
+ method => "run_method",
+ api_name => "open-ils.circ.renew.auto",
+ signature => q/@see open-ils.circ.renew/,
+);
__PACKAGE__->register_method(
method => "run_method",
}
$circulator->is_renewal(1) if $api =~ /renew/;
+ $circulator->is_autorenewal(1) if $api =~ /renew.auto/;
$circulator->is_checkin(1) if $api =~ /checkin/;
$circulator->is_checkout(1) if $api =~ /checkout/;
$circulator->override(1) if $api =~ /override/o;
$circulator->do_checkin();
} elsif( $api =~ /renew/ ) {
- $circulator->do_renew();
+ $circulator->do_renew($api);
}
if( $circulator->bail_out ) {
volume
title
is_renewal
+ is_autorenewal
is_checkout
is_res_checkout
is_precat
recurring_fines_rule
max_fine_rule
renewal_remaining
+ auto_renewal_remaining
hard_due_date
due_date
fulfilled_holds
max_fine => $self->get_max_fine_amount($max_fine_rule),
fine_interval => $recurring_fine_rule->recurrence_interval,
renewal_remaining => $duration_rule->max_renewals,
+ auto_renewal_remaining => $duration_rule->max_auto_renewals,
grace_period => $recurring_fine_rule->grace_period
};
$circ->max_fine($policy->{max_fine});
$circ->fine_interval($recurring->recurrence_interval);
$circ->renewal_remaining($duration->max_renewals);
+ $circ->auto_renewal_remaining($duration->max_auto_renewals);
$circ->grace_period($policy->{grace_period});
} else {
$circ->circ_staff($self->editor->requestor->id);
}
+ if ( $self->is_autorenewal ){
+ $circ->auto_renewal_remaining($self->auto_renewal_remaining);
+ $circ->auto_renewal('t');
+ }
# if the user provided an overiding checkout time,
# (e.g. the checkout really happened several hours ago), then
sub do_renew {
my $self = shift;
+ my $api = shift;
$self->log_me("do_renew()");
# Make sure there is an open circ to renew
$self->push_events(OpenILS::Event->new('MAX_RENEWALS_REACHED'))
if $circ->renewal_remaining < 1;
+ $self->push_events(OpenILS::Event->new('MAX_AUTO_RENEWALS_REACHED'))
+ if $api =~ /renew.auto/ and $circ->auto_renewal_remaining < 1;
# -----------------------------------------------------------------
$self->parent_circ($circ->id);
$self->renewal_remaining( $circ->renewal_remaining - 1 );
+ $self->auto_renewal_remaining( $circ->auto_renewal_remaining - 1 ) if (defined($circ->auto_renewal_remaining));
$self->circ($circ);
# Opac renewal - re-use circ library from original circ (unless told not to)
- if($self->opac_renewal) {
+ if($self->opac_renewal or $api =~ /renew.auto/) {
unless(defined($opac_renewal_use_circ_lib)) {
my $use_circ_lib = $self->editor->retrieve_config_global_flag('circ.opac_renewal.use_original_circ_lib');
if($use_circ_lib and $U->is_true($use_circ_lib->enabled)) {
use base qw/config/;
__PACKAGE__->table('config_rule_circ_duration');
__PACKAGE__->columns(Primary => 'id');
-__PACKAGE__->columns(Essential => qw/name extended normal shrt max_renewals/);
+__PACKAGE__->columns(Essential => qw/name extended normal shrt max_renewals max_auto_renewals/);
#-------------------------------------------------------------------------------
package config::rules::max_fine;
--- /dev/null
+package OpenILS::Application::Trigger::Reactor::Circ::AutoRenew;
+use strict; use warnings;
+use Error qw/:try/;
+use Data::Dumper;
+use OpenSRF::Utils::SettingsClient;
+use OpenILS::Application::Trigger::Reactor;
+use OpenSRF::Utils::Logger qw/:logger/;
+use OpenILS::Utils::CStoreEditor qw/:funcs/;
+use OpenILS::Application::AppUtils;
+my $AppUtils = 'OpenILS::Application::AppUtils';
+
+use Encode;
+$Data::Dumper::Indent = 0;
+
+use base 'OpenILS::Application::Trigger::Reactor';
+
+my $log = 'OpenSRF::Utils::Logger';
+
+sub ABOUT {
+ return <<ABOUT;
+This Autorenew reactor will auto renew a circulation on the day it is due.
+ABOUT
+}
+
+sub handler {
+ my $self = shift;
+ my $env = shift;
+
+ # 1. get a session token for circ user
+
+ my $circs = $env->{target};
+ my $svc = "open-ils.auth_internal";
+ my $api = $svc . '.session.create';
+
+ my $auth_internal_svc = OpenSRF::AppSession->create($svc);
+
+ my $userid = $circs->[0]->usr();
+ # fetch user
+ my $userObj = new_editor()->retrieve_actor_user($userid);
+ my %args =
+ (
+ user_id => $userid,
+ org_unit => $userObj->home_ou(), # all autorenewals occur from patron's Home OU.
+ login_type => "opac"
+ );
+
+ my $token = $auth_internal_svc->request($api, \%args)->gather(1)->{payload}->{authtoken};
+
+ # 2. carry out renewal:
+ my $ses = OpenSRF::AppSession->connect('open-ils.trigger');
+ for (@$circs){
+
+ $logger->info( "AUTORENEW: circ.target_copy: " . Dumper($_->target_copy()) );
+ my $evt = $AppUtils->simplereq(
+ 'open-ils.circ',
+ 'open-ils.circ.renew.auto',
+ $token,
+ {
+ patron_id => $_->usr(),
+ copy_id => $_->target_copy(),
+ opac_renewal => 0
+ }
+ );
+
+ $evt = $evt->[0] if ref($evt) eq "ARRAY"; # we got two resp events, likely renewal errors, grab the first.
+ my $is_renewed = $evt->{textcode} eq 'SUCCESS' ? 1 : 0;
+
+ my $new_circ_due = $is_renewed ? $evt->{payload}->{circ}->due_date : '';
+
+ my %user_data = (
+ copy => $_->target_copy(),
+ is_renewed => $is_renewed,
+ reason => !$is_renewed ? sprintf("%s : %s", $evt->{textcode}, substr($evt->{desc}, 0, 140)) : '',
+ new_due_date => $is_renewed ? $evt->{payload}->{circ}->due_date : '',
+ old_due_date => !$is_renewed ? $_->due_date() : '',
+ );
+
+ $ses->request('open-ils.trigger.event.autocreate', 'autorenewal', $_, $_->circ_lib(), 'system_autorenewal', \%user_data);
+ }
+
+ $ses->disconnect;
+
+ return 1;
+}
+
+1;
use OpenILS::Const qw/:const/;
use OpenILS::Application::AppUtils;
use OpenILS::Utils::CStoreEditor qw/:funcs/;
+use Data::Dumper;
+
sub fourty_two { return 42 }
sub NOOP_True { return 1 }
sub NOOP_False { return 0 }
return 0 if (!$self->MinPassiveTargetAge($env));
}
+ $logger->info("AUTORENEW: CircIsOpen is TRUE!");
return 1;
}
return @$existing ? 0 : 1;
}
+# core type circ in $env->{target}
+sub CircIsAutoRenewable {
+ my $self = shift;
+ my $env = shift;
+
+ my $circ = $env->{target};
+ my $userId = $env->{target}->usr;
+ # 1. check if circ is open
+ if (!$self->CircIsOpen($env)){
+ return 0;
+ }
+
+ # 2. Check if patron is barred
+
+ my ($user, $res) = $U->fetch_user($userId);
+ if ( $U->is_true($user->barred()) ){
+
+ my %user_data = (
+ is_renewed => 0,
+ reason => 'Please contact your library about your account.',
+ );
+
+ $U->create_events_for_hook('autorenewal', $circ, $user->home_ou(), 'system_autorenewal', \%user_data);
+
+ return 0;
+ }
+
+ return 1;
+}
1;
'A hold is cancelled by the patron'
);
+-- AUTORENEWAL Action Trigger definitions and email notification template
+
+ALTER TABLE config.rule_circ_duration
+ADD column max_auto_renewals INTEGER;
+
+ALTER TABLE action.circulation
+ADD column auto_renewal BOOLEAN;
+
+ALTER TABLE action.circulation
+ADD column auto_renewal_remaining INTEGER;
+
+INSERT INTO action_trigger.validator values('CircIsAutoRenewable', 'Checks whether the circulation is able to be autorenewed.');
+INSERT INTO action_trigger.reactor values('Circ::AutoRenew', 'Auto-Renews a circulation.');
+INSERT INTO action_trigger.hook(key, core_type, description) values('autorenewal', 'circ', 'Item was auto-renewed to patron.');
+
+-- AutoRenewer A/T Def:
+INSERT INTO action_trigger.event_definition(active, owner, name, hook, validator, reactor, delay, max_delay, delay_field, group_field)
+ values (false, 1, 'Autorenew', 'checkout.due', 'NOOP_True', 'Circ::AutoRenew', '-23 hours'::interval,'-1 minute'::interval, 'due_date', 'usr');
+
+-- AutoRenewal outcome Email notifier A/T Def:
+INSERT INTO action_trigger.event_definition(active, owner, name, hook, validator, reactor, group_field, template)
+ values (false, 1, 'AutorenewNotify', 'autorenewal', 'NOOP_True', 'SendEmail', 'usr',
+ $$
+ [%- USE date -%]
+ [%- user = target.0.usr -%]
+ To: [%- params.recipient_email || user.email %]
+ From: [%- params.sender_email || default_sender %]
+ Date: [%- date.format(date.now, '%a, %d %b %Y %T -0000', gmt => 1) %]
+ Subject: Items Out Auto-Renewal Notification Auto-Submitted: auto-generated
+
+ Dear [% user.family_name %], [% user.first_given_name %]
+ Your library would like to let you know about your currently borrowed item(s):
+
+ [% FOR circ IN target %]
+ [%- SET idx = loop.count - 1; SET udata = user_data.$idx -%]
+ Item# [%+ loop.count -%]
+ [%- SET cid = circ.target_copy || udata.copy -%]
+ [%- SET copy_details = helpers.get_copy_bib_basics(cid) +%]
+ Title: [% copy_details.title %]
+ Author: [% copy_details.author %]
+ Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]
+ Status: [%- IF udata.is_renewed %] Loan Renewed. Now Due: [%- date.format(helpers.format_date(udata.new_due_date), '%Y-%m-%d') %]
+ [% ELSE %] Not Renewed. Reason: [% udata.reason %] [% END %]
+ [% END %]
+ $$
+);
+
+INSERT INTO action_trigger.environment (event_def, path ) VALUES
+( currval('action_trigger.event_definition_id_seq'), 'usr' ),
+( currval('action_trigger.event_definition_id_seq'), 'circ_lib' );
+
+-- END of autorenwal trigger def stuff
-- in-db indexing normalizers
INSERT INTO config.index_normalizer (name, description, func, param_count) VALUES (
--- /dev/null
+BEGIN;
+ -- SELECT evergreen.upgrade_deps_block_check('xxxx', :eg_version);
+
+ ALTER TABLE config.rule_circ_duration
+ ADD column max_auto_renewals INTEGER;
+
+ ALTER TABLE action.circulation
+ ADD column auto_renewal BOOLEAN;
+
+ ALTER TABLE action.circulation
+ ADD column auto_renewal_remaining INTEGER;
+
+ INSERT INTO action_trigger.validator values('CircIsAutoRenewable', 'Checks whether the circulation is able to be autorenewed.');
+ INSERT INTO action_trigger.reactor values('Circ::AutoRenew', 'Auto-Renews a circulation.');
+ INSERT INTO action_trigger.hook(key, core_type, description) values('autorenewal', 'circ', 'Item was auto-renewed to patron.');
+
+ -- AutoRenewer A/T Def:
+ INSERT INTO action_trigger.event_definition(active, owner, name, hook, validator, reactor, delay, max_delay, delay_field, group_field)
+ values (true, 1, 'Autorenew', 'checkout.due', 'NOOP_True', 'Circ::AutoRenew', '-23 hours'::interval,'-1 minute'::interval, 'due_date', 'usr');
+
+ -- AutoRenewal outcome Email notifier A/T Def:
+ INSERT INTO action_trigger.event_definition(active, owner, name, hook, validator, reactor, group_field, template)
+ values (true, 1, 'AutorenewNotify', 'autorenewal', 'NOOP_True', 'SendEmail', 'usr',
+ $$
+ [%- USE date -%]
+ [%- user = target.0.usr -%]
+ To: [%- params.recipient_email || user.email %]
+ From: [%- params.sender_email || default_sender %]
+ Date: [%- date.format(date.now, '%a, %d %b %Y %T -0000', gmt => 1) %]
+ Subject: Items Out Auto-Renewal Notification Auto-Submitted: auto-generated
+
+ Dear [% user.family_name %], [% user.first_given_name %] (UserID: [%- user.id +%])
+ Your library would like to let you know about your currently borrowed item(s):
+
+ [% FOR circ IN target %]
+ [%- SET idx = loop.count - 1; SET udata = user_data.$idx -%]
+ Item# [%+ loop.count -%] (circ_id: [%- circ.id -%])
+ [%- SET cid = circ.target_copy || udata.copy -%]
+ [%- SET copy_details = helpers.get_copy_bib_basics(cid) +%]
+ Title: [% copy_details.title %]
+ Author: [% copy_details.author %]
+ Due Date: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]
+ Status: [%- IF udata.is_renewed %] Loan Renewed. Now Due: [%- date.format(helpers.format_date(udata.new_due_date), '%Y-%m-%d') %]
+ [% ELSE %] Not Renewed. Reason: [% udata.reason %] [% END %]
+ [% END %]
+ $$
+ );
+
+ INSERT INTO action_trigger.environment (event_def, path ) VALUES
+ ( currval('action_trigger.event_definition_id_seq'), 'usr' ),
+ ( currval('action_trigger.event_definition_id_seq'), 'circ_lib' );
+
+COMMIT;
</div>
<table jsId="ruleCircDurationGrid"
dojoType="openils.widget.AutoGrid"
- fieldOrder="['name', 'max_renewals', 'shrt', 'normal', 'extended']"
+ fieldOrder="['name', 'max_renewals', 'max_auto_renewals', 'shrt', 'normal', 'extended']"
suppressFields="['id']"
query="{id: '*'}"
fmClass='crcd'