[open-ils-commits] r19823 - in trunk/Open-ILS: examples src/perlmods/lib/OpenILS/Application/Circ src/perlmods/lib/OpenILS/Application/Storage/CDBI src/perlmods/lib/OpenILS/Application/Storage/Publisher src/sql/Pg src/sql/Pg/upgrade src/support-scripts web/js/ui/default/conify/global/config web/templates/default/conify/global/config (miker)
svn at svn.open-ils.org
svn at svn.open-ils.org
Sat Mar 19 10:33:21 EDT 2011
Author: miker
Date: 2011-03-19 10:33:18 -0400 (Sat, 19 Mar 2011)
New Revision: 19823
Added:
trunk/Open-ILS/src/sql/Pg/upgrade/0503.schema.grace_periods.sql
Modified:
trunk/Open-ILS/examples/fm_IDL.xml
trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/action.pm
trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm
trunk/Open-ILS/src/sql/Pg/002.schema.config.sql
trunk/Open-ILS/src/sql/Pg/090.schema.action.sql
trunk/Open-ILS/src/sql/Pg/100.circ_matrix.sql
trunk/Open-ILS/src/sql/Pg/950.data.seed-values.sql
trunk/Open-ILS/src/support-scripts/fine_generator.pl
trunk/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js
trunk/Open-ILS/web/templates/default/conify/global/config/circ_matrix_matchpoint.tt2
trunk/Open-ILS/web/templates/default/conify/global/config/rule_recurring_fine.tt2
Log:
In-database Grace intervals
s it stands the grace period for a transaction is only specified on the fine generator script, but fines can be generated on checkin as well without one. As a result any checkin results in grace periods being negated.
The attached patch adds in-db grace periods for all non-booking transactions, removing the grace period from the fine generator cron job script and placing it on the circulation. Grace periods are set on the recurring fine rule with an override available on the circ matchpoint, identical to how renewal count can be overridden from the duration rule already. These grace periods are respected on checkin fine generation as well as on the fine generator cron job script.
The upgrade script will assume, by default, a grace period of 1, but has a \set line to change this. It will also update all circulations without a checkin by default, but another \set will allow disabling of that.
[ NOTE: for the history of the patch, see: https://bugs.launchpad.net/evergreen/+bug/732679 ]
Signed-off-by: Thomas Berezansky <tsbere at mvlc.org>
Signed-off-by: Mike Rylander <mrylander at gmail.com>
Modified: trunk/Open-ILS/examples/fm_IDL.xml
===================================================================
--- trunk/Open-ILS/examples/fm_IDL.xml 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/examples/fm_IDL.xml 2011-03-19 14:33:18 UTC (rev 19823)
@@ -1245,6 +1245,7 @@
<field reporter:label="Max Fine Rule" name="max_fine_rule" reporter:datatype="link"/>
<field reporter:label="Hard Due Date" name="hard_due_date" reporter:datatype="link"/>
<field reporter:label="Renewals Override" name="renewals" reporter:datatype="int"/>
+ <field reporter:label="Grace Period Override" name="grace_period" reporter:datatype="interval"/>
<field reporter:label="Script Test" name="script_test" reporter:datatype="text"/>
<field name="total_copy_hold_ratio" reporter:datatype="float" reporter:label="Minimum Total Copy/Hold Ratio"/>
<field name="available_copy_hold_ratio" reporter:datatype="float" reporter:label="Minimum Available Copy/Hold Ratio"/>
@@ -2805,6 +2806,7 @@
<field reporter:label="Recurring Fine Amount" name="recurring_fine" reporter:datatype="money" />
<field reporter:label="Recurring Fine Rule" name="recurring_fine_rule" reporter:datatype="link"/>
<field reporter:label="Remaining Renewals" name="renewal_remaining" reporter:datatype="int" />
+ <field reporter:label="Grace Period" name="grace_period" reporter:datatype="interval" />
<field reporter:label="Fine Stop Reason" name="stop_fines" reporter:datatype="text"/>
<field reporter:label="Fine Stop Date/Time" name="stop_fines_time" reporter:datatype="timestamp"/>
<field reporter:label="Circulating Item" name="target_copy" reporter:datatype="link"/>
@@ -2866,6 +2868,7 @@
<field reporter:label="Recurring Fine Amount" name="recurring_fine" reporter:datatype="money" />
<field reporter:label="Recurring Fine Rule" name="recurring_fine_rule" reporter:datatype="link"/>
<field reporter:label="Remaining Renewals" name="renewal_remaining" reporter:datatype="int" />
+ <field reporter:label="Grace Period" name="grace_period" reporter:datatype="interval" />
<field reporter:label="Fine Stop Reason" name="stop_fines" reporter:datatype="text"/>
<field reporter:label="Fine Stop Date/Time" name="stop_fines_time" reporter:datatype="timestamp"/>
<field reporter:label="Circulating Item" name="target_copy" reporter:datatype="link"/>
@@ -2930,6 +2933,7 @@
<field reporter:label="Recurring Fine Amount" name="recurring_fine" reporter:datatype="money" />
<field reporter:label="Recurring Fine Rule" name="recurring_fine_rule" reporter:datatype="link"/>
<field reporter:label="Remaining Renewals" name="renewal_remaining" reporter:datatype="int" />
+ <field reporter:label="Grace Period" name="grace_period" reporter:datatype="interval" />
<field reporter:label="Fine Stop Reason" name="stop_fines" reporter:datatype="text"/>
<field reporter:label="Fine Stop Date/Time" name="stop_fines_time" reporter:datatype="timestamp"/>
<field reporter:label="Circulating Item" name="target_copy" reporter:datatype="link"/>
@@ -4571,6 +4575,7 @@
<field name="recurring_fine" reporter:datatype="money" />
<field name="recurring_fine_rule" reporter:datatype="link"/>
<field name="renewal_remaining" reporter:datatype="int" />
+ <field name="grace_period" reporter:datatype="interval" />
<field name="stop_fines" reporter:datatype="text"/>
<field name="stop_fines_time" reporter:datatype="timestamp"/>
<field name="target_copy" reporter:datatype="link"/>
@@ -4606,6 +4611,7 @@
<field name="name" reporter:datatype="text"/>
<field name="normal" reporter:datatype="money" />
<field name="recurrence_interval" reporter:datatype="interval"/>
+ <field name="grace_period" reporter:datatype="interval" />
</fields>
<links/>
<permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
Modified: trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm 2011-03-19 14:33:18 UTC (rev 19823)
@@ -1162,6 +1162,9 @@
$self->circ_matrix_matchpoint->duration_rule->max_renewals($results->[0]->{renewals});
}
$self->circ_matrix_matchpoint->recurring_fine_rule($self->editor->retrieve_config_rules_recurring_fine($results->[0]->{recurring_fine_rule}));
+ if($results->[0]->{grace_period}) {
+ $self->circ_matrix_matchpoint->recurring_fine_rule->grace_period($results->[0]->{grace_period});
+ }
$self->circ_matrix_matchpoint->max_fine_rule($self->editor->retrieve_config_rules_max_fine($results->[0]->{max_fine_rule}));
$self->circ_matrix_matchpoint->hard_due_date($self->editor->retrieve_config_hard_due_date($results->[0]->{hard_due_date}));
}
@@ -1220,7 +1223,8 @@
max_fine_rule => $max_fine_rule->name,
max_fine => $self->get_max_fine_amount($max_fine_rule),
fine_interval => $recurring_fine_rule->recurrence_interval,
- renewal_remaining => $duration_rule->max_renewals
+ renewal_remaining => $duration_rule->max_renewals,
+ grace_period => $recurring_fine_rule->grace_period
};
if($hard_due_date) {
@@ -1833,6 +1837,7 @@
$circ->max_fine($policy->{max_fine});
$circ->fine_interval($recurring->recurrence_interval);
$circ->renewal_remaining($duration->max_renewals);
+ $circ->grace_period($policy->{grace_period});
} else {
@@ -1841,6 +1846,7 @@
$circ->recurring_fine_rule(OILS_UNLIMITED_CIRC_DURATION);
$circ->max_fine_rule(OILS_UNLIMITED_CIRC_DURATION);
$circ->renewal_remaining(0);
+ $circ->grace_period(0);
}
$circ->target_copy( $copy->id );
@@ -2928,15 +2934,25 @@
sub generate_fines_start {
my $self = shift;
my $reservation = shift;
+ my $dt_parser = DateTime::Format::ISO8601->new;
- my $id = $reservation ? $self->reservation->id : $self->circ->id;
+ my $obj = $reservation ? $self->reservation : $self->circ;
+ # If we have a grace period
+ if($obj->can('grace_period')) {
+ # Parse out the due date
+ my $due_date = $dt_parser->parse_datetime( cleanse_ISO8601($obj->due_date) );
+ # Add the grace period to the due date
+ $due_date->add(seconds => OpenSRF::Utils->interval_to_seconds($obj->grace_period));
+ # Don't generate fines on circs still in grace period
+ return undef if ($due_date > DateTime->now);
+ }
+
if (!exists($self->{_gen_fines_req})) {
$self->{_gen_fines_req} = OpenSRF::AppSession->create('open-ils.storage')
->request(
'open-ils.storage.action.circulation.overdue.generate_fines',
- undef,
- $id
+ $obj->id
);
}
@@ -2947,6 +2963,8 @@
my $self = shift;
my $reservation = shift;
+ return undef unless $self->{_gen_fines_req};
+
my $id = $reservation ? $self->reservation->id : $self->circ->id;
$self->{_gen_fines_req}->wait_complete;
Modified: trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/action.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/action.pm 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/action.pm 2011-03-19 14:33:18 UTC (rev 19823)
@@ -63,7 +63,7 @@
__PACKAGE__->table('action_circulation');
__PACKAGE__->columns(Primary => 'id');
__PACKAGE__->columns(Essential => qw/xact_start usr target_copy circ_lib
- duration duration_rule renewal_remaining
+ duration duration_rule renewal_remaining grace_period
recurring_fine_rule recurring_fine stop_fines
max_fine max_fine_rule fine_interval
stop_fines xact_finish due_date opac_renewal
@@ -78,7 +78,7 @@
__PACKAGE__->table('action_open_circulation');
__PACKAGE__->columns(Primary => 'id');
__PACKAGE__->columns(Essential => qw/xact_start usr target_copy circ_lib
- duration duration_rule renewal_remaining
+ duration duration_rule renewal_remaining grace_period
recurring_fine_rule recurring_fine stop_fines
max_fine max_fine_rule fine_interval
stop_fines xact_finish due_date opac_renewal
Modified: trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/CDBI/config.pm 2011-03-19 14:33:18 UTC (rev 19823)
@@ -59,7 +59,7 @@
use base qw/config/;
__PACKAGE__->table('config_rule_recurring_fine');
__PACKAGE__->columns(Primary => 'id');
-__PACKAGE__->columns(Essential => qw/name high normal low recurrence_interval/);
+__PACKAGE__->columns(Essential => qw/name high normal low recurrence_interval grace_period/);
#-------------------------------------------------------------------------------
package config::rules::age_hold_protect;
Modified: trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm
===================================================================
--- trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm 2011-03-19 14:33:18 UTC (rev 19823)
@@ -95,23 +95,16 @@
sub overdue_circs {
- my $grace = shift;
my $upper_interval = shift || '1 millennium';
my $idlist = shift;
my $c_t = action::circulation->table;
- if ($grace && $grace =~ /^\d+$/o) {
- $grace = " - ($grace * (fine_interval))";
- } else {
- $grace = '';
- }
-
my $sql = <<" SQL";
SELECT *
FROM $c_t
WHERE stop_fines IS NULL
- AND due_date < ( CURRENT_TIMESTAMP $grace)
+ AND due_date < ( CURRENT_TIMESTAMP - grace_period )
AND fine_interval < ?::INTERVAL
SQL
@@ -125,7 +118,7 @@
SELECT *
FROM $c_t
WHERE return_time IS NULL
- AND end_time < ( CURRENT_TIMESTAMP $grace)
+ AND end_time < ( CURRENT_TIMESTAMP )
AND fine_interval IS NOT NULL
AND cancel_time IS NULL
SQL
@@ -266,11 +259,10 @@
sub grab_overdue {
my $self = shift;
my $client = shift;
- my $grace = shift || '';
my $idlist = $self->api_name =~/id_list/o ? 1 : 0;
- $client->respond( $idlist ? $_ : $_->to_fieldmapper ) for ( overdue_circs($grace, '', $idlist) );
+ $client->respond( $idlist ? $_ : $_->to_fieldmapper ) for ( overdue_circs('', $idlist) );
return undef;
@@ -787,7 +779,6 @@
sub generate_fines {
my $self = shift;
my $client = shift;
- my $grace = shift;
my $circ = shift;
my $overbill = shift;
@@ -799,7 +790,7 @@
action::circulation->search_where( { id => $circ, stop_fines => undef } ),
booking::reservation->search_where( { id => $circ, return_time => undef, cancel_time => undef } );
} else {
- push @circs, overdue_circs($grace);
+ push @circs, overdue_circs();
}
my %hoo = map { ( $_->id => $_ ) } actor::org_unit::hours_of_operation->retrieve_all;
@@ -823,6 +814,8 @@
$recurring_fine_method = 'fine_amount';
next unless ($c->fine_interval);
}
+ #TODO: reservation grace periods
+ my $grace_period = ($is_reservation ? 0 : $c->grace_period);
try {
if ($self->method_lookup('open-ils.storage.transaction.current')->run) {
@@ -902,8 +895,8 @@
while ( $h->$dow_open eq '00:00:00' and $h->$dow_close eq '00:00:00' ) {
# if the circ lib is closed, add a day to the grace period...
- $grace++;
- $log->info( "Grace period for circ ".$c->id." extended to $grace intervals" );
+ $grace_period+=86400;
+ $log->info( "Grace period for circ ".$c->id." extended to $grace_period [" . seconds_to_interval( $grace_period ) . "]" );
$log->info( "Day of week $dow open $dow_open, close $dow_close" );
$due_dt = $due_dt->add( days => 1 );
@@ -927,12 +920,11 @@
$pending_fine_count++ if ($fine_interval && ($fine_interval % 86400 == 0));
if ( $last_fine == $due # we have no fines yet
- && $grace # and we have a grace period
- && $pending_fine_count <= $grace # and we seem to be inside that period
- && $now < $due + $fine_interval * $grace # and some date math bares that out, then
+ && $grace_period # and we have a grace period
+ && $now < $due + $grace_period # and some date math says were are within the grace period
) {
- $client->respond( "Still inside grace period of: ". seconds_to_interval( $fine_interval * $grace)."\n" );
- $log->info( "Circ ".$c->id." is still inside grace period of: $grace [". seconds_to_interval( $fine_interval * $grace).']' );
+ $client->respond( "Still inside grace period of: ". seconds_to_interval( $grace_period )."\n" );
+ $log->info( "Circ ".$c->id." is still inside grace period of: $grace_period [". seconds_to_interval( $grace_period ).']' );
next;
}
Modified: trunk/Open-ILS/src/sql/Pg/002.schema.config.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/002.schema.config.sql 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/src/sql/Pg/002.schema.config.sql 2011-03-19 14:33:18 UTC (rev 19823)
@@ -70,7 +70,7 @@
install_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
-INSERT INTO config.upgrade_log (version) VALUES ('0502'); -- dbwells
+INSERT INTO config.upgrade_log (version) VALUES ('0503'); -- miker for tsbere
CREATE TABLE config.bib_source (
id SERIAL PRIMARY KEY,
@@ -420,7 +420,8 @@
high NUMERIC(6,2) NOT NULL,
normal NUMERIC(6,2) NOT NULL,
low NUMERIC(6,2) NOT NULL,
- recurrence_interval INTERVAL NOT NULL DEFAULT '1 day'::INTERVAL
+ recurrence_interval INTERVAL NOT NULL DEFAULT '1 day'::INTERVAL,
+ grace_period INTERVAL NOT NULL DEFAULT '1 day'::INTERVAL
);
COMMENT ON TABLE config.rule_recurring_fine IS $$
/*
Modified: trunk/Open-ILS/src/sql/Pg/090.schema.action.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/090.schema.action.sql 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/src/sql/Pg/090.schema.action.sql 2011-03-19 14:33:18 UTC (rev 19823)
@@ -109,6 +109,7 @@
checkin_staff INT, -- actor.usr.id
checkin_lib INT, -- actor.org_unit.id
renewal_remaining INT NOT NULL, -- derived from "circ duration" rule
+ grace_period INTERVAL NOT NULL, -- derived from "circ fine" rule
due_date TIMESTAMP WITH TIME ZONE,
stop_fines_time TIMESTAMP WITH TIME ZONE,
checkin_time TIMESTAMP WITH TIME ZONE,
@@ -191,7 +192,7 @@
CREATE OR REPLACE VIEW action.all_circulation AS
SELECT id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
- circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, due_date,
+ circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, grace_period, due_date,
stop_fines_time, checkin_time, create_time, duration, fine_interval, recurring_fine,
max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recurring_fine_rule,
max_fine_rule, stop_fines, workstation, checkin_workstation, checkin_scan_time, parent_circ
@@ -200,7 +201,7 @@
SELECT DISTINCT circ.id,COALESCE(a.post_code,b.post_code) AS usr_post_code, p.home_ou AS usr_home_ou, p.profile AS usr_profile, EXTRACT(YEAR FROM p.dob)::INT AS usr_birth_year,
cp.call_number AS copy_call_number, cp.location AS copy_location, cn.owning_lib AS copy_owning_lib, cp.circ_lib AS copy_circ_lib,
cn.record AS copy_bib_record, circ.xact_start, circ.xact_finish, circ.target_copy, circ.circ_lib, circ.circ_staff, circ.checkin_staff,
- circ.checkin_lib, circ.renewal_remaining, circ.due_date, circ.stop_fines_time, circ.checkin_time, circ.create_time, circ.duration,
+ circ.checkin_lib, circ.renewal_remaining, circ.grace_period, circ.due_date, circ.stop_fines_time, circ.checkin_time, circ.create_time, circ.duration,
circ.fine_interval, circ.recurring_fine, circ.max_fine, circ.phone_renewal, circ.desk_renewal, circ.opac_renewal, circ.duration_rule,
circ.recurring_fine_rule, circ.max_fine_rule, circ.stop_fines, circ.workstation, circ.checkin_workstation, circ.checkin_scan_time,
circ.parent_circ
@@ -233,14 +234,14 @@
INSERT INTO action.aged_circulation
(id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
- circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, due_date,
+ circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, grace_period, due_date,
stop_fines_time, checkin_time, create_time, duration, fine_interval, recurring_fine,
max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recurring_fine_rule,
max_fine_rule, stop_fines, workstation, checkin_workstation, checkin_scan_time, parent_circ)
SELECT
id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
- circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, due_date,
+ circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, grace_period, due_date,
stop_fines_time, checkin_time, create_time, duration, fine_interval, recurring_fine,
max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recurring_fine_rule,
max_fine_rule, stop_fines, workstation, checkin_workstation, checkin_scan_time, parent_circ
Modified: trunk/Open-ILS/src/sql/Pg/100.circ_matrix.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/100.circ_matrix.sql 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/src/sql/Pg/100.circ_matrix.sql 2011-03-19 14:33:18 UTC (rev 19823)
@@ -75,6 +75,7 @@
max_fine_rule INT REFERENCES config.rule_max_fine (id) DEFERRABLE INITIALLY DEFERRED,
hard_due_date INT REFERENCES config.hard_due_date (id) DEFERRABLE INITIALLY DEFERRED,
renewals INT, -- Renewal count override
+ grace_period INTERVAL, -- Grace period override
script_test TEXT, -- javascript source
total_copy_hold_ratio FLOAT,
available_copy_hold_ratio FLOAT
@@ -249,6 +250,9 @@
IF matchpoint.renewals IS NULL THEN
matchpoint.renewals := cur_matchpoint.renewals;
END IF;
+ IF matchpoint.grace_period IS NULL THEN
+ matchpoint.grace_period := cur_matchpoint.grace_period;
+ END IF;
END LOOP;
-- Check required fields
@@ -337,7 +341,7 @@
END;
$func$ LANGUAGE PLPGSQL;
-CREATE TYPE action.circ_matrix_test_result AS ( success BOOL, fail_part TEXT, buildrows INT[], matchpoint INT, circulate BOOL, duration_rule INT, recurring_fine_rule INT, max_fine_rule INT, hard_due_date INT, renewals INT );
+CREATE TYPE action.circ_matrix_test_result AS ( success BOOL, fail_part TEXT, buildrows INT[], matchpoint INT, circulate BOOL, duration_rule INT, recurring_fine_rule INT, max_fine_rule INT, hard_due_date INT, renewals INT, grace_period INTERVAL );
CREATE OR REPLACE FUNCTION action.item_user_circ_test( circ_ou INT, match_item BIGINT, match_user INT, renewal BOOL ) RETURNS SETOF action.circ_matrix_test_result AS $func$
DECLARE
user_object actor.usr%ROWTYPE;
@@ -429,6 +433,7 @@
result.max_fine_rule := circ_matchpoint.max_fine_rule;
result.hard_due_date := circ_matchpoint.hard_due_date;
result.renewals := circ_matchpoint.renewals;
+ result.grace_period := circ_matchpoint.grace_period;
result.buildrows := circ_test.buildrows;
-- Fail if we couldn't find a matchpoint
Modified: trunk/Open-ILS/src/sql/Pg/950.data.seed-values.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/950.data.seed-values.sql 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/src/sql/Pg/950.data.seed-values.sql 2011-03-19 14:33:18 UTC (rev 19823)
@@ -194,11 +194,11 @@
SELECT SETVAL('config.rule_max_fine_id_seq'::TEXT, 100);
INSERT INTO config.rule_recurring_fine VALUES
- (1, oils_i18n_gettext(1, 'default', 'crrf', 'name'), 0.50, 0.10, 0.05, '1 day');
+ (1, oils_i18n_gettext(1, 'default', 'crrf', 'name'), 0.50, 0.10, 0.05, '1 day', '1 day');
INSERT INTO config.rule_recurring_fine VALUES
- (2, oils_i18n_gettext(2, '10_cent_per_day', 'crrf', 'name'), 0.50, 0.10, 0.10, '1 day');
+ (2, oils_i18n_gettext(2, '10_cent_per_day', 'crrf', 'name'), 0.50, 0.10, 0.10, '1 day', '1 day');
INSERT INTO config.rule_recurring_fine VALUES
- (3, oils_i18n_gettext(3, '50_cent_per_day', 'crrf', 'name'), 0.50, 0.50, 0.50, '1 day');
+ (3, oils_i18n_gettext(3, '50_cent_per_day', 'crrf', 'name'), 0.50, 0.50, 0.50, '1 day', '1 day');
SELECT SETVAL('config.rule_recurring_fine_id_seq'::TEXT, 100);
INSERT INTO config.rule_age_hold_protect VALUES
Added: trunk/Open-ILS/src/sql/Pg/upgrade/0503.schema.grace_periods.sql
===================================================================
--- trunk/Open-ILS/src/sql/Pg/upgrade/0503.schema.grace_periods.sql (rev 0)
+++ trunk/Open-ILS/src/sql/Pg/upgrade/0503.schema.grace_periods.sql 2011-03-19 14:33:18 UTC (rev 19823)
@@ -0,0 +1,470 @@
+BEGIN;
+
+-- FAIR WARNING:
+-- Using a tool such as pgadmin to run this script may fail
+-- If it does, try psql command line.
+
+-- Change this to FALSE to disable updating existing circs
+-- Otherwise will use the fine interval for the grace period
+\set CircGrace TRUE
+
+INSERT INTO config.upgrade_log (version) VALUES ('0503');
+
+-- New Columns
+
+ALTER TABLE config.circ_matrix_matchpoint
+ ADD COLUMN grace_period INTERVAL;
+
+ALTER TABLE config.rule_recurring_fine
+ ADD COLUMN grace_period INTERVAL NOT NULL DEFAULT '1 day';
+
+ALTER TABLE action.circulation
+ ADD COLUMN grace_period INTERVAL NOT NULL DEFAULT '0 seconds';
+
+ALTER TABLE action.aged_circulation
+ ADD COLUMN grace_period INTERVAL NOT NULL DEFAULT '0 seconds';
+
+-- Remove defaults needed to stop null complaints
+
+ALTER TABLE action.circulation
+ ALTER COLUMN grace_period DROP DEFAULT;
+
+ALTER TABLE action.aged_circulation
+ ALTER COLUMN grace_period DROP DEFAULT;
+
+-- Drop Views
+
+DROP VIEW action.all_circulation;
+DROP VIEW action.open_circulation;
+DROP VIEW action.billable_circulations;
+
+-- Replace Views
+
+CREATE OR REPLACE VIEW action.all_circulation AS
+ SELECT id,usr_post_code, usr_home_ou, usr_profile, usr_birth_year, copy_call_number, copy_location,
+ copy_owning_lib, copy_circ_lib, copy_bib_record, xact_start, xact_finish, target_copy,
+ circ_lib, circ_staff, checkin_staff, checkin_lib, renewal_remaining, grace_period, due_date,
+ stop_fines_time, checkin_time, create_time, duration, fine_interval, recurring_fine,
+ max_fine, phone_renewal, desk_renewal, opac_renewal, duration_rule, recurring_fine_rule,
+ max_fine_rule, stop_fines, workstation, checkin_workstation, checkin_scan_time, parent_circ
+ FROM action.aged_circulation
+ UNION ALL
+ SELECT DISTINCT circ.id,COALESCE(a.post_code,b.post_code) AS usr_post_code, p.home_ou AS usr_home_ou, p.profile AS usr_profile, EXTRACT(YEAR FROM p.dob)::INT AS usr_birth_year,
+ cp.call_number AS copy_call_number, cp.location AS copy_location, cn.owning_lib AS copy_owning_lib, cp.circ_lib AS copy_circ_lib,
+ cn.record AS copy_bib_record, circ.xact_start, circ.xact_finish, circ.target_copy, circ.circ_lib, circ.circ_staff, circ.checkin_staff,
+ circ.checkin_lib, circ.renewal_remaining, circ.grace_period, circ.due_date, circ.stop_fines_time, circ.checkin_time, circ.create_time, circ.duration,
+ circ.fine_interval, circ.recurring_fine, circ.max_fine, circ.phone_renewal, circ.desk_renewal, circ.opac_renewal, circ.duration_rule,
+ circ.recurring_fine_rule, circ.max_fine_rule, circ.stop_fines, circ.workstation, circ.checkin_workstation, circ.checkin_scan_time,
+ circ.parent_circ
+ FROM action.circulation circ
+ JOIN asset.copy cp ON (circ.target_copy = cp.id)
+ JOIN asset.call_number cn ON (cp.call_number = cn.id)
+ JOIN actor.usr p ON (circ.usr = p.id)
+ LEFT JOIN actor.usr_address a ON (p.mailing_address = a.id)
+ LEFT JOIN actor.usr_address b ON (p.billing_address = a.id);
+
+CREATE OR REPLACE VIEW action.open_circulation AS
+ SELECT *
+ FROM action.circulation
+ WHERE checkin_time IS NULL
+ ORDER BY due_date;
+
+
+CREATE OR REPLACE VIEW action.billable_circulations AS
+ SELECT *
+ FROM action.circulation
+ WHERE xact_finish IS NULL;
+
+-- Drop Functions that rely on types
+
+DROP FUNCTION action.item_user_circ_test(INT, BIGINT, INT, BOOL);
+DROP FUNCTION action.item_user_circ_test(INT, BIGINT, INT);
+DROP FUNCTION action.item_user_renew_test(INT, BIGINT, INT);
+
+-- Drop Types that are changing
+
+DROP TYPE action.circ_matrix_test_result;
+
+-- Replace Types
+
+CREATE TYPE action.circ_matrix_test_result AS ( success BOOL, fail_part TEXT, buildrows INT[], matchpoint INT, circulate BOOL, duration_rule INT, recurring_fine_rule INT, max_fine_rule INT, hard_due_date INT, renewals INT, grace_period INTERVAL );
+
+-- Fix/Replace Functions
+
+CREATE OR REPLACE FUNCTION action.find_circ_matrix_matchpoint( context_ou INT, item_object asset.copy, user_object actor.usr, renewal BOOL ) RETURNS action.found_circ_matrix_matchpoint AS $func$
+DECLARE
+ cn_object asset.call_number%ROWTYPE;
+ rec_descriptor metabib.rec_descriptor%ROWTYPE;
+ cur_matchpoint config.circ_matrix_matchpoint%ROWTYPE;
+ matchpoint config.circ_matrix_matchpoint%ROWTYPE;
+ weights config.circ_matrix_weights%ROWTYPE;
+ user_age INTERVAL;
+ denominator NUMERIC(6,2);
+ row_list INT[];
+ result action.found_circ_matrix_matchpoint;
+BEGIN
+ -- Assume failure
+ result.success = false;
+
+ -- Fetch useful data
+ SELECT INTO cn_object * FROM asset.call_number WHERE id = item_object.call_number;
+ SELECT INTO rec_descriptor * FROM metabib.rec_descriptor WHERE record = cn_object.record;
+
+ -- Pre-generate this so we only calc it once
+ IF user_object.dob IS NOT NULL THEN
+ SELECT INTO user_age age(user_object.dob);
+ END IF;
+
+ -- Grab the closest set circ weight setting.
+ SELECT INTO weights cw.*
+ FROM config.weight_assoc wa
+ JOIN config.circ_matrix_weights cw ON (cw.id = wa.circ_weights)
+ JOIN actor.org_unit_ancestors_distance( context_ou ) d ON (wa.org_unit = d.id)
+ WHERE active
+ ORDER BY d.distance
+ LIMIT 1;
+
+ -- No weights? Bad admin! Defaults to handle that anyway.
+ IF weights.id IS NULL THEN
+ weights.grp := 11.0;
+ weights.org_unit := 10.0;
+ weights.circ_modifier := 5.0;
+ weights.marc_type := 4.0;
+ weights.marc_form := 3.0;
+ weights.marc_vr_format := 2.0;
+ weights.copy_circ_lib := 8.0;
+ weights.copy_owning_lib := 8.0;
+ weights.user_home_ou := 8.0;
+ weights.ref_flag := 1.0;
+ weights.juvenile_flag := 6.0;
+ weights.is_renewal := 7.0;
+ weights.usr_age_lower_bound := 0.0;
+ weights.usr_age_upper_bound := 0.0;
+ END IF;
+
+ -- Determine the max (expected) depth (+1) of the org tree and max depth of the permisson tree
+ -- If you break your org tree with funky parenting this may be wrong
+ -- Note: This CTE is duplicated in the find_hold_matrix_matchpoint function, and it may be a good idea to split it off to a function
+ -- We use one denominator for all tree-based checks for when permission groups and org units have the same weighting
+ WITH all_distance(distance) AS (
+ SELECT depth AS distance FROM actor.org_unit_type
+ UNION
+ SELECT distance AS distance FROM permission.grp_ancestors_distance((SELECT id FROM permission.grp_tree WHERE parent IS NULL))
+ )
+ SELECT INTO denominator MAX(distance) + 1 FROM all_distance;
+
+ -- Loop over all the potential matchpoints
+ FOR cur_matchpoint IN
+ SELECT m.*
+ FROM config.circ_matrix_matchpoint m
+ /*LEFT*/ JOIN permission.grp_ancestors_distance( user_object.profile ) upgad ON m.grp = upgad.id
+ /*LEFT*/ JOIN actor.org_unit_ancestors_distance( context_ou ) ctoua ON m.org_unit = ctoua.id
+ LEFT JOIN actor.org_unit_ancestors_distance( cn_object.owning_lib ) cnoua ON m.copy_owning_lib = cnoua.id
+ LEFT JOIN actor.org_unit_ancestors_distance( item_object.circ_lib ) iooua ON m.copy_circ_lib = iooua.id
+ LEFT JOIN actor.org_unit_ancestors_distance( user_object.home_ou ) uhoua ON m.user_home_ou = uhoua.id
+ WHERE m.active
+ -- Permission Groups
+ -- AND (m.grp IS NULL OR upgad.id IS NOT NULL) -- Optional Permission Group?
+ -- Org Units
+ -- AND (m.org_unit IS NULL OR ctoua.id IS NOT NULL) -- Optional Org Unit?
+ AND (m.copy_owning_lib IS NULL OR cnoua.id IS NOT NULL)
+ AND (m.copy_circ_lib IS NULL OR iooua.id IS NOT NULL)
+ AND (m.user_home_ou IS NULL OR uhoua.id IS NOT NULL)
+ -- Circ Type
+ AND (m.is_renewal IS NULL OR m.is_renewal = renewal)
+ -- Static User Checks
+ AND (m.juvenile_flag IS NULL OR m.juvenile_flag = user_object.juvenile)
+ AND (m.usr_age_lower_bound IS NULL OR (user_age IS NOT NULL AND m.usr_age_lower_bound < user_age))
+ AND (m.usr_age_upper_bound IS NULL OR (user_age IS NOT NULL AND m.usr_age_upper_bound > user_age))
+ -- Static Item Checks
+ AND (m.circ_modifier IS NULL OR m.circ_modifier = item_object.circ_modifier)
+ AND (m.marc_type IS NULL OR m.marc_type = COALESCE(item_object.circ_as_type, rec_descriptor.item_type))
+ AND (m.marc_form IS NULL OR m.marc_form = rec_descriptor.item_form)
+ AND (m.marc_vr_format IS NULL OR m.marc_vr_format = rec_descriptor.vr_format)
+ AND (m.ref_flag IS NULL OR m.ref_flag = item_object.ref)
+ ORDER BY
+ -- Permission Groups
+ CASE WHEN upgad.distance IS NOT NULL THEN 2^(2*weights.grp - (upgad.distance/denominator)) ELSE 0.0 END +
+ -- Org Units
+ CASE WHEN ctoua.distance IS NOT NULL THEN 2^(2*weights.org_unit - (ctoua.distance/denominator)) ELSE 0.0 END +
+ CASE WHEN cnoua.distance IS NOT NULL THEN 2^(2*weights.copy_owning_lib - (cnoua.distance/denominator)) ELSE 0.0 END +
+ CASE WHEN iooua.distance IS NOT NULL THEN 2^(2*weights.copy_circ_lib - (iooua.distance/denominator)) ELSE 0.0 END +
+ CASE WHEN uhoua.distance IS NOT NULL THEN 2^(2*weights.user_home_ou - (uhoua.distance/denominator)) ELSE 0.0 END +
+ -- Circ Type -- Note: 4^x is equiv to 2^(2*x)
+ CASE WHEN m.is_renewal IS NOT NULL THEN 4^weights.is_renewal ELSE 0.0 END +
+ -- Static User Checks
+ CASE WHEN m.juvenile_flag IS NOT NULL THEN 4^weights.juvenile_flag ELSE 0.0 END +
+ CASE WHEN m.usr_age_lower_bound IS NOT NULL THEN 4^weights.usr_age_lower_bound ELSE 0.0 END +
+ CASE WHEN m.usr_age_upper_bound IS NOT NULL THEN 4^weights.usr_age_upper_bound ELSE 0.0 END +
+ -- Static Item Checks
+ CASE WHEN m.circ_modifier IS NOT NULL THEN 4^weights.circ_modifier ELSE 0.0 END +
+ CASE WHEN m.marc_type IS NOT NULL THEN 4^weights.marc_type ELSE 0.0 END +
+ CASE WHEN m.marc_form IS NOT NULL THEN 4^weights.marc_form ELSE 0.0 END +
+ CASE WHEN m.marc_vr_format IS NOT NULL THEN 4^weights.marc_vr_format ELSE 0.0 END +
+ CASE WHEN m.ref_flag IS NOT NULL THEN 4^weights.ref_flag ELSE 0.0 END DESC,
+ -- Final sort on id, so that if two rules have the same sorting in the previous sort they have a defined order
+ -- This prevents "we changed the table order by updating a rule, and we started getting different results"
+ m.id LOOP
+
+ -- Record the full matching row list
+ row_list := row_list || cur_matchpoint.id;
+
+ -- No matchpoint yet?
+ IF matchpoint.id IS NULL THEN
+ -- Take the entire matchpoint as a starting point
+ matchpoint := cur_matchpoint;
+ CONTINUE; -- No need to look at this row any more.
+ END IF;
+
+ -- Incomplete matchpoint?
+ IF matchpoint.circulate IS NULL THEN
+ matchpoint.circulate := cur_matchpoint.circulate;
+ END IF;
+ IF matchpoint.duration_rule IS NULL THEN
+ matchpoint.duration_rule := cur_matchpoint.duration_rule;
+ END IF;
+ IF matchpoint.recurring_fine_rule IS NULL THEN
+ matchpoint.recurring_fine_rule := cur_matchpoint.recurring_fine_rule;
+ END IF;
+ IF matchpoint.max_fine_rule IS NULL THEN
+ matchpoint.max_fine_rule := cur_matchpoint.max_fine_rule;
+ END IF;
+ IF matchpoint.hard_due_date IS NULL THEN
+ matchpoint.hard_due_date := cur_matchpoint.hard_due_date;
+ END IF;
+ IF matchpoint.total_copy_hold_ratio IS NULL THEN
+ matchpoint.total_copy_hold_ratio := cur_matchpoint.total_copy_hold_ratio;
+ END IF;
+ IF matchpoint.available_copy_hold_ratio IS NULL THEN
+ matchpoint.available_copy_hold_ratio := cur_matchpoint.available_copy_hold_ratio;
+ END IF;
+ IF matchpoint.renewals IS NULL THEN
+ matchpoint.renewals := cur_matchpoint.renewals;
+ END IF;
+ IF matchpoint.grace_period IS NULL THEN
+ matchpoint.grace_period := cur_matchpoint.grace_period;
+ END IF;
+ END LOOP;
+
+ -- Check required fields
+ IF matchpoint.circulate IS NOT NULL AND
+ matchpoint.duration_rule IS NOT NULL AND
+ matchpoint.recurring_fine_rule IS NOT NULL AND
+ matchpoint.max_fine_rule IS NOT NULL THEN
+ -- All there? We have a completed match.
+ result.success := true;
+ END IF;
+
+ -- Include the assembled matchpoint, even if it isn't complete
+ result.matchpoint := matchpoint;
+
+ -- Include (for debugging) the full list of matching rows
+ result.buildrows := row_list;
+
+ -- Hand the result back to caller
+ RETURN result;
+END;
+$func$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION action.item_user_circ_test( circ_ou INT, match_item BIGINT, match_user INT, renewal BOOL ) RETURNS SETOF action.circ_matrix_test_result AS $func$
+DECLARE
+ user_object actor.usr%ROWTYPE;
+ standing_penalty config.standing_penalty%ROWTYPE;
+ item_object asset.copy%ROWTYPE;
+ item_status_object config.copy_status%ROWTYPE;
+ item_location_object asset.copy_location%ROWTYPE;
+ result action.circ_matrix_test_result;
+ circ_test action.found_circ_matrix_matchpoint;
+ circ_matchpoint config.circ_matrix_matchpoint%ROWTYPE;
+ out_by_circ_mod config.circ_matrix_circ_mod_test%ROWTYPE;
+ circ_mod_map config.circ_matrix_circ_mod_test_map%ROWTYPE;
+ hold_ratio action.hold_stats%ROWTYPE;
+ penalty_type TEXT;
+ items_out INT;
+ context_org_list INT[];
+ done BOOL := FALSE;
+BEGIN
+ -- Assume success unless we hit a failure condition
+ result.success := TRUE;
+
+ -- Fail if the user is BARRED
+ SELECT INTO user_object * FROM actor.usr WHERE id = match_user;
+
+ -- Fail if we couldn't find the user
+ IF user_object.id IS NULL THEN
+ result.fail_part := 'no_user';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ RETURN;
+ END IF;
+
+ SELECT INTO item_object * FROM asset.copy WHERE id = match_item;
+
+ -- Fail if we couldn't find the item
+ IF item_object.id IS NULL THEN
+ result.fail_part := 'no_item';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ RETURN;
+ END IF;
+
+ IF user_object.barred IS TRUE THEN
+ result.fail_part := 'actor.usr.barred';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+
+ -- Fail if the item can't circulate
+ IF item_object.circulate IS FALSE THEN
+ result.fail_part := 'asset.copy.circulate';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+
+ -- Fail if the item isn't in a circulateable status on a non-renewal
+ IF NOT renewal AND item_object.status NOT IN ( 0, 7, 8 ) THEN
+ result.fail_part := 'asset.copy.status';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ ELSIF renewal AND item_object.status <> 1 THEN
+ result.fail_part := 'asset.copy.status';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+
+ -- Fail if the item can't circulate because of the shelving location
+ SELECT INTO item_location_object * FROM asset.copy_location WHERE id = item_object.location;
+ IF item_location_object.circulate IS FALSE THEN
+ result.fail_part := 'asset.copy_location.circulate';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+
+ SELECT INTO circ_test * FROM action.find_circ_matrix_matchpoint(circ_ou, item_object, user_object, renewal);
+
+ circ_matchpoint := circ_test.matchpoint;
+ result.matchpoint := circ_matchpoint.id;
+ result.circulate := circ_matchpoint.circulate;
+ result.duration_rule := circ_matchpoint.duration_rule;
+ result.recurring_fine_rule := circ_matchpoint.recurring_fine_rule;
+ result.max_fine_rule := circ_matchpoint.max_fine_rule;
+ result.hard_due_date := circ_matchpoint.hard_due_date;
+ result.renewals := circ_matchpoint.renewals;
+ result.grace_period := circ_matchpoint.grace_period;
+ result.buildrows := circ_test.buildrows;
+
+ -- Fail if we couldn't find a matchpoint
+ IF circ_test.success = false THEN
+ result.fail_part := 'no_matchpoint';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ RETURN; -- All tests after this point require a matchpoint. No sense in running on an incomplete or missing one.
+ END IF;
+
+ -- Apparently....use the circ matchpoint org unit to determine what org units are valid.
+ SELECT INTO context_org_list ARRAY_ACCUM(id) FROM actor.org_unit_full_path( circ_matchpoint.org_unit );
+
+ IF renewal THEN
+ penalty_type = '%RENEW%';
+ ELSE
+ penalty_type = '%CIRC%';
+ END IF;
+
+ FOR standing_penalty IN
+ SELECT DISTINCT csp.*
+ FROM actor.usr_standing_penalty usp
+ JOIN config.standing_penalty csp ON (csp.id = usp.standing_penalty)
+ WHERE usr = match_user
+ AND usp.org_unit IN ( SELECT * FROM unnest(context_org_list) )
+ AND (usp.stop_date IS NULL or usp.stop_date > NOW())
+ AND csp.block_list LIKE penalty_type LOOP
+
+ result.fail_part := standing_penalty.name;
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END LOOP;
+
+ -- Fail if the test is set to hard non-circulating
+ IF circ_matchpoint.circulate IS FALSE THEN
+ result.fail_part := 'config.circ_matrix_test.circulate';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+
+ -- Fail if the total copy-hold ratio is too low
+ IF circ_matchpoint.total_copy_hold_ratio IS NOT NULL THEN
+ SELECT INTO hold_ratio * FROM action.copy_related_hold_stats(match_item);
+ IF hold_ratio.total_copy_ratio IS NOT NULL AND hold_ratio.total_copy_ratio < circ_matchpoint.total_copy_hold_ratio THEN
+ result.fail_part := 'config.circ_matrix_test.total_copy_hold_ratio';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+ END IF;
+
+ -- Fail if the available copy-hold ratio is too low
+ IF circ_matchpoint.available_copy_hold_ratio IS NOT NULL THEN
+ IF hold_ratio.hold_count IS NULL THEN
+ SELECT INTO hold_ratio * FROM action.copy_related_hold_stats(match_item);
+ END IF;
+ IF hold_ratio.available_copy_ratio IS NOT NULL AND hold_ratio.available_copy_ratio < circ_matchpoint.available_copy_hold_ratio THEN
+ result.fail_part := 'config.circ_matrix_test.available_copy_hold_ratio';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+ END IF;
+
+ -- Fail if the user has too many items with specific circ_modifiers checked out
+ FOR out_by_circ_mod IN SELECT * FROM config.circ_matrix_circ_mod_test WHERE matchpoint = circ_matchpoint.id LOOP
+ SELECT INTO items_out COUNT(*)
+ FROM action.circulation circ
+ JOIN asset.copy cp ON (cp.id = circ.target_copy)
+ WHERE circ.usr = match_user
+ AND circ.circ_lib IN ( SELECT * FROM unnest(context_org_list) )
+ AND circ.checkin_time IS NULL
+ AND (circ.stop_fines IN ('MAXFINES','LONGOVERDUE') OR circ.stop_fines IS NULL)
+ AND cp.circ_modifier IN (SELECT circ_mod FROM config.circ_matrix_circ_mod_test_map WHERE circ_mod_test = out_by_circ_mod.id);
+ IF items_out >= out_by_circ_mod.items_out THEN
+ result.fail_part := 'config.circ_matrix_circ_mod_test';
+ result.success := FALSE;
+ done := TRUE;
+ RETURN NEXT result;
+ END IF;
+ END LOOP;
+
+ -- If we passed everything, return the successful matchpoint id
+ IF NOT done THEN
+ RETURN NEXT result;
+ END IF;
+
+ RETURN;
+END;
+$func$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION action.item_user_circ_test( INT, BIGINT, INT ) RETURNS SETOF action.circ_matrix_test_result AS $func$
+ SELECT * FROM action.item_user_circ_test( $1, $2, $3, FALSE );
+$func$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION action.item_user_renew_test( INT, BIGINT, INT ) RETURNS SETOF action.circ_matrix_test_result AS $func$
+ SELECT * FROM action.item_user_circ_test( $1, $2, $3, TRUE );
+$func$ LANGUAGE SQL;
+
+-- Update recurring fine rules
+UPDATE config.rule_recurring_fine SET grace_period=recurrence_interval;
+
+-- Update Circulation Data
+-- Only update if we were told to and the circ hasn't been checked in
+UPDATE action.circulation SET grace_period=fine_interval WHERE :CircGrace AND (checkin_time IS NULL);
+
+COMMIT;
Modified: trunk/Open-ILS/src/support-scripts/fine_generator.pl
===================================================================
--- trunk/Open-ILS/src/support-scripts/fine_generator.pl 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/src/support-scripts/fine_generator.pl 2011-03-19 14:33:18 UTC (rev 19823)
@@ -1,7 +1,7 @@
#!/usr/bin/perl
# ---------------------------------------------------------------------
-# Fine generator with default grace period param.
-# ./object_dumper.pl <bootstrap_config> <lockfile> <grace (default 0)>
+# Fine generator
+# ./fine_generator.pl <bootstrap_config> <lockfile>
# ---------------------------------------------------------------------
use strict;
@@ -15,7 +15,9 @@
my $lockfile = shift || "/tmp/generate_fines-LOCK";
my $grace = shift;
-$grace = '' if (!defined($grace) or $grace == 0);
+if (defined($grace)) {
+ die "Grace period is now defined in the database. It should not be passed to the fine generator.";
+}
if (-e $lockfile) {
open(F,$lockfile);
@@ -44,7 +46,7 @@
my $r = OpenSRF::AppSession
->create( 'open-ils.storage' )
- ->request( 'open-ils.storage.action.circulation.overdue.generate_fines' => $grace );
+ ->request( 'open-ils.storage.action.circulation.overdue.generate_fines' );
while (!$r->complete) { $r->recv };
@@ -57,10 +59,10 @@
);
my $storage = OpenSRF::AppSession->create("open-ils.storage");
- my $r = $storage->request('open-ils.storage.action.circulation.overdue.id_list', $grace);
+ my $r = $storage->request('open-ils.storage.action.circulation.overdue.id_list');
while (my $resp = $r->recv) {
my $circ_id = $resp->content;
- $multi_generator->request( 'open-ils.storage.action.circulation.overdue.generate_fines', $grace, $circ_id );
+ $multi_generator->request( 'open-ils.storage.action.circulation.overdue.generate_fines', $circ_id );
}
$storage->disconnect();
$multi_generator->session_wait(1);
Modified: trunk/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js
===================================================================
--- trunk/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/web/js/ui/default/conify/global/config/circ_matrix_matchpoint.js 2011-03-19 14:33:18 UTC (rev 19823)
@@ -23,6 +23,7 @@
cmGrid.overrideWidgetArgs.available_copy_hold_ratio = {inherits : true};
cmGrid.overrideWidgetArgs.total_copy_hold_ratio = {inherits : true};
cmGrid.overrideWidgetArgs.renewals = {inherits : true};
+ cmGrid.overrideWidgetArgs.grace_period = {inherits : true};
cmGrid.overrideWidgetArgs.hard_due_date = {inherits : true};
cmGrid.loadAll({order_by:{ccmm:'circ_modifier'}});
cmGrid.onEditPane = buildEditPaneAdditions;
Modified: trunk/Open-ILS/web/templates/default/conify/global/config/circ_matrix_matchpoint.tt2
===================================================================
--- trunk/Open-ILS/web/templates/default/conify/global/config/circ_matrix_matchpoint.tt2 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/web/templates/default/conify/global/config/circ_matrix_matchpoint.tt2 2011-03-19 14:33:18 UTC (rev 19823)
@@ -9,7 +9,7 @@
<table jsId="cmGrid"
style="height: 600px;"
dojoType="openils.widget.AutoGrid"
- fieldOrder="['id', 'active', 'grp', 'org_unit', 'copy_circ_lib', 'copy_owning_lib', 'user_home_ou', 'is_renewal', 'juvenile_flag', 'circ_modifier', 'marc_type', 'marc_form', 'marc_vr_format', 'ref_flag', 'usr_age_lower_bound', 'usr_age_upper_bound', 'circulate', 'duration_rule', 'renewals', 'hard_due_date', 'recurring_fine_rule', 'max_fine_rule', 'available_copy_hold_ratio', 'total_copy_hold_ratio', 'script_test']"
+ fieldOrder="['id', 'active', 'grp', 'org_unit', 'copy_circ_lib', 'copy_owning_lib', 'user_home_ou', 'is_renewal', 'juvenile_flag', 'circ_modifier', 'marc_type', 'marc_form', 'marc_vr_format', 'ref_flag', 'usr_age_lower_bound', 'usr_age_upper_bound', 'circulate', 'duration_rule', 'renewals', 'hard_due_date', 'recurring_fine_rule', 'grace_period', 'max_fine_rule', 'available_copy_hold_ratio', 'total_copy_hold_ratio', 'script_test']"
defaultCellWidth='"auto"'
query="{id: '*'}"
fmClass='ccmm'
Modified: trunk/Open-ILS/web/templates/default/conify/global/config/rule_recurring_fine.tt2
===================================================================
--- trunk/Open-ILS/web/templates/default/conify/global/config/rule_recurring_fine.tt2 2011-03-19 05:48:01 UTC (rev 19822)
+++ trunk/Open-ILS/web/templates/default/conify/global/config/rule_recurring_fine.tt2 2011-03-19 14:33:18 UTC (rev 19823)
@@ -11,7 +11,7 @@
<div>
<table jsId="ruleRecurringFineGrid"
dojoType="openils.widget.AutoGrid"
- fieldOrder="['name', 'recurrence_interval', 'low', 'normal', 'high']"
+ fieldOrder="['name', 'recurrence_interval', 'low', 'normal', 'high', 'grace_period']"
suppressFields="['id']"
query="{id: '*'}"
fmClass='crrf'
More information about the open-ils-commits
mailing list