LP 1169193 long-overdue automated processing
authorBill Erickson <berick@esilibrary.com>
Wed, 17 Apr 2013 14:31:04 +0000 (10:31 -0400)
committerJason Stephenson <jstephenson@mvlc.org>
Fri, 9 Aug 2013 19:58:18 +0000 (15:58 -0400)
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@esilibrary.com>
Signed-off-by: Jason Stephenson <jstephenson@mvlc.org>
Open-ILS/examples/action_trigger_filters.json.example
Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Reactor/MarkItemLongOverdue.pm [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/Application/Trigger/Validator.pm

index d599d7b..31d713d 100644 (file)
@@ -4,7 +4,7 @@
       "filter"      :
             { "checkin_time"  : null,
               "-or"           :
-                    [ { "stop_fines"  : ["MAXFINES", "LONGOVERDUE"] },
+                    [ { "stop_fines"  : ["MAXFINES"] },
                       { "stop_fines"  : null }
                     ]
             }
index 0e67974..1cf8cc8 100644 (file)
@@ -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 (file)
index 0000000..26e6aae
--- /dev/null
@@ -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;
index 6b5dc3c..db909a5 100644 (file)
@@ -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;