From d29d41b061d7d8232e63d6173ad86f0d573924c8 Mon Sep 17 00:00:00 2001 From: Jeff Godin Date: Tue, 6 Dec 2011 15:20:44 -0500 Subject: [PATCH] "forgive" overdues when marking an item lost New option for forgiving (as opposed to voiding) overdues on a circ when marking the item lost: When circ.forgive_overdue_on_lost is set, attempt to make a payment of type "Forgive" on the transaction for the amount of outstanding overdue billings. Only outstanding bills of type 1 (Overdue materials) will be paid, and only the first contiguous grouping. If the system finds an outstanding billing of type other than 1, it will pay what it has found up to that point. circ.forgive_overdue_on_lost has priority over the "void" version of the same setting, if both happen to be set. Signed-off-by: Jeff Godin --- .../lib/OpenILS/Application/Cat/AssetCommon.pm | 10 ++- .../lib/OpenILS/Application/Circ/CircCommon.pm | 93 ++++++++++++++++++++++ 2 files changed, 101 insertions(+), 2 deletions(-) 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 673e470cf6..f69029b538 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm @@ -536,6 +536,8 @@ sub set_item_lost { # fetch the related org settings my $proc_fee = $U->ou_ancestor_setting_value( $owning_lib, OILS_SETTING_LOST_PROCESSING_FEE, $e) || 0; + my $forgive_overdue = $U->ou_ancestor_setting_value( + $owning_lib, OILS_SETTING_FORGIVE_OVERDUE_ON_LOST, $e) || 0; my $void_overdue = $U->ou_ancestor_setting_value( $owning_lib, OILS_SETTING_VOID_OVERDUE_ON_LOST, $e) || 0; @@ -569,8 +571,12 @@ sub set_item_lost { $e->update_action_circulation($circ) or return $e->die_event; # --------------------------------------------------------------------- - # void all overdue fines on this circ if configured - if( $void_overdue ) { + # forgive outstanding overdue fines or void all overdue fines on this circ if configured + if( $forgive_overdue ) { + my $evt = OpenILS::Application::Circ::CircCommon->forgive_overdues($e, $circ, "System: OVERDUES FORGIVEN ON LOST"); + return $evt if $evt; + + } elsif( $void_overdue ) { my $evt = OpenILS::Application::Circ::CircCommon->void_overdues($e, $circ); return $evt if $evt; } 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 1319201554..64a23059d0 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CircCommon.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CircCommon.pm @@ -17,6 +17,99 @@ my $U = "OpenILS::Application::AppUtils"; # ----------------------------------------------------------------- +# Forgive (don't void) unpaid overdue fines on the given circ. +# This is different from void_overdues in a few ways: +# * only deals with 'unpaid' overdue billings +# * does not accept a backdate argument +# * only forgives if the first unpaid billing is of type 1, +# and stops when it gets to a billing type other than 1 +# ----------------------------------------------------------------- +sub forgive_overdues { + my ($class, $e, $circ, $note) = @_; + + + $logger->info("attempting to forgive overdues on circ " . $circ->id . " with note " . $note); + + # find all unvoided bills in order + my $bill_search = [ + { xact => $circ->id, voided=>'f' }, + { order_by => { mb => { billing_ts => { direction => 'asc' } } } }, + ]; + + # find all unvoided payments in order + my $payment_search = [ + { xact => $circ->id, voided=>'f' }, + { order_by => { mp => { payment_ts => { direction => 'asc' } } } }, + ]; + + my $bills = $e->search_money_billing($bill_search); + + my $payments = $e->search_money_payment($payment_search); + + # "Pay" the bills, removing fully paid bills and + # adjusting the amount for partially paid bills + map { + my $payment = $_; + my $paybal = $payment->amount; + + while ($paybal > 0) { + # get next billing + my $bill = shift @{$bills}; + my $newbal = (($paybal*100) - ($bill->amount*100))/100; + if ($newbal < 0) { + $newbal = 0; + my $new_bill_amount = (($bill->amount*100) - ($paybal*100))/100; + $bill->amount($new_bill_amount); + unshift(@{$bills}, $bill); # put the partially-paid bill back on top of the stack + } + + $paybal = $newbal; + + } + + } @$payments; + + # Sum any outstanding overdue billings, stopping at the first non-overdue billing + + my $outstanding_overdues = 0; + + foreach (@$bills) { + my $bill = $_; + if ($bill->btype == 1) { + $logger->debug("forgive_overdues found a btype 1 bill id " . $bill->id . " amount " . $bill->amount); + $outstanding_overdues = ($outstanding_overdues*100 + $bill->amount*100)/100; + } else { + # We found a billing type other than 1 -- Overdue Fines + $logger->info("forgive_overdues found a bill id " . $bill->id . " with btype " . $bill->btype); + last; # stop looking for bills to forgive + } + + } + + $logger->debug("forgive_overdues outstanding balance to forgive is: " . $outstanding_overdues); + my $amount = $outstanding_overdues; + + if ($amount >= 0.01) { + # pay with forgive payment + my $payobj = Fieldmapper::money::forgive_payment->new; + $payobj->amount($amount); + $payobj->amount_collected($amount); + $payobj->xact($circ->id); + $payobj->note($note); + # do we need an accepting user? who should be the accepting user? + $payobj->accepting_usr($e->requestor->id); # or 1? + + $logger->info("forgive_overdues about to create the forgive payment... "); + $e->create_money_forgive_payment($payobj) or return $e->die_event; + + return undef; + } else { + $logger->info("forgive_overdues found no outstanding overdues, or found outstanding billings of another type first. No forgive payment made."); + return undef; + } +} + +# ----------------------------------------------------------------- # Voids overdue fines on the given circ. if a backdate is # provided, then we only void back to the backdate # ----------------------------------------------------------------- -- 2.11.0