From: Dan Wells Date: Wed, 3 Dec 2014 19:49:54 +0000 (-0500) Subject: LP#1198465 First pass at generate_fines cstore conversion X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=778fee68372c3639d04e6fd3c51ec342719e3715;p=working%2FEvergreen.git LP#1198465 First pass at generate_fines cstore conversion Broadly speaking, this commit does two things: 1) Rewrite bits of the generate_fines copy in CircCommon.pm to use cstore in place of the DBI code bits. 2) Gut the old generate_fines in Publisher/action.pm, including helper bits, then make it a wrapper for the CircCommon verison. This is a rough pass, but works in basic testing. Signed-off-by: Dan Wells --- 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 e7acd5fce6..2c2d4d3f32 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CircCommon.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CircCommon.pm @@ -354,23 +354,18 @@ sub seconds_to_interval_hash { } sub generate_fines { - my $self = shift; - my $client = shift; - my $circ = shift; - my $stop_fines_reasons = shift; - - local $OpenILS::Application::Storage::WRITE = 1; - - my @circs; - if ($circ) { - push @circs, - action::circulation->search_where( { id => $circ, stop_fines => $stop_fines_reasons } ), - booking::reservation->search_where( { id => $circ, return_time => undef, cancel_time => undef } ); - } else { - push @circs, overdue_circs(); + my ($class, $conn, $args) = @_; + my $circs = $args->{circs}; + return unless $circs and @$circs; + my $e = $args->{editor}; + + my $commit = 0; + unless ($e) { + $e = new_editor(xact => 1); + $commit = 1; } - my %hoo = map { ( $_->id => $_ ) } actor::org_unit::hours_of_operation->retrieve_all; + my %hoo = map { ( $_->id => $_ ) } @{ $e->retrieve_all_actor_org_unit_hours_of_operation }; my $penalty = OpenSRF::AppSession->create('open-ils.penalty'); my $handling_resvs = 0; @@ -378,16 +373,16 @@ sub generate_fines { my $ctype = ref($c); - if (!$ctype) { # fetched via idlist + if (!$ctype) { # we received only an idlist, not objects if ($handling_resvs) { - $c = booking::reservation->retrieve($c); + $c = $e->retrieve_booking_reservation($c); } elsif (not defined $c) { # an undef value is the indicator that we are moving # from processing circulations to reservations. $handling_resvs = 1; next; } else { - $c = action::circulation->retrieve($c); + $c = $e->retrieve_action_circulation($c); } $ctype = ref($c); } @@ -411,12 +406,12 @@ sub generate_fines { my $grace_period = ($is_reservation ? 0 : interval_to_seconds($c->grace_period)); eval { - if ($self->method_lookup('open-ils.storage.transaction.current')->run) { - $log->debug("Cleaning up after previous transaction\n"); - $self->method_lookup('open-ils.storage.transaction.rollback')->run; - } - $self->method_lookup('open-ils.storage.transaction.begin')->run( $client ); - $log->info( +# if ($self->method_lookup('open-ils.storage.transaction.current')->run) { +# $logger->debug("Cleaning up after previous transaction\n"); +# $self->method_lookup('open-ils.storage.transaction.rollback')->run; +# } +# $self->method_lookup('open-ils.storage.transaction.begin')->run( $client ); + $logger->info( sprintf("Processing %s %d...", ($is_reservation ? "reservation" : "circ"), $c->id ) @@ -433,8 +428,8 @@ sub generate_fines { $fine_interval = interval_to_seconds( $fine_interval ); if ( $fine_interval == 0 || int($c->$recurring_fine_method * 100) == 0 || int($c->max_fine * 100) == 0 ) { - $client->respond( "Fine Generator skipping circ due to 0 fine interval, 0 fine rate, or 0 max fine.\n" ); - $log->info( "Fine Generator skipping circ " . $c->id . " due to 0 fine interval, 0 fine rate, or 0 max fine." ); + $conn->respond( "Fine Generator skipping circ due to 0 fine interval, 0 fine rate, or 0 max fine.\n" ); + $logger->info( "Fine Generator skipping circ " . $c->id . " due to 0 fine interval, 0 fine rate, or 0 max fine." ); return; } @@ -448,33 +443,33 @@ sub generate_fines { $now -= ($now % $fine_interval) + $tz_offset_s; } - $client->respond( + $conn->respond( "ARG! Overdue $ctype ".$c->id. " for item ".$c->$target_copy_method. " (user ".$c->usr.").\n". "\tItem was due on or before: ".localtime($due)."\n"); - my @fines = money::billing->search_where( + my @fines = @{$e->search_money_billing( { xact => $c->id, btype => 1, billing_ts => { '>' => $c->$due_date_method } }, { order_by => 'billing_ts DESC'} - ); + )}; my $f_idx = 0; my $fine = $fines[$f_idx] if (@fines); my $current_fine_total = 0; - $current_fine_total += int($_->amount * 100) for (grep { $_ and !$_->voided } @fines); + $current_fine_total += int($_->amount * 100) for (grep { $_ and !$U->is_true($_->voided) } @fines); my $last_fine; if ($fine) { - $client->respond( "Last billing time: ".$fine->billing_ts." (clensed format: ".cleanse_ISO8601( $fine->billing_ts ).")"); + $conn->respond( "Last billing time: ".$fine->billing_ts." (clensed format: ".cleanse_ISO8601( $fine->billing_ts ).")"); $last_fine = $parser->parse_datetime( cleanse_ISO8601( $fine->billing_ts ) )->epoch; } else { - $log->info( "Potential first billing for circ ".$c->id ); + $logger->info( "Potential first billing for circ ".$c->id ); $last_fine = $due; - $grace_period = OpenILS::Application::Circ::CircCommon->extend_grace_period($c->$circ_lib_method->to_fieldmapper->id,$c->$due_date_method,$grace_period,undef,$hoo{$c->$circ_lib_method}); + $grace_period = extend_grace_period($class, $c->$circ_lib_method,$c->$due_date_method,$grace_period,undef,$hoo{$c->$circ_lib_method}); } return if ($last_fine > $now); @@ -485,31 +480,35 @@ sub generate_fines { && $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( $grace_period )."\n" ); - $log->info( "Circ ".$c->id." is still inside grace period of: $grace_period [". seconds_to_interval( $grace_period ).']' ); + $conn->respond( "Still inside grace period of: ". seconds_to_interval( $grace_period )."\n" ); + $logger->info( "Circ ".$c->id." is still inside grace period of: $grace_period [". seconds_to_interval( $grace_period ).']' ); return; } - $client->respond( "\t$pending_fine_count pending fine(s)\n" ); + $conn->respond( "\t$pending_fine_count pending fine(s)\n" ); return unless ($pending_fine_count); my $recurring_fine = int($c->$recurring_fine_method * 100); my $max_fine = int($c->max_fine * 100); my $skip_closed_check = $U->ou_ancestor_setting_value( - $c->$circ_lib_method->to_fieldmapper->id, 'circ.fines.charge_when_closed'); + $c->$circ_lib_method, 'circ.fines.charge_when_closed'); $skip_closed_check = $U->is_true($skip_closed_check); my $truncate_to_max_fine = $U->ou_ancestor_setting_value( - $c->$circ_lib_method->to_fieldmapper->id, 'circ.fines.truncate_to_max_fine'); + $c->$circ_lib_method, 'circ.fines.truncate_to_max_fine'); $truncate_to_max_fine = $U->is_true($truncate_to_max_fine); my ($latest_billing_ts, $latest_amount) = ('',0); for (my $bill = 1; $bill <= $pending_fine_count; $bill++) { if ($current_fine_total >= $max_fine) { - $c->update({stop_fines => 'MAXFINES', stop_fines_time => 'now'}) if ($ctype eq 'circulation'); - $client->respond( + if ($ctype eq 'circulation') { + $c->stop_fines('MAXFINES'); + $c->stop_fines_time('now'); + $e->update_action_circulation($c); + } + $conn->respond( "\tMaximum fine level of ".$c->max_fine. " reached for this $ctype.\n". "\tNo more fines will be generated.\n" ); @@ -534,11 +533,11 @@ sub generate_fines { next if ( $h->$dow_open eq '00:00:00' and $h->$dow_close eq '00:00:00'); } - my @cl = actor::org_unit::closed_date->search_where( + my @cl = @{$e->search_actor_org_unit_closed_date( { close_start => { '<=' => $timestamptz }, close_end => { '>=' => $timestamptz }, org_unit => $c->$circ_lib_method } - ); + )}; next if (@cl); } @@ -553,61 +552,40 @@ sub generate_fines { $latest_amount += $this_billing_amount; $latest_billing_ts = $timestamptz; - money::billing->create( - { xact => ''.$c->id, - note => "System Generated Overdue Fine", - billing_type => "Overdue materials", - btype => 1, - amount => sprintf('%0.2f', $this_billing_amount/100), - billing_ts => $timestamptz, - } - ); + my $bill = Fieldmapper::money::billing->new; + $bill->xact($c->id); + $bill->note("System Generated Overdue Fine"); + $bill->billing_type("Overdue materials"); + $bill->btype(1); + $bill->amount(sprintf('%0.2f', $this_billing_amount/100)); + $bill->billing_ts($timestamptz); + $e->create_money_billing($bill); } - $client->respond( "\t\tAdding fines totaling $latest_amount for overdue up to $latest_billing_ts\n" ) + $conn->respond( "\t\tAdding fines totaling $latest_amount for overdue up to $latest_billing_ts\n" ) if ($latest_billing_ts and $latest_amount); - $self->method_lookup('open-ils.storage.transaction.commit')->run; +# $self->method_lookup('open-ils.storage.transaction.commit')->run; - if(1) { - - # Caluclate penalties inline - OpenILS::Utils::Penalty->calculate_penalties( - undef, $c->usr->to_fieldmapper->id.'', $c->$circ_lib_method->to_fieldmapper->id.''); - - } else { - - # Calculate penalties with an aysnc call to the penalty server. This approach - # may lead to duplicate penalties since multiple penalty processes for a - # given user may be running at the same time. Leave this here for reference - # in case we later find that asyc calls are needed in some environments. - $penalty->request( - 'open-ils.penalty.patron_penalty.calculate', - { patronid => ''.$c->usr, - context_org => ''.$c->$circ_lib_method, - update => 1, - background => 1, - } - )->gather(1); - } + # Caluclate penalties inline + OpenILS::Utils::Penalty->calculate_penalties( + undef, $c->usr, $c->$circ_lib_method); }; if ($@) { my $e = $@; - $client->respond( "Error processing overdue $ctype [".$c->id."]:\n\n$e\n" ); - $log->error("Error processing overdue $ctype [".$c->id."]:\n$e\n"); - $self->method_lookup('open-ils.storage.transaction.rollback')->run; + $conn->respond( "Error processing overdue $ctype [".$c->id."]:\n\n$e\n" ); + $logger->error("Error processing overdue $ctype [".$c->id."]:\n$e\n"); +# $self->method_lookup('open-ils.storage.transaction.rollback')->run; last if ($e =~ /IS NOT CONNECTED TO THE NETWORK/o); } } + + $e->commit if ($commit); + + return undef; } -__PACKAGE__->register_method( - api_name => 'open-ils.storage.action.circulation.overdue.generate_fines', - api_level => 1, - stream => 1, - method => 'generate_fines', -); 1; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm index b619711e0d..2f9b9c52af 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Storage/Publisher/action.pm @@ -13,7 +13,6 @@ use OpenILS::Utils::CStoreEditor qw/:funcs/; use DateTime; use DateTime::Format::ISO8601; use OpenILS::Utils::Penalty; -use POSIX qw(ceil); use OpenILS::Application::Circ::CircCommon; use OpenILS::Application::AppUtils; my $U = "OpenILS::Application::AppUtils"; @@ -993,329 +992,30 @@ __PACKAGE__->register_method( method => 'find_usr_summary_surveys', ); -sub seconds_to_interval_hash { - my $interval = shift; - my $limit = shift || 's'; - $limit =~ s/^(.)/$1/o; - - my %output; - - my ($y,$ym,$M,$Mm,$w,$wm,$d,$dm,$h,$hm,$m,$mm,$s); - my ($year, $month, $week, $day, $hour, $minute, $second) = - ('years','months','weeks','days', 'hours', 'minutes', 'seconds'); - - if ($y = int($interval / (60 * 60 * 24 * 365))) { - $output{$year} = $y; - $ym = $interval % (60 * 60 * 24 * 365); - } else { - $ym = $interval; - } - return %output if ($limit eq 'y'); - - if ($M = int($ym / ((60 * 60 * 24 * 365)/12))) { - $output{$month} = $M; - $Mm = $ym % ((60 * 60 * 24 * 365)/12); - } else { - $Mm = $ym; - } - return %output if ($limit eq 'M'); - - if ($w = int($Mm / 604800)) { - $output{$week} = $w; - $wm = $Mm % 604800; - } else { - $wm = $Mm; - } - return %output if ($limit eq 'w'); - - if ($d = int($wm / 86400)) { - $output{$day} = $d; - $dm = $wm % 86400; - } else { - $dm = $wm; - } - return %output if ($limit eq 'd'); - - if ($h = int($dm / 3600)) { - $output{$hour} = $h; - $hm = $dm % 3600; - } else { - $hm = $dm; - } - return %output if ($limit eq 'h'); - - if ($m = int($hm / 60)) { - $output{$minute} = $m; - $mm = $hm % 60; - } else { - $mm = $hm; - } - return %output if ($limit eq 'm'); - - if ($s = int($mm)) { - $output{$second} = $s; - } else { - $output{$second} = 0 unless (keys %output); - } - return %output; -} - - sub generate_fines { my $self = shift; my $client = shift; - my $circ = shift; - my $overbill = shift; + my $circ_id = shift; - local $OpenILS::Application::Storage::WRITE = 1; - - my @circs; - if ($circ) { - push @circs, - action::circulation->search_where( { id => $circ, stop_fines => undef } ), - booking::reservation->search_where( { id => $circ, return_time => undef, cancel_time => undef } ); + my $circs; + my $editor = new_editor; + if ($circ_id) { +# my $circ; +# if ($circ = action::circulation->search_where( { id => $circ_id, stop_fines => undef } )) { +# $circ = action::circulation->retrieve($circ_id)->to_fieldmapper; +# } elsif ($circ = booking::reservation->search_where( { id => $circ_id, return_time => undef, cancel_time => undef } )) { +# $circ = booking::reservation->retrieve($circ_id)->to_fieldmapper; +# } +# $circs = [$circ] if ($circ); + $circs = $editor->search_action_circulation( { id => $circ_id, stop_fines => undef } ); + unless (@$circs) { + $circs = $editor->search_booking_reservation->search_where( { id => $circ_id, return_time => undef, cancel_time => undef } ); + } } else { - push @circs, overdue_circs(undef, 1, 1, 1); + $circs = [map { $_->to_fieldmapper } overdue_circs(undef, 1, 1, 1)]; } - $logger->info("fine generator processing ".scalar(@circs)." transactions"); - - my %hoo = map { ( $_->id => $_ ) } actor::org_unit::hours_of_operation->retrieve_all; - - my $penalty = OpenSRF::AppSession->create('open-ils.penalty'); - my $handling_resvs = 0; - for my $c (@circs) { - - my $ctype = ref($c); - - if (!$ctype) { # fetched via idlist - if ($handling_resvs) { - $c = booking::reservation->retrieve($c); - } elsif (not defined $c) { - # an undef value is the indicator that we are moving - # from processing circulations to reservations. - $handling_resvs = 1; - next; - } else { - $c = action::circulation->retrieve($c); - } - $ctype = ref($c); - } - - $ctype =~ s/^.+::(\w+)$/$1/; - - my $due_date_method = 'due_date'; - my $target_copy_method = 'target_copy'; - my $circ_lib_method = 'circ_lib'; - my $recurring_fine_method = 'recurring_fine'; - my $is_reservation = 0; - if ($ctype eq 'reservation') { - $is_reservation = 1; - $due_date_method = 'end_time'; - $target_copy_method = 'current_resource'; - $circ_lib_method = 'pickup_lib'; - $recurring_fine_method = 'fine_amount'; - next unless ($c->fine_interval); - } - #TODO: reservation grace periods - my $grace_period = ($is_reservation ? 0 : interval_to_seconds($c->grace_period)); - - eval { - if ($self->method_lookup('open-ils.storage.transaction.current')->run) { - $log->debug("Cleaning up after previous transaction\n"); - $self->method_lookup('open-ils.storage.transaction.rollback')->run; - } - $self->method_lookup('open-ils.storage.transaction.begin')->run( $client ); - $log->info( - sprintf("Processing %s %d...", - ($is_reservation ? "reservation" : "circ"), $c->id - ) - ); - - - my $due_dt = $parser->parse_datetime( cleanse_ISO8601( $c->$due_date_method ) ); - - my $due = $due_dt->epoch; - my $now = time; - - my $fine_interval = $c->fine_interval; - $fine_interval =~ s/(\d{2}):(\d{2}):(\d{2})/$1 h $2 m $3 s/o; - $fine_interval = interval_to_seconds( $fine_interval ); - - if ( $fine_interval == 0 || int($c->$recurring_fine_method * 100) == 0 || int($c->max_fine * 100) == 0 ) { - $client->respond( "Fine Generator skipping circ due to 0 fine interval, 0 fine rate, or 0 max fine.\n" ); - $log->info( "Fine Generator skipping circ " . $c->id . " due to 0 fine interval, 0 fine rate, or 0 max fine." ); - return; - } - - if ( $is_reservation and $fine_interval >= interval_to_seconds('1d') ) { - my $tz_offset_s = 0; - if ($due_dt->strftime('%z') =~ /(-|\+)(\d{2}):?(\d{2})/) { - $tz_offset_s = $1 . interval_to_seconds( "${2}h ${3}m"); - } - - $due -= ($due % $fine_interval) + $tz_offset_s; - $now -= ($now % $fine_interval) + $tz_offset_s; - } - - $client->respond( - "ARG! Overdue $ctype ".$c->id. - " for item ".$c->$target_copy_method. - " (user ".$c->usr.").\n". - "\tItem was due on or before: ".localtime($due)."\n"); - - my @fines = money::billing->search_where( - { xact => $c->id, - btype => 1, - billing_ts => { '>' => $c->$due_date_method } }, - { order_by => 'billing_ts DESC'} - ); - - my $f_idx = 0; - my $fine = $fines[$f_idx] if (@fines); - if ($overbill) { - $fine = $fines[++$f_idx] while ($fine and $fine->voided); - } - - my $current_fine_total = 0; - $current_fine_total += int($_->amount * 100) for (grep { $_ and !$_->voided } @fines); - - my $last_fine; - if ($fine) { - $client->respond( "Last billing time: ".$fine->billing_ts." (clensed format: ".cleanse_ISO8601( $fine->billing_ts ).")"); - $last_fine = $parser->parse_datetime( cleanse_ISO8601( $fine->billing_ts ) )->epoch; - } else { - $log->info( "Potential first billing for circ ".$c->id ); - $last_fine = $due; - - $grace_period = OpenILS::Application::Circ::CircCommon->extend_grace_period($c->$circ_lib_method->to_fieldmapper->id,$c->$due_date_method,$grace_period,undef,$hoo{$c->$circ_lib_method}); - } - - return if ($last_fine > $now); - # Generate fines for each past interval, including the one we are inside - my $pending_fine_count = ceil( ($now - $last_fine) / $fine_interval ); - - if ( $last_fine == $due # we have no fines yet - && $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( $grace_period )."\n" ); - $log->info( "Circ ".$c->id." is still inside grace period of: $grace_period [". seconds_to_interval( $grace_period ).']' ); - return; - } - - $client->respond( "\t$pending_fine_count pending fine(s)\n" ); - return unless ($pending_fine_count); - - my $recurring_fine = int($c->$recurring_fine_method * 100); - my $max_fine = int($c->max_fine * 100); - - my $skip_closed_check = $U->ou_ancestor_setting_value( - $c->$circ_lib_method->to_fieldmapper->id, 'circ.fines.charge_when_closed'); - $skip_closed_check = $U->is_true($skip_closed_check); - - my $truncate_to_max_fine = $U->ou_ancestor_setting_value( - $c->$circ_lib_method->to_fieldmapper->id, 'circ.fines.truncate_to_max_fine'); - $truncate_to_max_fine = $U->is_true($truncate_to_max_fine); - - my ($latest_billing_ts, $latest_amount) = ('',0); - for (my $bill = 1; $bill <= $pending_fine_count; $bill++) { - - if ($current_fine_total >= $max_fine) { - $c->update({stop_fines => 'MAXFINES', stop_fines_time => 'now'}) if ($ctype eq 'circulation'); - $client->respond( - "\tMaximum fine level of ".$c->max_fine. - " reached for this $ctype.\n". - "\tNo more fines will be generated.\n" ); - last; - } - - # XXX Use org time zone (or default to 'local') once we have the ou setting built for that - my $billing_ts = DateTime->from_epoch( epoch => $last_fine, time_zone => 'local' ); - my $current_bill_count = $bill; - while ( $current_bill_count ) { - $billing_ts->add( seconds_to_interval_hash( $fine_interval ) ); - $current_bill_count--; - } - - my $timestamptz = $billing_ts->strftime('%FT%T%z'); - if (!$skip_closed_check) { - my $dow = $billing_ts->day_of_week_0(); - my $dow_open = "dow_${dow}_open"; - my $dow_close = "dow_${dow}_close"; - - if (my $h = $hoo{$c->$circ_lib_method}) { - next if ( $h->$dow_open eq '00:00:00' and $h->$dow_close eq '00:00:00'); - } - - my @cl = actor::org_unit::closed_date->search_where( - { close_start => { '<=' => $timestamptz }, - close_end => { '>=' => $timestamptz }, - org_unit => $c->$circ_lib_method } - ); - next if (@cl); - } - - # The billing amount for this billing normally ought to be the recurring fine amount. - # However, if the recurring fine amount would cause total fines to exceed the max fine amount, - # we may wish to reduce the amount for this billing (if circ.fines.truncate_to_max_fine is true). - my $this_billing_amount = $recurring_fine; - if ( $truncate_to_max_fine && ($current_fine_total + $this_billing_amount) > $max_fine ) { - $this_billing_amount = ($max_fine - $current_fine_total); - } - $current_fine_total += $this_billing_amount; - $latest_amount += $this_billing_amount; - $latest_billing_ts = $timestamptz; - - money::billing->create( - { xact => ''.$c->id, - note => "System Generated Overdue Fine", - billing_type => "Overdue materials", - btype => 1, - amount => sprintf('%0.2f', $this_billing_amount/100), - billing_ts => $timestamptz, - } - ); - - } - - $client->respond( "\t\tAdding fines totaling $latest_amount for overdue up to $latest_billing_ts\n" ) - if ($latest_billing_ts and $latest_amount); - - $self->method_lookup('open-ils.storage.transaction.commit')->run; - - if(1) { - - # Caluclate penalties inline - OpenILS::Utils::Penalty->calculate_penalties( - undef, $c->usr->to_fieldmapper->id.'', $c->$circ_lib_method->to_fieldmapper->id.''); - - } else { - - # Calculate penalties with an aysnc call to the penalty server. This approach - # may lead to duplicate penalties since multiple penalty processes for a - # given user may be running at the same time. Leave this here for reference - # in case we later find that asyc calls are needed in some environments. - $penalty->request( - 'open-ils.penalty.patron_penalty.calculate', - { patronid => ''.$c->usr, - context_org => ''.$c->$circ_lib_method, - update => 1, - background => 1, - } - )->gather(1); - } - - }; - - if ($@) { - my $e = $@; - $client->respond( "Error processing overdue $ctype [".$c->id."]:\n\n$e\n" ); - $log->error("Error processing overdue $ctype [".$c->id."]:\n$e\n"); - $self->method_lookup('open-ils.storage.transaction.rollback')->run; - last if ($e =~ /IS NOT CONNECTED TO THE NETWORK/o); - } - } + return OpenILS::Application::Circ::CircCommon->generate_fines($client, {circs => $circs}) } __PACKAGE__->register_method( api_name => 'open-ils.storage.action.circulation.overdue.generate_fines',