From ea0284c0a9275e0de65487398f4944b8043d63c3 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Fri, 8 Nov 2013 11:43:38 -0500 Subject: [PATCH] LP#1249398 clear negative balance API PI call for zero-ing a negative balance transaction. The API works on transaction which are negative because of the existence of void payments. The void payments are deleted or modified as appropriate to produce a zero-balance transaction. Billings and real patron payments are not affected. open-ils.circ.money.zeroize_transaction (auth, [xact_ids]) Signed-off-by: Bill Erickson --- .../perlmods/lib/OpenILS/Application/Circ/Money.pm | 121 +++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm index 99a714dc33..3921611964 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm @@ -951,5 +951,126 @@ sub retrieve_credit_payable_balance { return $sum; } +__PACKAGE__->register_method( + method => 'zeroize_transaction', + api_name => 'open-ils.circ.money.zeroize_transaction', + signature => { + desc => q/ + Given a list of negative-balance transactions, deletes or + modifies (as appropriate) void payment(s) on the transaction + to produce a zero-balance transaction, without affecting any + of the billings or real patron payments. + + Transactions which do not have a negative balance will be + ignored. + /, + params => [ + {desc => 'Authtoken', type => 'string'}, + {desc => 'Array of transaction IDs', type => 'array'} + ], + return => { + desc => q/Array of IDs for each transaction updated, + Event on error./ + } + } +); + +sub zeroize_transaction { + my ($self, $client, $auth, $xact_ids) = @_; + + my $e = new_editor(xact => 1, authtoken => $auth); + return $e->die_event unless $e->checkauth; + + # in case a bare ID is passed + $xact_ids = [$xact_ids] unless ref $xact_ids; + + # going newest to oldest, delete void payments which cause the + # transaction to remain negative. Once we locate the void payment + # which causes the transaction to reach or exceed a $0 balance, + # delete or modify as needed, then we're done. + sub zeroize_one { + my ($e, $xact) = @_; + + my $void_payments = $e->search_money_void_payment([ + {xact => $xact->id}, + {order_by => {mvp => 'payment_ts desc'}} + ]); + + for my $payment (@$void_payments) { + + # cast balance_owed to postive so we can use fpdiff(); + my $remainder = $U->fpdiff(-$xact->balance_owed, $payment->amount); + + if ($remainder >= 0) { + # void payment is not large enough to take us beyond $0, + # delete the whole payment. + + $logger->info("deleting void payment ".$payment->id. + " in zeroize_transaction"); + + $e->delete_money_void_payment($payment) or return $e->die_event; + + return if $remainder == 0; # all done + + # fetch the updated transaction from the DB to get the most + # accurate value for balance_owed. + $xact = $e->retrieve_money_billable_transaction_summary($xact->id); + + } else { + + # update the void payment to use the difference between + # the amount voided and the amount owed. + $remainder = -$remainder; + $payment->amount($remainder); + $payment->amount_collected($remainder); + + $logger->info("modifying void payment ". + $payment->id."; setting amount to $remainder in zeroize"); + + $e->update_money_void_payment($payment) or return $e->die_event; + + # we've reached $0, all done. + return; + } + } + } + + my @modified; + for my $xact_id (@$xact_ids) { + + my $xact = + $e->retrieve_money_billable_transaction_summary([ + $xact_id, + {flesh => 1, flesh_fields => {mbts => ['usr']}} + ]) or return $e->die_event; + + # we are only concerned with negative-balance transactions + next if $xact->balance_owed >= 0; + + return $e->die_event unless + $e->allowed('CREATE_PAYMENT', $xact->usr->home_ou); + + my $evt = zeroize_one($e, $xact); + return $evt if $evt; + push(@modified, $xact->id); + + # now we see if we can close the transaction + # same logic as make_payments(); + my $circ = $e->retrieve_action_circulation($xact_id); + next if $circ and !$CC->can_close_circ($e, $circ); + + # we don't check to see if the xact is already closed. since the + # xact had a negative balance, it should not have been closed, so + # assume 'now' is the correct close time regardless. + + my $trans = $e->retrieve_money_billable_transaction($xact_id); + $trans->xact_finish("now"); + $e->update_money_billable_transaction($trans) or return $e->die_event; + } + + $e->commit; + return \@modified; +} + 1; -- 2.11.0