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

Evergreen Git git at git.evergreen-ils.org
Fri Aug 9 16:04:25 EDT 2013


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

The branch, master has been updated
       via  1d7b2ffb0fc3f76dfb92f918419334afb2c418b7 (commit)
       via  3dcdcf427477cd875bb40c1ab88746bb053b3c22 (commit)
       via  91e7fe44a8ca68b126715b767dd0cdb361edf2e3 (commit)
       via  5d842e5791092ece4647ede0ab288744447bdf16 (commit)
       via  ceb56824e7ca2031366580b2d41397bdcc8102d4 (commit)
       via  69573105e2498ebc34f3de26882af95268d46c28 (commit)
       via  18f672d40658964f85657713c743acafe22f3633 (commit)
       via  feb1c3f2044add1cf6a262824f7e2082a372253c (commit)
      from  e071eb91a40d3871bc0e0a078b88cfdde7ba3b5e (commit)

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

- Log -----------------------------------------------------------------
commit 1d7b2ffb0fc3f76dfb92f918419334afb2c418b7
Author: Jason Stephenson <jstephenson at mvlc.org>
Date:   Fri Aug 9 16:03:47 2013 -0400

    Stamping upgrade script for long overdue status -- LP 1169193.
    
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>

diff --git a/Open-ILS/src/sql/Pg/002.schema.config.sql b/Open-ILS/src/sql/Pg/002.schema.config.sql
index 6028fc8..e33fa31 100644
--- a/Open-ILS/src/sql/Pg/002.schema.config.sql
+++ b/Open-ILS/src/sql/Pg/002.schema.config.sql
@@ -91,7 +91,7 @@ CREATE TRIGGER no_overlapping_deps
     BEFORE INSERT OR UPDATE ON config.db_patch_dependencies
     FOR EACH ROW EXECUTE PROCEDURE evergreen.array_overlap_check ('deprecates');
 
-INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0816', :eg_version); -- eeevil/senator/dbwells
+INSERT INTO config.upgrade_log (version, applied_to) VALUES ('0817', :eg_version); -- berick/Dyrcona
 
 CREATE TABLE config.bib_source (
 	id		SERIAL	PRIMARY KEY,
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.long-overdue.sql b/Open-ILS/src/sql/Pg/upgrade/0817.data.long-overdue.sql
similarity index 99%
rename from Open-ILS/src/sql/Pg/upgrade/XXXX.data.long-overdue.sql
rename to Open-ILS/src/sql/Pg/upgrade/0817.data.long-overdue.sql
index d66bf50..c0ddeac 100644
--- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.long-overdue.sql
+++ b/Open-ILS/src/sql/Pg/upgrade/0817.data.long-overdue.sql
@@ -2,7 +2,7 @@ BEGIN;
 
 -- NOTE: very IDs are still correct for perms and event_def data at merge.
 
--- SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+SELECT evergreen.upgrade_deps_block_check('0817', :eg_version);
 
 -- copy status
 

commit 3dcdcf427477cd875bb40c1ab88746bb053b3c22
Author: Bill Erickson <berick at esilibrary.com>
Date:   Mon May 6 11:01:52 2013 -0400

    LP 1169193 Support L/O xact close on paid
    
    Middle-layer support for the org unit setting "Leave transaction
    open when long overdue balance equals zero".  It behaves the same
    as "Leave transaction open when lost balance equals zero", but for
    long-overdue circs.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CircCommon.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CircCommon.pm
index 03dc4d5..2901ec5 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CircCommon.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CircCommon.pm
@@ -235,7 +235,22 @@ sub can_close_circ {
                 )
             );
         }
+
+    } elsif ($reason eq OILS_STOP_FINES_LONGOVERDUE) {
+        # Check the copy circ_lib to see if they close
+        # transactions when long-overdue are paid.
+        my $copy = $e->retrieve_asset_copy($circ->target_copy);
+        if ($copy) {
+            $can_close = !$U->is_true(
+                $U->ou_ancestor_setting_value(
+                    $copy->circ_lib,
+                    'circ.longoverdue.xact_open_on_zero',
+                    $e
+                )
+            );
+        }
     }
+
     return $can_close;
 }
 

commit 91e7fe44a8ca68b126715b767dd0cdb361edf2e3
Author: Bill Erickson <berick at esilibrary.com>
Date:   Fri Apr 26 12:59:33 2013 -0400

    LP 1169193 Bypass longoverdue w/ default A/T runner
    
    Avoid processing LONGOVERDUE circulations in the default
    action_trigger_runner.pl filter.
    
    When no custom filters are used, the script will provide it's own
    default filter for circulation-based hooks.  This change ensure that
    when the default filter is in use, the script will not attempt to
    process longoverdue circulations, since they have already been processed
    (which is how they became longoverdue in the first place).
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>

diff --git a/Open-ILS/src/support-scripts/action_trigger_runner.pl b/Open-ILS/src/support-scripts/action_trigger_runner.pl
index 0225518..9e219f0 100755
--- a/Open-ILS/src/support-scripts/action_trigger_runner.pl
+++ b/Open-ILS/src/support-scripts/action_trigger_runner.pl
@@ -72,7 +72,7 @@ my $hook_handlers = {
         filter => {
             checkin_time => undef, 
             '-or' => [
-                {stop_fines => ['MAXFINES', 'LONGOVERDUE']}, 
+                {stop_fines => ['MAXFINES']}, 
                 {stop_fines => undef}
             ]
         }

commit 5d842e5791092ece4647ede0ab288744447bdf16
Author: Bill Erickson <berick at esilibrary.com>
Date:   Wed Apr 24 14:09:12 2013 -0400

    LP 1169193 long-overdue release notes
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>

diff --git a/docs/RELEASE_NOTES_NEXT/Circulation/long-overdue.txt b/docs/RELEASE_NOTES_NEXT/Circulation/long-overdue.txt
new file mode 100644
index 0000000..89f07cc
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/Circulation/long-overdue.txt
@@ -0,0 +1,92 @@
+Long Overdue Circulations Management
+====================================
+
+This is a two-part feature, which covers marking circulations as long
+overdue via automated processing and check-in of long overdue circulations.
+
+Marking Circulations Long Overdue
+---------------------------------
+
+A new Action/Trigger reactor (MarkItemLongOverdue) and sample event 
+definition (6 Month Overdue Mark Long-Overdue) are included for 
+marking circulations and their associated copies as long overdue.  New org
+unit settings determine whether the item price and/or a processing fee is
+applied.  
+
+A secondary Action/Trigger hook (longoverdue.auto) and sample event 
+definition (6 Month Long Overdue Notice) are added so that (email, etc.) 
+notifications can be sent when a circulation is marked long overdue via
+this new automated process.
+
+Also included is a new Action/Trigger validator PatronNotInCollections, which
+can be used to prevent long overdue processing (or any circ-based event 
+definition) for patrons that are in collections processing at (or above) the 
+circulating library.
+
+New Org Unit Settings
+~~~~~~~~~~~~~~~~~~~~~
+
+ * Long-Overdue Materials Processing Fee
+ * Void Overdue Fines When Items are Marked Long-Overdue
+ * Leave transaction open when long overdue balance equals zero
+
+A combination of 'Charge lost on zero' and 'Default Item Price' are used to
+determine the amount to charge for the item price when a circulation is 
+marked as long overdue.
+
+New Billing Types
+~~~~~~~~~~~~~~~~~
+
+ * Long-Overdue Materials
+ * Long-Overdue Materials Processing Fee
+
+New Permissions
+~~~~~~~~~~~~~~~
+
+ * SET_CIRC_LONG_OVERDUE
+
+New Copy Status
+~~~~~~~~~~~~~~~
+
+ * Long Overdue
+
+Check-in of Long Overdue Circulations
+-------------------------------------
+
+Check-in of long overdue items may result in any of the following actions, 
+depending on configuration.
+
+ * Void the copy price billing 
+ * Void the long-overdue processing fee billing 
+ * Reinstate voided overdue fines 
+
+The process is practically identical to Lost processing.  However, one
+difference between Lost and Long Overdue check-in is that the window
+of time during which a long overdue item may be returned may be based on the
+due date (like Lost) or the last billing activity date (last payment, last 
+billing).  This is controlled with the "Long-Overdue Check-In Interval Uses 
+Last Activity Date" org unit setting.
+
+New Org Unit Settings
+~~~~~~~~~~~~~~~~~~~~~
+
+ * Long-Overdue Items Usable on Checkin
+ * Long-Overdue Max Return Interval
+ * Restore Overdues on Long-Overdue Item Return
+ * Void Long-Overdue Item Billing When Returned
+ * Void Processing Fee on Long-Overdue Item Return
+ * Long-Overdue Check-In Interval Uses Last Activity Date
+
+New Permissions
+~~~~~~~~~~~~~~~
+
+ * COPY_STATUS_LONGOVERDUE.override
+
+Upgrade Notes
+-------------
+
+If you are using a custom version of the 
+'/openils/conf/action_trigger_filters.json.example' file, you will need to 
+merge the changes made by this feature into your file.  The change in 
+question alters the 'checkout.due' hook such that LONGOVERDUE circulations 
+are no longer treated as regular overdue items.

commit ceb56824e7ca2031366580b2d41397bdcc8102d4
Author: Bill Erickson <berick at esilibrary.com>
Date:   Wed Apr 24 11:05:02 2013 -0400

    LP 1169193 transit_slip macro for copy status
    
    Adds support for a new 'transit_slip' receipt template macro called
    "transit_copy_status", which displays the stored status of the
    in-transit copy (i.e. the status the copy will be placed in once it
    arrives at the transit destination).  This is useful, in particular, for
    lost or long-overdue items which are not "immediately available" upon
    checkin.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>

diff --git a/Open-ILS/xul/staff_client/server/circ/util.js b/Open-ILS/xul/staff_client/server/circ/util.js
index c3a9c55..5b81b63 100644
--- a/Open-ILS/xul/staff_client/server/circ/util.js
+++ b/Open-ILS/xul/staff_client/server/circ/util.js
@@ -1,5 +1,4 @@
 dump('entering circ/util.js\n');
-// vim:noet:sw=4:ts=4:
 
 if (typeof circ == 'undefined') { var circ = {}; }
 circ.util = {};
@@ -1827,6 +1826,24 @@ circ.util.transit_columns = function(modify,params) {
             'hidden' : true,
             'editable' : false, 'render' : function(my) { return my.atc.target_copy(); }
         },
+        {
+            // status of the copy on the transit, not "in-transit".
+            // putting this here allows 'transit_copy_status' to
+            // appear as a MACRO for the 'transit_slip' receipt.
+            // Note that the actual value (for checkin) is 
+            // collected below in circ.util.checkin_via_barcode2().
+            'persist' : 'hidden width ordinal',
+            'id' : 'transit_copy_status',
+            'label' : document.getElementById('circStrings').
+                getString('staff.circ.utils.transit_copy_status'),
+            'flex' : 1,
+            'primary' : false,
+            'hidden' : true,
+            'editable' : false,
+            'render' : function(my) {
+                return data.hash.ccs[ my.atc.copy_status() ].name();
+            }
+        },
     ];
     for (var i = 0; i < c.length; i++) {
         if (modify[ c[i].id ]) {
@@ -2978,7 +2995,8 @@ circ.util.checkin_via_barcode2 = function(session,params,backdate,auto_print,che
             'slip_date' : '',
             'slip_date_msg' : '',
             'user' : '',
-            'user_stat_cat_entries' : ''
+            'user_stat_cat_entries' : '',
+            'transit_copy_status' : ''
         };
 
         if (check.payload && check.payload.cancelled_hold_transit) {
@@ -3483,6 +3501,13 @@ circ.util.checkin_via_barcode2 = function(session,params,backdate,auto_print,che
             print_data.item_author = payload_author;
             msg += print_data.item_author_msg;
             msg += '\n';
+            if (check.payload.transit) {
+                // by adding this here, we make the data available to the
+                // receipt printing engine, but since we are not appending it
+                // to the 'msg', it will not display in the pre-print dialog.
+                print_data.transit_copy_status = 
+                    data.hash.ccs[check.payload.transit.copy_status()].name();
+            }
             JSAN.use('util.date');
             if (check.payload.hold) {
                 check.what_happened = 'transit_for_hold';
diff --git a/Open-ILS/xul/staff_client/server/locale/en-US/circ.properties b/Open-ILS/xul/staff_client/server/locale/en-US/circ.properties
index cf4ae70..74402fb 100644
--- a/Open-ILS/xul/staff_client/server/locale/en-US/circ.properties
+++ b/Open-ILS/xul/staff_client/server/locale/en-US/circ.properties
@@ -307,6 +307,7 @@ staff.circ.utils.transit_source_send_time=Transit Send Time
 staff.circ.utils.transit_dest=Transit Destination
 staff.circ.utils.transit_dest_recv_time=Transit Completion Time
 staff.circ.utils.transit_target_copy=Transit Copy ID
+staff.circ.utils.transit_copy_status=Transit Copy Status
 staff.circ.utils.request_lib=Request Library (Full Name)
 staff.circ.utils.request_lib_shortname=Request Library
 staff.circ.utils.request_time=Request Date

commit 69573105e2498ebc34f3de26882af95268d46c28
Author: Bill Erickson <berick at esilibrary.com>
Date:   Mon Apr 22 13:05:14 2013 -0400

    LP 1169193 long-overdue item checkin
    
    Checkin of long-overdue items now goes through a very simimlar process
    as check-in of Lost items.  Staff can control how long after the due
    date (and potentially other date-related fields) the item may be
    returned for a configurable set of refunds and/or reinstatement of
    overdue fines.  All settings are controlled by a series of new org unit
    settings specifically related to long-overdue processing.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>

diff --git a/Open-ILS/src/extras/ils_events.xml b/Open-ILS/src/extras/ils_events.xml
index 9706603..b8e3086 100644
--- a/Open-ILS/src/extras/ils_events.xml
+++ b/Open-ILS/src/extras/ils_events.xml
@@ -912,7 +912,9 @@
 	<event code="7024" textcode="HOLD_RESERVATION_CONFLICT">
 		<desc xml:lang="en-US">Both a hold and a reservation exist for this item; staff intervention is required to resolve the conflict.</desc>
 	</event>
-
+	<event code='7025' textcode='COPY_STATUS_LONG_OVERDUE'>
+		<desc xml:lang="en-US">Copy is marked as long-overdue</desc>
+	</event>
 
 
 	<!-- ================================================================ -->
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
index e01bbc9..2e5924e 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Circulate.pm
@@ -2932,6 +2932,9 @@ sub checkin_build_copy_transit {
             unless $self->editor->create_action_transit_copy($transit);
     }
 
+    # ensure the transit is returned to the caller
+    $self->transit($transit);
+
     $copy->status(OILS_COPY_STATUS_IN_TRANSIT);
     $self->update_copy;
     $self->checkin_changed(1);
@@ -3413,6 +3416,9 @@ sub checkin_handle_circ {
         # we will need to call lost fine handling code both when checking items
         # in and also when receiving transits
         $self->checkin_handle_lost($circ_lib);
+    } elsif ($stat == OILS_COPY_STATUS_LONG_OVERDUE) {
+        # same process as above.
+        $self->checkin_handle_long_overdue($circ_lib);
     } elsif ($circ_lib != $self->circ_lib and $stat == OILS_COPY_STATUS_MISSING) {
         $logger->info("circulator: not updating copy status on checkin because copy is missing");
     } else {
@@ -3433,63 +3439,171 @@ sub checkin_handle_circ {
     return undef;
 }
 
-
 # ------------------------------------------------------------------
-# See if we need to void billings for lost checkin
+# See if we need to void billings, etc. for lost checkin
 # ------------------------------------------------------------------
 sub checkin_handle_lost {
     my $self = shift;
     my $circ_lib = shift;
-    my $circ = $self->circ;
 
-    my $max_return = $U->ou_ancestor_setting_value(
-        $circ_lib, OILS_SETTING_MAX_ACCEPT_RETURN_OF_LOST, $self->editor) || 0;
+    my $max_return = $U->ou_ancestor_setting_value($circ_lib, 
+        OILS_SETTING_MAX_ACCEPT_RETURN_OF_LOST, $self->editor) || 0;
+
+    return $self->checkin_handle_lost_or_longoverdue(
+        circ_lib => $circ_lib,
+        max_return => $max_return,
+        ous_void_item_cost => OILS_SETTING_VOID_LOST_ON_CHECKIN,
+        ous_void_proc_fee => OILS_SETTING_VOID_LOST_PROCESS_FEE_ON_CHECKIN,
+        ous_restore_overdue => OILS_SETTING_RESTORE_OVERDUE_ON_LOST_RETURN,
+        ous_immediately_available => OILS_SETTING_LOST_IMMEDIATELY_AVAILABLE,
+        ous_use_last_activity => undef, # not supported for LOST checkin
+        void_cost_btype => 3, 
+        void_fee_btype => 4 
+    );
+}
+
+# ------------------------------------------------------------------
+# See if we need to void billings, etc. for long-overdue checkin
+# note: not using constants below since they serve little purpose 
+# for single-use strings that are descriptive in their own right 
+# and mostly just complicate debugging.
+# ------------------------------------------------------------------
+sub checkin_handle_long_overdue {
+    my $self = shift;
+    my $circ_lib = shift;
+
+    $logger->info("circulator: processing long-overdue checkin...");
+
+    my $max_return = $U->ou_ancestor_setting_value($circ_lib, 
+        'circ.max_accept_return_of_longoverdue', $self->editor) || 0;
+
+    return $self->checkin_handle_lost_or_longoverdue(
+        circ_lib => $circ_lib,
+        max_return => $max_return,
+        is_longoverdue => 1,
+        ous_void_item_cost => 'circ.void_longoverdue_on_checkin',
+        ous_void_proc_fee => 'circ.void_longoverdue_proc_fee_on_checkin',
+        ous_restore_overdue => 'circ.restore_overdue_on_longoverdue_return',
+        ous_immediately_available => 'circ.longoverdue_immediately_available',
+        ous_use_last_activity => 
+            'circ.longoverdue.use_last_activity_date_on_return',
+        void_cost_btype => 10,
+        void_fee_btype => 11
+    )
+}
+
+# last billing activity is last payment time, last billing time, or the 
+# circ due date.  If the relevant "use last activity" org unit setting is 
+# false/unset, then last billing activity is always the due date.
+sub get_circ_last_billing_activity {
+    my $self = shift;
+    my $circ_lib = shift;
+    my $setting = shift;
+    my $date = $self->circ->due_date;
+
+    return $date unless $setting and 
+        $U->ou_ancestor_setting_value($circ_lib, $setting, $self->editor);
+
+    my $xact = $self->editor->retrieve_money_billable_transaction([
+        $self->circ->id,
+        {flesh => 1, flesh_fields => {mbt => ['summary']}}
+    ]);
+
+    if ($xact->summary) {
+        $date = $xact->summary->last_payment_ts || 
+                $xact->summary->last_billing_ts || 
+                $self->circ->due_date;
+    }
+
+    return $date;
+}
+
+
+sub checkin_handle_lost_or_longoverdue {
+    my ($self, %args) = @_;
+
+    my $circ = $self->circ;
+    my $max_return = $args{max_return};
+    my $circ_lib = $args{circ_lib};
 
     if ($max_return) {
 
+        my $last_activity = 
+            $self->get_circ_last_billing_activity(
+                $circ_lib, $args{ous_use_last_activity});
+
         my $today = time();
-        my @tm = reverse($circ->due_date =~ /([\d\.]+)/og);
+        my @tm = reverse($last_activity =~ /([\d\.]+)/og);
         $tm[5] -= 1 if $tm[5] > 0;
-        my $due = timelocal(int($tm[1]), int($tm[2]), int($tm[3]), int($tm[4]), int($tm[5]), int($tm[6]));
+        my $due = timelocal(int($tm[1]), int($tm[2]), 
+            int($tm[3]), int($tm[4]), int($tm[5]), int($tm[6]));
+
+        my $last_chance = 
+            OpenSRF::Utils->interval_to_seconds($max_return) + int($due);
 
-        my $last_chance = OpenSRF::Utils->interval_to_seconds($max_return) + int($due);
-        $logger->info("MAX OD: ".$max_return."  DUEDATE: ".$circ->due_date."  TODAY: ".$today."  DUE: ".$due."  LAST: ".$last_chance);
+        $logger->info("MAX OD: $max_return LAST ACTIVITY: ".
+            "$last_activity DUEDATE: ".$circ->due_date." TODAY: $today ".
+                "DUE: $due LAST: $last_chance");
 
         $max_return = 0 if $today < $last_chance;
     }
 
-    if (!$max_return){  # there's either no max time to accept returns defined or we're within that time
 
-        my $void_lost = $U->ou_ancestor_setting_value(
-            $circ_lib, OILS_SETTING_VOID_LOST_ON_CHECKIN, $self->editor) || 0;
-        my $void_lost_fee = $U->ou_ancestor_setting_value(
-            $circ_lib, OILS_SETTING_VOID_LOST_PROCESS_FEE_ON_CHECKIN, $self->editor) || 0;
+    if ($max_return) {
+
+        $logger->info("circulator: check-in of lost/lo item exceeds max ". 
+            "return interval.  skipping fine/fee voiding, etc.");
+
+    } else { # within max-return interval or no interval defined
+
+        $logger->info("circulator: check-in of lost/lo item is within the ".
+            "max return interval (or no interval is defined).  Proceeding ".
+            "with fine/fee voiding, etc.");
+
+        my $void_cost = $U->ou_ancestor_setting_value(
+            $circ_lib, $args{ous_void_item_cost}, $self->editor) || 0;
+        my $void_proc_fee = $U->ou_ancestor_setting_value(
+            $circ_lib, $args{ous_void_proc_fee}, $self->editor) || 0;
         my $restore_od = $U->ou_ancestor_setting_value(
-            $circ_lib, OILS_SETTING_RESTORE_OVERDUE_ON_LOST_RETURN, $self->editor) || 0;
-        $self->generate_lost_overdue(1) if $U->ou_ancestor_setting_value(
-            $circ_lib, OILS_SETTING_GENERATE_OVERDUE_ON_LOST_RETURN, $self->editor);
+            $circ_lib, $args{ous_restore_overdue}, $self->editor) || 0;
+
+        # for reference: generate-overdues-on-long-overdue-checkin is not 
+        # supported because it doesn't make any sense that a circ would be 
+        # marked as long-overdue before it was done being regular-overdue
+        if (!$args{is_longoverdue}) {
+            $self->generate_lost_overdue(1) if 
+                $U->ou_ancestor_setting_value($circ_lib, 
+                    OILS_SETTING_GENERATE_OVERDUE_ON_LOST_RETURN, 
+                    $self->editor);
+        }
 
-        $self->checkin_handle_lost_now_found(3) if $void_lost;
-        $self->checkin_handle_lost_now_found(4) if $void_lost_fee;
-        $self->checkin_handle_lost_now_found_restore_od($circ_lib) if $restore_od && ! $self->void_overdues;
+        $self->checkin_handle_lost_or_lo_now_found(
+            $args{void_cost_btype}, $args{is_longoverdue}) if $void_cost;
+        $self->checkin_handle_lost_or_lo_now_found(
+            $args{void_fee_btype}, $args{is_longoverdue}) if $void_proc_fee;
+        $self->checkin_handle_lost_or_lo_now_found_restore_od($circ_lib) 
+            if $restore_od && ! $self->void_overdues;
     }
 
     if ($circ_lib != $self->circ_lib) {
-        # if the item is not home, check to see if we want to retain the lost
-        # status at this point in the process
-        my $immediately_available = $U->ou_ancestor_setting_value($circ_lib, OILS_SETTING_LOST_IMMEDIATELY_AVAILABLE, $self->editor) || 0;
+        # if the item is not home, check to see if we want to retain the
+        # lost/longoverdue status at this point in the process
+
+        my $immediately_available = $U->ou_ancestor_setting_value($circ_lib, 
+            $args{ous_immediately_available}, $self->editor) || 0;
 
         if ($immediately_available) {
-            # lost item status does not need to be retained, so give it a
+            # item status does not need to be retained, so give it a
             # reshelving status as if it were a normal checkin
             $self->copy->status($U->copy_status(OILS_COPY_STATUS_RESHELVING));
             $self->update_copy;
         } else {
-            $logger->info("circulator: not updating copy status on checkin because copy is lost");
+            $logger->info("circulator: leaving lost/longoverdue copy".
+                " status in place on checkin");
         }
     } else {
-        # lost item is home and processed, treat like a normal checkin from
-        # this point on
+        # lost/longoverdue item is home and processed, treat like a normal 
+        # checkin from this point on
         $self->copy->status($U->copy_status(OILS_COPY_STATUS_RESHELVING));
         $self->update_copy;
     }
@@ -3536,6 +3650,9 @@ sub check_checkin_copy_status {
    return OpenILS::Event->new('COPY_STATUS_LOST', payload => $copy )
       if( $status == OILS_COPY_STATUS_LOST );
 
+   return OpenILS::Event->new('COPY_STATUS_LONG_OVERDUE', payload => $copy )
+      if( $status == OILS_COPY_STATUS_LONG_OVERDUE );
+
    return OpenILS::Event->new('COPY_STATUS_MISSING', payload => $copy )
       if( $status == OILS_COPY_STATUS_MISSING );
 
@@ -3841,8 +3958,8 @@ sub make_trigger_events {
 
 
 
-sub checkin_handle_lost_now_found {
-    my ($self, $bill_type) = @_;
+sub checkin_handle_lost_or_lo_now_found {
+    my ($self, $bill_type, $is_longoverdue) = @_;
 
     # ------------------------------------------------------------------
     # remove charge from patron's account if lost item is returned
@@ -3855,15 +3972,17 @@ sub checkin_handle_lost_now_found {
         }
     );
 
-    $logger->debug("voiding lost item charge of  ".scalar(@$bills));
+    my $tag = $is_longoverdue ? "LONGOVERDUE" : "LOST";
+    
+    $logger->debug("voiding ".scalar(@$bills)." $tag item billings");
     for my $bill (@$bills) {
         if( !$U->is_true($bill->voided) ) {
-            $logger->info("lost item returned - voiding bill ".$bill->id);
+            $logger->info("$tag item returned - voiding bill ".$bill->id);
             $bill->voided('t');
             $bill->void_time('now');
             $bill->voider($self->editor->requestor->id);
             my $note = ($bill->note) ? $bill->note . "\n" : '';
-            $bill->note("${note}System: VOIDED FOR LOST ITEM RETURNED");
+            $bill->note("${note}System: VOIDED FOR $tag ITEM RETURNED");
 
             $self->bail_on_events($self->editor->event)
                 unless $self->editor->update_money_billing($bill);
@@ -3871,9 +3990,11 @@ sub checkin_handle_lost_now_found {
     }
 }
 
-sub checkin_handle_lost_now_found_restore_od {
+sub checkin_handle_lost_or_lo_now_found_restore_od {
     my $self = shift;
     my $circ_lib = shift;
+    my $is_longoverdue = shift;
+    my $tag = $is_longoverdue ? "LONGOVERDUE" : "LOST";
 
     # ------------------------------------------------------------------
     # restore those overdue charges voided when item was set to lost
@@ -3881,20 +4002,20 @@ sub checkin_handle_lost_now_found_restore_od {
 
     my $ods = $self->editor->search_money_billing(
         {
-                xact => $self->circ->id,
-                btype => 1
+            xact => $self->circ->id,
+            btype => 1
         }
     );
 
-    $logger->debug("returning overdue charges pre-lost  ".scalar(@$ods));
+    $logger->debug("returning ".scalar(@$ods)." overdue charges pre-$tag");
     for my $bill (@$ods) {
         if( $U->is_true($bill->voided) ) {
-                $logger->info("lost item returned - restoring overdue ".$bill->id);
+                $logger->info("$tag item returned - restoring overdue ".$bill->id);
                 $bill->voided('f');
                 $bill->clear_void_time;
                 $bill->voider($self->editor->requestor->id);
                 my $note = ($bill->note) ? $bill->note . "\n" : '';
-                $bill->note("${note}System: LOST RETURNED - OVERDUES REINSTATED");
+                $bill->note("${note}System: $tag RETURNED - OVERDUES REINSTATED");
 
                 $self->bail_on_events($self->editor->event)
                         unless $self->editor->update_money_billing($bill);
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Const.pm b/Open-ILS/src/perlmods/lib/OpenILS/Const.pm
index 07db6ed..9bbcdf2 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Const.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Const.pm
@@ -42,6 +42,7 @@ econst OILS_COPY_STATUS_RESERVES      => 12;
 econst OILS_COPY_STATUS_DISCARD       => 13;
 econst OILS_COPY_STATUS_DAMAGED       => 14;
 econst OILS_COPY_STATUS_ON_RESV_SHELF => 15;
+econst OILS_COPY_STATUS_LONG_OVERDUE  => 16;
 
 
 # ---------------------------------------------------------------------
diff --git a/Open-ILS/xul/staff_client/server/circ/checkin.js b/Open-ILS/xul/staff_client/server/circ/checkin.js
index 3f1d976..631122a 100644
--- a/Open-ILS/xul/staff_client/server/circ/checkin.js
+++ b/Open-ILS/xul/staff_client/server/circ/checkin.js
@@ -682,6 +682,7 @@ circ.checkin.prototype = {
                 || checkin.ilsevent == 1203 /* COPY_BAD_STATUS */
                 || checkin.ilsevent == 7009 /* CIRC_CLAIMS_RETURNED */ 
                 || checkin.ilsevent == 7011 /* COPY_STATUS_LOST */ 
+                || checkin.ilsevent == 7025 /* COPY_STATUS_LONG_OVERDUE */ 
                 || checkin.ilsevent == 7012 /* COPY_STATUS_MISSING */) {
                 obj.list.refresh_row( row_params ); 
                 return obj.on_failure();
diff --git a/Open-ILS/xul/staff_client/server/circ/util.js b/Open-ILS/xul/staff_client/server/circ/util.js
index 4c8a080..c3a9c55 100644
--- a/Open-ILS/xul/staff_client/server/circ/util.js
+++ b/Open-ILS/xul/staff_client/server/circ/util.js
@@ -2856,6 +2856,7 @@ circ.util.checkin_via_barcode = function(session,params,backdate,auto_print,asyn
                     7009 /* CIRC_CLAIMS_RETURNED */,
                     7010 /* COPY_ALERT_MESSAGE */,
                     7011 /* COPY_STATUS_LOST */,
+                    7025 /* COPY_STATUS_LONG_OVERDUE */, 
                     7012 /* COPY_STATUS_MISSING */,
                     7013 /* PATRON_EXCEEDS_FINES */
                 ] : [],
@@ -2869,6 +2870,7 @@ circ.util.checkin_via_barcode = function(session,params,backdate,auto_print,asyn
                     7009 /* CIRC_CLAIMS_RETURNED */,
                     7010 /* COPY_ALERT_MESSAGE */,
                     7011 /* COPY_STATUS_LOST */,
+                    7025 /* COPY_STATUS_LONG_OVERDUE */, 
                     7012 /* COPY_STATUS_MISSING */,
                     7013 /* PATRON_EXCEEDS_FINES */,
                     11103 /* TRANSIT_CHECKIN_INTERVAL_BLOCK */ 
@@ -3744,6 +3746,7 @@ circ.util.checkin_via_barcode2 = function(session,params,backdate,auto_print,che
                 case 7009 /* CIRC_CLAIMS_RETURNED */ :
                 case 7010 /* COPY_ALERT_MESSAGE */ :
                 case 7011 /* COPY_STATUS_LOST */ :
+                case 7025 /* COPY_STATUS_LONG_OVERDUE */ :
                 case 7012 /* COPY_STATUS_MISSING */ :
                 case 7013 /* PATRON_EXCEEDS_FINES */ :
                     return null; /* handled */

commit 18f672d40658964f85657713c743acafe22f3633
Author: Bill Erickson <berick at esilibrary.com>
Date:   Wed Apr 17 10:31:04 2013 -0400

    LP 1169193 long-overdue automated processing
    
    Middle layer components for marking circulations long overdue.  The
    automation is controlled with an Action/Trigger event definition
    (sample included in seed data), which uses a new MarkItemLongOverdue
    reactor.  The reactor makes use of a new util function (AssetCommon.pm)
    for doing the actual work and looking up the relevant org unit settings.
    
    Inluded is a new PatronNotInCollections Validator, which can be used to
    avoid marking circulations long overdue for patrons that are in
    collections processing.
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>

diff --git a/Open-ILS/examples/action_trigger_filters.json.example b/Open-ILS/examples/action_trigger_filters.json.example
index d599d7b..31d713d 100644
--- a/Open-ILS/examples/action_trigger_filters.json.example
+++ b/Open-ILS/examples/action_trigger_filters.json.example
@@ -4,7 +4,7 @@
       "filter"      :
             { "checkin_time"  : null,
               "-or"           :
-                    [ { "stop_fines"  : ["MAXFINES", "LONGOVERDUE"] },
+                    [ { "stop_fines"  : ["MAXFINES"] },
                       { "stop_fines"  : null }
                     ]
             }
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm
index 0e67974..1cf8cc8 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm
@@ -642,7 +642,47 @@ sub copy_perm_org {
 
 
 sub set_item_lost {
-    my($class, $e, $copy_id) = @_;
+    my ($class, $e, $copy_id) = @_;
+
+    return $class->set_item_lost_or_lod(
+        $e, $copy_id,
+        perm => 'SET_CIRC_LOST',
+        status => OILS_COPY_STATUS_LOST,
+        ous_proc_fee => OILS_SETTING_LOST_PROCESSING_FEE,
+        ous_void_od => OILS_SETTING_VOID_OVERDUE_ON_LOST,
+        bill_type => 3,
+        bill_fee_type => 4,
+        bill_note => 'Lost Materials',
+        bill_fee_note => 'Lost Materials Processing Fee',
+        event => 'COPY_MARKED_LOST',
+        stop_fines => OILS_STOP_FINES_LOST,
+        at_hook => 'lost'
+    );
+}
+
+sub set_item_long_overdue {
+    my ($class, $e, $copy_id) = @_;
+
+    return $class->set_item_lost_or_lod(
+        $e, $copy_id,
+        perm => 'SET_CIRC_LONG_OVERDUE',
+        status => 16, # Long Overdue
+        ous_proc_fee => 'circ.longoverdue_materials_processing_fee',
+        ous_void_od => 'circ.void_overdue_on_longoverdue',
+        bill_type => 10,
+        bill_fee_type => 11,
+        bill_note => 'Long Overdue Materials',
+        bill_fee_note => 'Long Overdue Materials Processing Fee',
+        event => 'COPY_MARKED_LONG_OVERDUE',
+        stop_fines => 'LONGOVERDUE',
+        at_hook => 'longoverdue'
+    );
+}
+
+# LOST or LONGOVERDUE
+# basic process is the same.  details change.
+sub set_item_lost_or_lod {
+    my ($class, $e, $copy_id, %args) = @_;
 
     my $copy = $e->retrieve_asset_copy([
         $copy_id, 
@@ -657,21 +697,21 @@ sub set_item_lost {
         {checkin_time => undef, target_copy => $copy->id} )->[0]
             or return $e->die_event;
 
-    $e->allowed('SET_CIRC_LOST', $circ->circ_lib) or return $e->die_event;
+    $e->allowed($args{perm}, $circ->circ_lib) or return $e->die_event;
 
-    return $e->die_event(OpenILS::Event->new('COPY_MARKED_LOST'))
-        if $copy->status == OILS_COPY_STATUS_LOST;
+    return $e->die_event(OpenILS::Event->new($args{event}))
+	    if $copy->status == $args{status};
 
     # ---------------------------------------------------------------------
     # fetch the related org settings
     my $proc_fee = $U->ou_ancestor_setting_value(
-        $owning_lib, OILS_SETTING_LOST_PROCESSING_FEE, $e) || 0;
+        $owning_lib, $args{ous_proc_fee}, $e) || 0;
     my $void_overdue = $U->ou_ancestor_setting_value(
-        $owning_lib, OILS_SETTING_VOID_OVERDUE_ON_LOST, $e) || 0;
+        $owning_lib, $args{ous_void_od}, $e) || 0;
 
     # ---------------------------------------------------------------------
     # move the copy into LOST status
-    $copy->status(OILS_COPY_STATUS_LOST);
+    $copy->status($args{status});
     $copy->editor($e->requestor->id);
     $copy->edit_date('now');
     $e->update_asset_copy($copy) or return $e->die_event;
@@ -679,22 +719,22 @@ sub set_item_lost {
     my $price = $U->get_copy_price($e, $copy, $copy->call_number);
 
     if( $price > 0 ) {
-        my $evt = OpenILS::Application::Circ::CircCommon->create_bill(
-            $e, $price, 3, 'Lost Materials', $circ->id);
+        my $evt = OpenILS::Application::Circ::CircCommon->create_bill($e, 
+            $price, $args{bill_type}, $args{bill_note}, $circ->id);
         return $evt if $evt;
     }
 
     # ---------------------------------------------------------------------
     # if there is a processing fee, charge that too
     if( $proc_fee > 0 ) {
-        my $evt = OpenILS::Application::Circ::CircCommon->create_bill(
-            $e, $proc_fee, 4, 'Lost Materials Processing Fee', $circ->id);
+        my $evt = OpenILS::Application::Circ::CircCommon->create_bill($e, 
+            $proc_fee, $args{bill_fee_type}, $args{bill_fee_note}, $circ->id);
         return $evt if $evt;
     }
 
     # ---------------------------------------------------------------------
     # mark the circ as lost and stop the fines
-    $circ->stop_fines(OILS_STOP_FINES_LOST);
+    $circ->stop_fines($args{stop_fines});
     $circ->stop_fines_time('now') unless $circ->stop_fines_time;
     $e->update_action_circulation($circ) or return $e->die_event;
 
@@ -709,9 +749,13 @@ sub set_item_lost {
     return $evt if $evt;
 
     my $ses = OpenSRF::AppSession->create('open-ils.trigger');
-    $ses->request('open-ils.trigger.event.autocreate', 'lost', $circ, $circ->circ_lib);
+    $ses->request(
+        'open-ils.trigger.event.autocreate', 
+        $args{at_hook}, $circ, $circ->circ_lib
+    );
 
-    my $evt2 = OpenILS::Utils::Penalty->calculate_penalties($e, $circ->usr, $U->xact_org($circ->id,$e));
+    my $evt2 = OpenILS::Utils::Penalty->calculate_penalties(
+        $e, $circ->usr, $U->xact_org($circ->id, $e));
     return $evt2 if $evt2;
 
     return undef;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/MarkItemLongOverdue.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/MarkItemLongOverdue.pm
new file mode 100644
index 0000000..26e6aae
--- /dev/null
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/MarkItemLongOverdue.pm
@@ -0,0 +1,60 @@
+package OpenILS::Application::Trigger::Reactor::MarkItemLongOverdue;
+use base 'OpenILS::Application::Trigger::Reactor';
+use strict; use warnings;
+use Error qw/:try/;
+use Data::Dumper;
+use OpenSRF::Utils::Logger qw/:logger/;
+use OpenILS::Utils::CStoreEditor q/:funcs/;
+use OpenILS::Application::Cat::AssetCommon;
+$Data::Dumper::Indent = 0;
+
+
+sub ABOUT {
+    return <<ABOUT;
+    
+    Marks circulation and corresponding item as long-overdue.  This uses
+    the standard mark-long-overdue functionality, creating billings where 
+    appropriate.
+
+    Required event parameters:
+        "editor" which points to a user ID.  This is the user that effectively
+        performs the action.  For example, when the copy status is updated,
+        this user is entered as the last editor of the copy.
+
+ABOUT
+}
+
+sub handler {
+    my $self = shift;
+    my $env = shift;
+    my $e = new_editor(xact => 1);
+
+    my $requestor = $e->retrieve_actor_user($$env{params}{editor});
+
+    if (!$requestor) {
+        $logger->error("trigger: MarkItemLongOverdue require 'editor' param");
+        return 0;
+    }
+
+    $e->requestor($requestor);
+
+    my $circ = $$env{target};
+    my $evt = OpenILS::Application::Cat::AssetCommon->
+        set_item_long_overdue($e, $circ->target_copy);
+
+    if ($evt) {
+        $logger->error("trigger: MarkItemLongOverdue ".
+            "failed with event $evt->{textcode}");
+        return 0;
+    }
+
+    $e->commit;
+
+    my $ses = OpenSRF::AppSession->create('open-ils.trigger');
+    $ses->request('open-ils.trigger.event.autocreate', 
+        'longoverdue.auto', $circ, $circ->circ_lib);
+
+    return 1;
+}
+
+1;
diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Validator.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Validator.pm
index 6b5dc3c..db909a5 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Validator.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Validator.pm
@@ -6,6 +6,7 @@ use OpenSRF::Utils qw/:datetime/;
 use OpenSRF::Utils::Logger qw/:logger/;
 use OpenILS::Const qw/:const/;
 use OpenILS::Application::AppUtils;
+use OpenILS::Utils::CStoreEditor qw/:funcs/;
 sub fourty_two { return 42 }
 sub NOOP_True { return 1 }
 sub NOOP_False { return 0 }
@@ -161,4 +162,30 @@ sub PatronNotBarred {
     return !PatronBarred(@_);
 }
 
+# core type "circ".
+# Being "In Collections" means having the PATRON_IN_COLLECTIONS penalty 
+# applied to the user at or above the circ_lib of the target circ.
+sub PatronNotInCollections {
+    my ($self, $env) = @_;
+    my $user = $env->{target}->usr;
+    my $org = $env->{target}->circ_lib;
+
+    # beware environment fleshing
+    $user = $user->id if ref $user;
+    $org = $org->id if ref $org;
+
+    my $existing = new_editor()->search_actor_user_standing_penalty({
+        usr => $user,
+        org_unit => $U->get_org_ancestors($org, 1),
+        standing_penalty => 30, # PATRON_IN_COLLECTIONS
+        '-or' => [
+            {stop_date => undef},
+            {stop_date => {'>' => 'now'}}
+        ]
+    });
+
+    return @$existing ? 0 : 1;
+}
+
+
 1;

commit feb1c3f2044add1cf6a262824f7e2082a372253c
Author: Bill Erickson <berick at esilibrary.com>
Date:   Mon Apr 15 11:44:26 2013 -0400

    LP 1169193 long-overdue SQL seed data
    
    Seed data for managing long-overdue circulations.
    
    * new copy status
    * new billing types
    * new org settings
    * new permissions
    * sample action/trigger event definitions
    
    Signed-off-by: Bill Erickson <berick at esilibrary.com>
    Signed-off-by: Jason Stephenson <jstephenson at mvlc.org>

diff --git a/Open-ILS/src/sql/Pg/950.data.seed-values.sql b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
index dad8658..dd9405d 100644
--- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql
+++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql
@@ -315,6 +315,10 @@ INSERT INTO config.copy_status (id,name,opac_visible,copy_active) VALUES (12,oil
 INSERT INTO config.copy_status (id,name) VALUES (13,oils_i18n_gettext(13, 'Discard/Weed', 'ccs', 'name'));
 INSERT INTO config.copy_status (id,name) VALUES (14,oils_i18n_gettext(14, 'Damaged', 'ccs', 'name'));
 INSERT INTO config.copy_status (id,name,copy_active) VALUES (15,oils_i18n_gettext(15, 'On reservation shelf', 'ccs', 'name'),'t');
+INSERT INTO config.copy_status
+    (id, name, holdable, opac_visible, copy_active, restrict_copy_delete)
+    VALUES (16, oils_i18n_gettext(16, 'Long Overdue', 'ccs', 'name'), 'f', 'f', 'f', 't');
+
 
 SELECT SETVAL('config.copy_status_id_seq'::TEXT, 100);
 
@@ -491,6 +495,11 @@ INSERT INTO config.billing_type (id, name, owner) VALUES
 	( 8, oils_i18n_gettext(8, 'Damaged Item Processing Fee', 'cbt', 'name'), 1);
 INSERT INTO config.billing_type (id, name, owner) VALUES
 	( 9, oils_i18n_gettext(9, 'Notification Fee', 'cbt', 'name'), 1);
+INSERT INTO config.billing_type (id, owner, name) VALUES
+    (10, 1, oils_i18n_gettext(10, 'Long-Overdue Materials', 'cbt', 'name'));
+INSERT INTO config.billing_type (id, owner, name) VALUES
+    (11, 1, oils_i18n_gettext(11, 'Long-Overdue Materials Processing Fee', 'cbt', 'name'));
+
 
 INSERT INTO config.billing_type (id, name, owner) VALUES ( 101, oils_i18n_gettext(101, 'Misc', 'cbt', 'name'), 1);
 
@@ -1593,7 +1602,12 @@ INSERT INTO permission.perm_list ( id, code, description ) VALUES
  ( 547, 'ACQ_ADD_LINEITEM_IDENTIFIER', oils_i18n_gettext(547,
         'When granted, newly added lineitem identifiers will propagate to linked bib records', 'ppl', 'description')),
  ( 548, 'ACQ_SET_LINEITEM_IDENTIFIER', oils_i18n_gettext(548,
-        'Allows staff to change the lineitem identifier', 'ppl', 'description'))
+        'Allows staff to change the lineitem identifier', 'ppl', 'description')),
+ ( 549, 'COPY_STATUS_LONGOVERDUE.override', oils_i18n_gettext(549,
+        'Allows the user to check-in long-overdue items, prompting ' ||
+            'long-overdue check-in processing', 'ppl', 'code')), 
+ ( 550, 'SET_CIRC_LONG_OVERDUE', oils_i18n_gettext(550,
+        'Allows the user to mark a circulation as long-overdue', 'ppl', 'code'))
 ;
 
 
@@ -12872,3 +12886,236 @@ INSERT INTO config.org_unit_setting_type
         'integer'
     );
 
+-- long overdue stuff...
+
+INSERT INTO config.org_unit_setting_type 
+    (name, grp, datatype, label, description) VALUES 
+(
+    'circ.longoverdue_immediately_available',
+    'circ', 'bool',
+    oils_i18n_gettext(
+        'circ.longoverdue_immediately_available',
+        'Long-Overdue Items Usable on Checkin',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.longoverdue_immediately_available',
+        'Long-overdue items are usable on checkin instead of going "home" first',
+        'coust',
+        'description'
+    )
+), (
+    'circ.longoverdue_materials_processing_fee',
+    'finance', 'currency',
+    oils_i18n_gettext(
+        'circ.longoverdue_materials_processing_fee',
+        'Long-Overdue Materials Processing Fee',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.longoverdue_materials_processing_fee',
+        'Long-Overdue Materials Processing Fee',
+        'coust',
+        'description'
+    )
+), (
+    'circ.max_accept_return_of_longoverdue',
+    'circ', 'interval',
+    oils_i18n_gettext(
+        'circ.max_accept_return_of_longoverdue',
+        'Long-Overdue Max Return Interval',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.max_accept_return_of_longoverdue',
+        'Long-overdue check-in processing (voiding fees, re-instating ' ||
+            'overdues, etc.) will not take place for items that have been ' ||
+            'overdue for (or have last activity older than) this amount of time',
+        'coust',
+        'description'
+    )
+), (
+    'circ.restore_overdue_on_longoverdue_return',
+    'circ', 'bool',
+    oils_i18n_gettext(
+        'circ.restore_overdue_on_longoverdue_return',
+        'Restore Overdues on Long-Overdue Item Return',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.restore_overdue_on_longoverdue_return',
+        'Restore Overdues on Long-Overdue Item Return',
+        'coust',
+        'description'
+    )
+), (
+    'circ.void_longoverdue_on_checkin',
+    'circ', 'bool',
+    oils_i18n_gettext(
+        'circ.void_longoverdue_on_checkin',
+        'Void Long-Overdue Item Billing When Returned',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.void_longoverdue_on_checkin',
+        'Void Long-Overdue Item Billing When Returned',
+        'coust',
+        'description'
+    )
+), (
+    'circ.void_longoverdue_proc_fee_on_checkin',
+    'circ', 'bool',
+    oils_i18n_gettext(
+        'circ.void_longoverdue_proc_fee_on_checkin',
+        'Void Processing Fee on Long-Overdue Item Return',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.void_longoverdue_proc_fee_on_checkin',
+        'Void Processing Fee on Long-Overdue Item Return',
+        'coust',
+        'description'
+    )
+), (
+    'circ.void_overdue_on_longoverdue',
+    'finance', 'bool',
+    oils_i18n_gettext(
+        'circ.void_overdue_on_longoverdue',
+        'Void Overdue Fines When Items are Marked Long-Overdue',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.void_overdue_on_longoverdue',
+        'Void Overdue Fines When Items are Marked Long-Overdue',
+        'coust',
+        'description'
+    )
+), (
+    'circ.longoverdue.xact_open_on_zero',
+    'finance', 'bool',
+    oils_i18n_gettext(
+        'circ.longoverdue.xact_open_on_zero',
+        'Leave transaction open when long overdue balance equals zero',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.longoverdue.xact_open_on_zero',
+        'Leave transaction open when long-overdue balance equals zero.  ' ||
+            'This leaves the lost copy on the patron record when it is paid',
+        'coust',
+        'description'
+    )
+), (
+    'circ.longoverdue.use_last_activity_date_on_return',
+    'circ', 'bool',
+    oils_i18n_gettext(
+        'circ.longoverdue.use_last_activity_date_on_return',
+        'Long-Overdue Check-In Interval Uses Last Activity Date',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.longoverdue.use_last_activity_date_on_return',
+        'Use the long-overdue last-activity date instead of the due_date to ' ||
+            'determine whether the item has been checked out too long to ' ||
+            'perform long-overdue check-in processing.  If set, the system ' ||
+            'will first check the last payment time, followed by the last ' ||
+            'billing time, followed by the due date.  See also ' ||
+            'circ.max_accept_return_of_longoverdue',
+        'coust',
+        'description'
+    )
+);
+
+-- mark long-overdue reactor
+
+INSERT INTO action_trigger.reactor (module, description) VALUES
+(   'MarkItemLongOverdue',
+    oils_i18n_gettext(
+        'MarkItemLongOverdue',
+        'Marks a circulating item as long-overdue and applies configured ' ||
+        'penalties.  Also creates events for the longoverdue.auto hook',
+        'atreact',
+        'description'
+    )
+);
+
+INSERT INTO action_trigger.validator (module, description) VALUES (
+    'PatronNotInCollections', 
+    'Event is valid if the linked patron is not in collections processing ' ||
+        'at the context org unit'
+);
+
+INSERT INTO action_trigger.event_definition 
+    (id, active, owner, name, hook, validator, reactor, delay, delay_field) 
+VALUES (
+    49, FALSE, 1, '6 Month Overdue Mark Long-Overdue', 
+    'checkout.due', 'PatronNotInCollections', 
+    'MarkItemLongOverdue', '6 months', 'due_date'
+);
+
+INSERT INTO action_trigger.event_params (event_def, param, value) VALUES
+    (49, 'editor', '''1''');
+
+-- new longoverdue and longervdue.auto hook.
+
+INSERT INTO action_trigger.hook (key,core_type,description) VALUES (
+    'longoverdue',
+    'circ',
+    'Circulating Item marked long-overdue'
+);
+
+INSERT INTO action_trigger.hook (key,core_type,description) VALUES (
+    'longoverdue.auto',
+    'circ',
+    'Circulating Item automatically marked long-overdue'
+);
+
+-- sample longoverdue.auto notification reactor
+
+INSERT INTO action_trigger.event_definition 
+    (id, active, owner, name, hook, validator, reactor, group_field, template) 
+    VALUES (
+        50, FALSE, 1, '6 Month Long Overdue Notice', 
+        'longoverdue.auto', 'NOOP_True', 'SendEmail', 'usr',
+$$
+[%- USE date -%]
+[%- user = target.0.usr -%]
+To: [%- params.recipient_email || user.email %]
+From: [%- params.sender_email || default_sender %]
+Subject: Overdue Items Marked Long Overdue
+
+Dear [% user.family_name %], [% user.first_given_name %]
+The following items are 6 months overdue and have been marked Long Overdue.
+
+[% FOR circ IN target %]
+    [%- copy_details = helpers.get_copy_bib_basics(circ.target_copy.id) -%]
+    Title: [% copy_details.title %], by [% copy_details.author %]
+    Call Number: [% circ.target_copy.call_number.label %]
+    Shelving Location: [% circ.target_copy.location.name %]
+    Barcode: [% circ.target_copy.barcode %]
+    Due: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]
+    Item Cost: [% helpers.get_copy_price(circ.target_copy) %]
+    Total Owed For Transaction: [% circ.billable_transaction.summary.balance_owed %]
+    Library: [% circ.circ_lib.name %]
+
+[% END %]
+$$);
+
+-- ENV for above
+
+INSERT INTO action_trigger.environment (event_def, path) VALUES 
+    (50, 'target_copy.call_number'),
+    (50, 'usr'),
+    (50, 'billable_transaction.summary'),
+    (50, 'circ_lib.billing_address'),
+    (50, 'target_copy.location');
+
diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.long-overdue.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.long-overdue.sql
new file mode 100644
index 0000000..d66bf50
--- /dev/null
+++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.long-overdue.sql
@@ -0,0 +1,283 @@
+BEGIN;
+
+-- NOTE: very IDs are still correct for perms and event_def data at merge.
+
+-- SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version);
+
+-- copy status
+
+INSERT INTO config.copy_status
+    (id, name, holdable, opac_visible, copy_active, restrict_copy_delete)
+    VALUES (16, oils_i18n_gettext(16, 'Long Overdue', 'ccs', 'name'), 'f', 'f', 'f', 't');
+
+-- checkin override perm
+
+INSERT INTO permission.perm_list (id, code, description) VALUES (
+    549, -- VERIFY
+    'COPY_STATUS_LONGOVERDUE.override',
+    oils_i18n_gettext(
+        549, -- VERIFY
+        'Allows the user to check-in long-overdue items, prompting ' ||
+            'long-overdue check-in processing',
+        'ppl',
+        'code'
+    )
+), (
+    550, -- VERIFY
+    'SET_CIRC_LONG_OVERDUE',
+    oils_i18n_gettext(
+        550, -- VERIFY
+        'Allows the user to mark a circulation as long-overdue',
+        'ppl',
+        'code'
+    )
+);
+
+-- billing types
+
+INSERT INTO config.billing_type (id, owner, name) VALUES
+    (10, 1, oils_i18n_gettext(
+        10, 'Long-Overdue Materials', 'cbt', 'name')),
+    (11, 1, oils_i18n_gettext(
+        11, 'Long-Overdue Materials Processing Fee', 'cbt', 'name'));
+
+-- org settings
+
+INSERT INTO config.org_unit_setting_type 
+    (name, grp, datatype, label, description) VALUES 
+(
+    'circ.longoverdue_immediately_available',
+    'circ', 'bool',
+    oils_i18n_gettext(
+        'circ.longoverdue_immediately_available',
+        'Long-Overdue Items Usable on Checkin',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.longoverdue_immediately_available',
+        'Long-overdue items are usable on checkin instead of going "home" first',
+        'coust',
+        'description'
+    )
+), (
+    'circ.longoverdue_materials_processing_fee',
+    'finance', 'currency',
+    oils_i18n_gettext(
+        'circ.longoverdue_materials_processing_fee',
+        'Long-Overdue Materials Processing Fee',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.longoverdue_materials_processing_fee',
+        'Long-Overdue Materials Processing Fee',
+        'coust',
+        'description'
+    )
+), (
+    'circ.max_accept_return_of_longoverdue',
+    'circ', 'interval',
+    oils_i18n_gettext(
+        'circ.max_accept_return_of_longoverdue',
+        'Long-Overdue Max Return Interval',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.max_accept_return_of_longoverdue',
+        'Long-overdue check-in processing (voiding fees, re-instating ' ||
+            'overdues, etc.) will not take place for items that have been ' ||
+            'overdue for (or have last activity older than) this amount of time',
+        'coust',
+        'description'
+    )
+), (
+    'circ.restore_overdue_on_longoverdue_return',
+    'circ', 'bool',
+    oils_i18n_gettext(
+        'circ.restore_overdue_on_longoverdue_return',
+        'Restore Overdues on Long-Overdue Item Return',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.restore_overdue_on_longoverdue_return',
+        'Restore Overdues on Long-Overdue Item Return',
+        'coust',
+        'description'
+    )
+), (
+    'circ.void_longoverdue_on_checkin',
+    'circ', 'bool',
+    oils_i18n_gettext(
+        'circ.void_longoverdue_on_checkin',
+        'Void Long-Overdue Item Billing When Returned',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.void_longoverdue_on_checkin',
+        'Void Long-Overdue Item Billing When Returned',
+        'coust',
+        'description'
+    )
+), (
+    'circ.void_longoverdue_proc_fee_on_checkin',
+    'circ', 'bool',
+    oils_i18n_gettext(
+        'circ.void_longoverdue_proc_fee_on_checkin',
+        'Void Processing Fee on Long-Overdue Item Return',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.void_longoverdue_proc_fee_on_checkin',
+        'Void Processing Fee on Long-Overdue Item Return',
+        'coust',
+        'description'
+    )
+), (
+    'circ.void_overdue_on_longoverdue',
+    'finance', 'bool',
+    oils_i18n_gettext(
+        'circ.void_overdue_on_longoverdue',
+        'Void Overdue Fines When Items are Marked Long-Overdue',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.void_overdue_on_longoverdue',
+        'Void Overdue Fines When Items are Marked Long-Overdue',
+        'coust',
+        'description'
+    )
+), (
+    'circ.longoverdue.xact_open_on_zero',
+    'finance', 'bool',
+    oils_i18n_gettext(
+        'circ.longoverdue.xact_open_on_zero',
+        'Leave transaction open when long overdue balance equals zero',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.longoverdue.xact_open_on_zero',
+        'Leave transaction open when long-overdue balance equals zero.  ' ||
+            'This leaves the lost copy on the patron record when it is paid',
+        'coust',
+        'description'
+    )
+), (
+    'circ.longoverdue.use_last_activity_date_on_return',
+    'circ', 'bool',
+    oils_i18n_gettext(
+        'circ.longoverdue.use_last_activity_date_on_return',
+        'Long-Overdue Check-In Interval Uses Last Activity Date',
+        'coust',
+        'label'
+    ),
+    oils_i18n_gettext(
+        'circ.longoverdue.use_last_activity_date_on_return',
+        'Use the long-overdue last-activity date instead of the due_date to ' ||
+            'determine whether the item has been checked out too long to ' ||
+            'perform long-overdue check-in processing.  If set, the system ' ||
+            'will first check the last payment time, followed by the last ' ||
+            'billing time, followed by the due date.  See also ' ||
+            'circ.max_accept_return_of_longoverdue',
+        'coust',
+        'description'
+    )
+);
+
+-- mark long-overdue reactor
+
+INSERT INTO action_trigger.reactor (module, description) VALUES
+(   'MarkItemLongOverdue',
+    oils_i18n_gettext(
+        'MarkItemLongOverdue',
+        'Marks a circulating item as long-overdue and applies configured ' ||
+        'penalties.  Also creates events for the longoverdue.auto hook',
+        'atreact',
+        'description'
+    )
+);
+
+INSERT INTO action_trigger.validator (module, description) VALUES (
+    'PatronNotInCollections', 
+    'Event is valid if the linked patron is not in collections processing ' ||
+        'at the context org unit'
+);
+
+-- VERIFY ID
+INSERT INTO action_trigger.event_definition 
+    (id, active, owner, name, hook, validator, reactor, delay, delay_field) 
+VALUES ( 
+    49, FALSE, 1, '6 Month Overdue Mark Long-Overdue', 
+    'checkout.due', 'PatronNotInCollections', 
+    'MarkItemLongOverdue', '6 months', 'due_date'
+);
+
+-- VERIFY ID
+INSERT INTO action_trigger.event_params (event_def, param, value) VALUES
+    (49, 'editor', '''1'''); 
+
+-- new longoverdue and longervdue.auto hook.
+
+INSERT INTO action_trigger.hook (key,core_type,description) VALUES (
+    'longoverdue',
+    'circ',
+    'Circulating Item marked long-overdue'
+);
+
+INSERT INTO action_trigger.hook (key,core_type,description) VALUES (
+    'longoverdue.auto',
+    'circ',
+    'Circulating Item automatically marked long-overdue'
+);
+
+-- sample longoverdue.auto notification reactor
+
+-- VERIFY ID
+INSERT INTO action_trigger.event_definition 
+    (id, active, owner, name, hook, validator, reactor, group_field, template) 
+    VALUES ( 
+        50, FALSE, 1, '6 Month Long Overdue Notice', 
+        'longoverdue.auto', 'NOOP_True', 'SendEmail', 'usr',
+$$
+[%- USE date -%]
+[%- user = target.0.usr -%]
+To: [%- params.recipient_email || user.email %]
+From: [%- params.sender_email || default_sender %]
+Subject: Overdue Items Marked Long Overdue
+
+Dear [% user.family_name %], [% user.first_given_name %]
+The following items are 6 months overdue and have been marked Long Overdue.
+
+[% FOR circ IN target %]
+    [%- copy_details = helpers.get_copy_bib_basics(circ.target_copy.id) -%]
+    Title: [% copy_details.title %], by [% copy_details.author %]
+    Call Number: [% circ.target_copy.call_number.label %]
+    Shelving Location: [% circ.target_copy.location.name %]
+    Barcode: [% circ.target_copy.barcode %]
+    Due: [% date.format(helpers.format_date(circ.due_date), '%Y-%m-%d') %]
+    Item Cost: [% helpers.get_copy_price(circ.target_copy) %]
+    Total Owed For Transaction: [% circ.billable_transaction.summary.balance_owed %]
+    Library: [% circ.circ_lib.name %]
+
+[% END %]
+$$);
+
+-- ENV for above
+
+-- VERIFY IDs
+INSERT INTO action_trigger.environment (event_def, path) VALUES 
+    (50, 'target_copy.call_number'),
+    (50, 'usr'),
+    (50, 'billable_transaction.summary'),
+    (50, 'circ_lib.billing_address'),
+    (50, 'target_copy.location');
+
+
+--ROLLBACK;
+COMMIT;

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

Summary of changes:
 .../examples/action_trigger_filters.json.example   |    2 +-
 Open-ILS/src/extras/ils_events.xml                 |    4 +-
 .../lib/OpenILS/Application/Cat/AssetCommon.pm     |   72 ++++-
 .../lib/OpenILS/Application/Circ/CircCommon.pm     |   15 +
 .../lib/OpenILS/Application/Circ/Circulate.pm      |  197 +++++++++++---
 .../{MarkItemLost.pm => MarkItemLongOverdue.pm}    |   29 ++-
 .../lib/OpenILS/Application/Trigger/Validator.pm   |   27 ++
 Open-ILS/src/perlmods/lib/OpenILS/Const.pm         |    1 +
 Open-ILS/src/sql/Pg/002.schema.config.sql          |    2 +-
 Open-ILS/src/sql/Pg/950.data.seed-values.sql       |  249 +++++++++++++++++-
 .../src/sql/Pg/upgrade/0817.data.long-overdue.sql  |  283 ++++++++++++++++++++
 .../src/support-scripts/action_trigger_runner.pl   |    2 +-
 Open-ILS/xul/staff_client/server/circ/checkin.js   |    1 +
 Open-ILS/xul/staff_client/server/circ/util.js      |   32 ++-
 .../server/locale/en-US/circ.properties            |    1 +
 .../Circulation/long-overdue.txt                   |   92 +++++++
 16 files changed, 942 insertions(+), 67 deletions(-)
 copy Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/{MarkItemLost.pm => MarkItemLongOverdue.pm} (50%)
 create mode 100644 Open-ILS/src/sql/Pg/upgrade/0817.data.long-overdue.sql
 create mode 100644 docs/RELEASE_NOTES_NEXT/Circulation/long-overdue.txt


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list