From: Jason Stephenson Date: Fri, 18 Jan 2013 21:30:44 +0000 (-0500) Subject: Remove Jeff's org_unit settings for using forgive payments instead of voids. X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=231592cb930973dbe02ac524bd3e0423c5820524;p=working%2FEvergreen.git Remove Jeff's org_unit settings for using forgive payments instead of voids. Remove string constants for Jeff's new org_unit settings. IDL changes to add void_payment. Add the money.void_payment table in the database. Remove voided, voider, and void_time columns from money.billing tables. Remove voided, void_time, and voider field from money::billing in IDL. Update money.materialized_billable_xact_summary in upgrade script. Modifications to void_overdues to make void payments. Reuse and update Jeff's outstanding outstanding_bills_for_circ() method. Rename outstanding_bills_for_circ() to outstanding_bills_for_xact(), because it really is that generic. Modify void_billing in O::A::Circ::Money to use the new void payment. Signed-off-by: Jason Stephenson --- diff --git a/Open-ILS/examples/fm_IDL.xml b/Open-ILS/examples/fm_IDL.xml index a7a765dbfb..b75b199875 100644 --- a/Open-ILS/examples/fm_IDL.xml +++ b/Open-ILS/examples/fm_IDL.xml @@ -31,6 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + @@ -3229,6 +3230,24 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + + + + + + + + + + + + + + + + + + @@ -6265,6 +6284,7 @@ SELECT usr, + @@ -6274,6 +6294,7 @@ SELECT usr, + @@ -6293,6 +6314,7 @@ SELECT usr, + @@ -6302,6 +6324,7 @@ SELECT usr, + @@ -6318,12 +6341,14 @@ SELECT usr, + + @@ -6498,15 +6523,11 @@ SELECT usr, - - - - 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 1ae777c1e4..c87eb281a9 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Cat/AssetCommon.pm @@ -666,8 +666,6 @@ 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; @@ -701,13 +699,8 @@ sub set_item_lost { $e->update_action_circulation($circ) or return $e->die_event; # --------------------------------------------------------------------- - # 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 ) { - + # void all overdue fines on this circ if configured + if( $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 f7e5b0b88c..e29cc24440 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CircCommon.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/CircCommon.pm @@ -16,62 +16,6 @@ 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); - - # get outstanding bills for the circ in question - my $bills = outstanding_bills_for_circ($e, $circ); - - # 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 @@ -82,9 +26,9 @@ sub forgive_overdues { sub void_overdues { my($class, $e, $circ, $backdate, $note) = @_; - my $bill_search = { - xact => $circ->id, - btype => 1 + my $bill_search = { + xact => $circ->id, + btype => 1 }; if( $backdate ) { @@ -113,20 +57,33 @@ sub void_overdues { } } - my $bills = $e->search_money_billing($bill_search); - - for my $bill (@$bills) { - next if $U->is_true($bill->voided); - $logger->info("voiding overdue bill ".$bill->id); - $bill->voided('t'); - $bill->void_time('now'); - $bill->voider($e->requestor->id); - my $n = ($bill->note) ? sprintf("%s\n", $bill->note) : ""; - $bill->note(sprintf("$n%s", ($note) ? $note : "System: VOIDED FOR BACKDATE")); - $e->update_money_billing($bill) or return $e->die_event; + my $bills = $class->oustanding_bills_for_xact($e, $circ, $bill_search); + + # Sum any outstanding overdue billings + my $outstanding_overdues = 0; + + foreach my $bill (@$bills) { + $outstanding_overdues = ($outstanding_overdues*100 + $bill->amount*100)/100; } - return undef; + # TODO: I am sure that at some point someone is going to want to + # keep the old behavior of voiding the whole bill amount and if + # that give the patron a "credit" then so be it. I'll need an ou + # setting for that. + + if ($outstanding_overdues >= 0.01) { + # Make void payment + my $payobj = Fieldmapper::money::void_payment->new; + $payobj->amount($outstanding_overdues); + $payobj->amount_collected($outstanding_overdues); + $payobj->xact($circ->id); + $payobj->note($note); + $payobj->accepting_usr($e->requestor->id); + + $e->create_money_void_payment($payobj) or return $e->die_event; + } + + return undef; } @@ -297,23 +254,33 @@ sub can_close_circ { } # ----------------------------------------------------------------- -# Given an editor and a circ, return a reference to an array of +# Given an editor and a xact, return a reference to an array of # billing objects which are outstanding (unpaid, not voided). # If a bill is partially paid, change the amount of the bill # to reflect the unpaid amount, not the original amount. +# +# It also takes an optional last parameter as a bill search predicate +# filter. # ----------------------------------------------------------------- -sub outstanding_bills_for_circ { - my ($class, $e, $circ) = @_; +sub outstanding_bills_for_xact { + my ($class, $e, $xact, $bill_predicate) = @_; + + # A little defensive coding never hurts. + unless ($bill_predicate) { + $bill_predicate = {xact => $xact->id}; + } else { + $bill_predicate->{xact} = $xact->id unless ($bill_predicate->{xact}); + } # find all unvoided bills in order my $bill_search = [ - { xact => $circ->id, voided=>'f' }, + $bill_predicate, { order_by => { mb => { billing_ts => { direction => 'asc' } } } }, ]; # find all unvoided payments in order my $payment_search = [ - { xact => $circ->id, voided=>'f' }, + { xact => $xact->id, voided=>'f' }, { order_by => { mp => { payment_ts => { direction => 'asc' } } } }, ]; @@ -324,23 +291,21 @@ sub outstanding_bills_for_circ { # "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; - + 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; 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 eb1ac40587..f8358f813a 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Circ/Money.pm @@ -741,20 +741,38 @@ sub void_bill { my $xact = $e->retrieve_money_billable_transaction($bill->xact) or return $e->die_event; - if($U->is_true($bill->voided)) { + my $amount_to_void = $bill->amount; + my $open_amount = 0; + my $open_bills = OpenILS::Application::Circ::CircCommon->outstanding_bills_for_xact($e, $xact); + for my $open_bill (@$open_bills) { + $open_amount = ($open_amount*100 + $open_bill->amount*100)/100; + } + + # TODO: I am sure that at some point someone is going to want + # to keep the old behavior of voiding the whole bill amount + # and if that give the patron a "credit" then so be it. I'll + # need an ou setting for that. + + if($open_amount == 0) { $e->rollback; return OpenILS::Event->new('BILL_ALREADY_VOIDED', payload => $bill); + } else { + # Void the lesser of $amount_to_void or $open_amount: + $amount_to_void = ($amount_to_void < $open_amount) ? $amount_to_void : $open_amount; + # Make a void payment in the amount of $amount_to_void + my $payobj = Fieldmapper::money::void_payment->new; + $payobj->amount($amount_to_void); + $payobj->amount_collected($amount_to_void); + $payobj->xact($bill->xact); + $payobj->accepting_usr($e->requestor->id); + + $e->create_money_void_payment($payobj) or return $e->die_event; } my $org = $U->xact_org($bill->xact, $e); $users{$xact->usr} = {} unless $users{$xact->usr}; $users{$xact->usr}->{$org} = 1; - $bill->voided('t'); - $bill->voider($e->requestor->id); - $bill->void_time('now'); - - $e->update_money_billing($bill) or return $e->die_event; my $evt = _check_open_xact($e, $bill->xact, $xact); return $evt if $evt; } diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Const.pm b/Open-ILS/src/perlmods/lib/OpenILS/Const.pm index 25479e2b3d..f86a801dc3 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Const.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Const.pm @@ -78,7 +78,6 @@ econst OILS_SETTING_LOST_PROCESSING_FEE => 'circ.lost_materials_processing_fee'; econst OILS_SETTING_DEF_ITEM_PRICE => 'cat.default_item_price'; econst OILS_SETTING_ORG_BOUNCED_EMAIL => 'org.bounced_emails'; econst OILS_SETTING_CHARGE_LOST_ON_ZERO => 'circ.charge_lost_on_zero'; -econst OILS_SETTING_FORGIVE_OVERDUE_ON_LOST => 'circ.forgive_overdue_on_lost'; econst OILS_SETTING_VOID_OVERDUE_ON_LOST => 'circ.void_overdue_on_lost'; econst OILS_SETTING_HOLD_SOFT_STALL => 'circ.hold_stalling.soft'; econst OILS_SETTING_HOLD_HARD_STALL => 'circ.hold_stalling.hard'; @@ -86,10 +85,8 @@ econst OILS_SETTING_HOLD_SOFT_BOUNDARY => 'circ.hold_boundary.soft'; econst OILS_SETTING_HOLD_HARD_BOUNDARY => 'circ.hold_boundary.hard'; econst OILS_SETTING_HOLD_EXPIRE => 'circ.hold_expire_interval'; econst OILS_SETTING_HOLD_ESIMATE_WAIT_INTERVAL => 'circ.holds.default_estimated_wait_interval'; -econst OILS_SETTING_FORGIVE_LOST_ON_CHECKIN => 'circ.forgive_lost_on_checkin'; econst OILS_SETTING_VOID_LOST_ON_CHECKIN => 'circ.void_lost_on_checkin'; econst OILS_SETTING_MAX_ACCEPT_RETURN_OF_LOST => 'circ.max_accept_return_of_lost'; -econst OILS_SETTING_FORGIVE_LOST_PROCESS_FEE_ON_CHECKIN => 'circ.forgive_lost_proc_fee_on_checkin'; econst OILS_SETTING_VOID_LOST_PROCESS_FEE_ON_CHECKIN => 'circ.void_lost_proc_fee_on_checkin'; econst OILS_SETTING_RESTORE_OVERDUE_ON_LOST_RETURN => 'circ.restore_overdue_on_lost_return'; econst OILS_SETTING_LOST_IMMEDIATELY_AVAILABLE => 'circ.lost_immediately_available'; diff --git a/Open-ILS/src/sql/Pg/080.schema.money.sql b/Open-ILS/src/sql/Pg/080.schema.money.sql index 5004f00490..d7b258460f 100644 --- a/Open-ILS/src/sql/Pg/080.schema.money.sql +++ b/Open-ILS/src/sql/Pg/080.schema.money.sql @@ -52,9 +52,6 @@ CREATE TABLE money.billing ( id BIGSERIAL PRIMARY KEY, xact BIGINT NOT NULL, -- money.billable_xact.id billing_ts TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), - voided BOOL NOT NULL DEFAULT FALSE, - voider INT, - void_time TIMESTAMP WITH TIME ZONE, amount NUMERIC(6,2) NOT NULL, billing_type TEXT NOT NULL, btype INT NOT NULL REFERENCES config.billing_type (id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED, @@ -89,7 +86,6 @@ CREATE OR REPLACE VIEW money.transaction_billing_type_summary AS MAX(billing_ts) AS last_billing_ts, SUM(COALESCE(amount,0)) AS total_owed FROM money.billing - WHERE voided IS FALSE GROUP BY xact,billing_type ORDER BY MAX(billing_ts); @@ -100,7 +96,6 @@ CREATE OR REPLACE VIEW money.transaction_billing_summary AS MAX(billing_ts) AS last_billing_ts, SUM(COALESCE(amount,0)) AS total_owed FROM money.billing - WHERE voided IS FALSE GROUP BY xact ORDER BY MAX(billing_ts); @@ -115,26 +110,6 @@ CREATE OR REPLACE VIEW money.transaction_payment_summary AS GROUP BY xact ORDER BY MAX(payment_ts); -CREATE OR REPLACE VIEW money.transaction_billing_with_void_summary AS - SELECT xact, - LAST(billing_type) AS last_billing_type, - LAST(note) AS last_billing_note, - MAX(billing_ts) AS last_billing_ts, - SUM(CASE WHEN voided THEN 0 ELSE COALESCE(amount,0) END) AS total_owed - FROM money.billing - GROUP BY xact - ORDER BY MAX(billing_ts); - -CREATE OR REPLACE VIEW money.transaction_payment_with_void_summary AS - SELECT xact, - LAST(payment_type) AS last_payment_type, - LAST(note) AS last_payment_note, - MAX(payment_ts) as last_payment_ts, - SUM(CASE WHEN voided THEN 0 ELSE COALESCE(amount,0) END) AS total_paid - FROM money.payment_view - GROUP BY xact - ORDER BY MAX(payment_ts); - CREATE OR REPLACE VIEW money.open_transaction_billing_type_summary AS SELECT xact, billing_type AS last_billing_type, @@ -142,7 +117,6 @@ CREATE OR REPLACE VIEW money.open_transaction_billing_type_summary AS MAX(billing_ts) AS last_billing_ts, SUM(COALESCE(amount,0)) AS total_owed FROM money.billing - WHERE voided IS FALSE GROUP BY xact,billing_type ORDER BY MAX(billing_ts); @@ -153,7 +127,6 @@ CREATE OR REPLACE VIEW money.open_transaction_billing_summary AS MAX(billing_ts) AS last_billing_ts, SUM(COALESCE(amount,0)) AS total_owed FROM money.billing - WHERE voided IS FALSE GROUP BY xact ORDER BY MAX(billing_ts); @@ -168,49 +141,6 @@ CREATE OR REPLACE VIEW money.open_transaction_payment_summary AS GROUP BY xact ORDER BY MAX(payment_ts); -/* Replacing with the one below. -CREATE OR REPLACE VIEW money.billable_xact_with_void_summary AS - SELECT xact.id AS id, - xact.usr AS usr, - xact.xact_start AS xact_start, - xact.xact_finish AS xact_finish, - credit.total_paid, - credit.last_payment_ts, - credit.last_payment_note, - credit.last_payment_type, - debit.total_owed, - debit.last_billing_ts, - debit.last_billing_note, - debit.last_billing_type, - COALESCE(debit.total_owed,0) - COALESCE(credit.total_paid,0) AS balance_owed, - p.relname AS xact_type - FROM money.billable_xact xact - JOIN pg_class p ON (xact.tableoid = p.oid) - LEFT JOIN money.transaction_billing_with_void_summary debit ON (xact.id = debit.xact) - LEFT JOIN money.transaction_payment_with_void_summary credit ON (xact.id = credit.xact); -*/ - -CREATE OR REPLACE VIEW money.billable_xact_with_void_summary AS - SELECT xact.id AS id, - xact.usr AS usr, - xact.xact_start AS xact_start, - xact.xact_finish AS xact_finish, - SUM(credit.amount) AS total_paid, - MAX(credit.payment_ts) AS last_payment_ts, - LAST(credit.note) AS last_payment_note, - LAST(credit.payment_type) AS last_payment_type, - SUM(debit.amount) AS total_owed, - MAX(debit.billing_ts) AS last_billing_ts, - LAST(debit.note) AS last_billing_note, - LAST(debit.billing_type) AS last_billing_type, - COALESCE(SUM(debit.amount),0) - COALESCE(SUM(credit.amount),0) AS balance_owed, - p.relname AS xact_type - FROM money.billable_xact xact - JOIN pg_class p ON (xact.tableoid = p.oid) - LEFT JOIN money.billing debit ON (xact.id = debit.xact) - LEFT JOIN money.payment_view credit ON (xact.id = credit.xact) - GROUP BY 1,2,3,4,14 - ORDER BY MAX(debit.billing_ts), MAX(credit.payment_ts); CREATE OR REPLACE VIEW money.billable_xact_summary AS SELECT xact.id, @@ -236,7 +166,6 @@ CREATE OR REPLACE VIEW money.billable_xact_summary AS last(billing.note) AS note, last(billing.billing_type) AS billing_type FROM money.billing - WHERE billing.voided IS FALSE GROUP BY billing.xact ) debit ON xact.id = debit.xact LEFT JOIN ( @@ -297,20 +226,16 @@ CREATE TRIGGER mat_summary_create_tgr AFTER INSERT ON money.grocery FOR EACH ROW CREATE TRIGGER mat_summary_change_tgr AFTER UPDATE ON money.grocery FOR EACH ROW EXECUTE PROCEDURE money.mat_summary_update (); CREATE TRIGGER mat_summary_remove_tgr AFTER DELETE ON money.grocery FOR EACH ROW EXECUTE PROCEDURE money.mat_summary_delete (); - - /* BEFORE or AFTER trigger */ CREATE OR REPLACE FUNCTION money.materialized_summary_billing_add () RETURNS TRIGGER AS $$ BEGIN - IF NOT NEW.voided THEN - UPDATE money.materialized_billable_xact_summary - SET total_owed = COALESCE(total_owed, 0.0::numeric) + NEW.amount, - last_billing_ts = NEW.billing_ts, - last_billing_note = NEW.note, - last_billing_type = NEW.billing_type, - balance_owed = balance_owed + NEW.amount - WHERE id = NEW.xact; - END IF; + UPDATE money.materialized_billable_xact_summary + SET total_owed = COALESCE(total_owed, 0.0::numeric) + NEW.amount, + last_billing_ts = NEW.billing_ts, + last_billing_note = NEW.note, + last_billing_type = NEW.billing_type, + balance_owed = balance_owed + NEW.amount + WHERE id = NEW.xact; RETURN NEW; END; @@ -323,44 +248,12 @@ DECLARE old_voided money.billing%ROWTYPE; BEGIN - SELECT * INTO old_billing FROM money.billing WHERE xact = NEW.xact AND NOT voided ORDER BY billing_ts DESC LIMIT 1; - SELECT * INTO old_voided FROM money.billing WHERE xact = NEW.xact ORDER BY billing_ts DESC LIMIT 1; + SELECT * INTO old_billing FROM money.billing WHERE xact = NEW.xact ORDER BY billing_ts DESC LIMIT 1; - IF NEW.voided AND NOT OLD.voided THEN - IF OLD.id = old_voided.id THEN - UPDATE money.materialized_billable_xact_summary - SET last_billing_ts = old_billing.billing_ts, - last_billing_note = old_billing.note, - last_billing_type = old_billing.billing_type - WHERE id = OLD.xact; - END IF; - - UPDATE money.materialized_billable_xact_summary - SET total_owed = total_owed - NEW.amount, - balance_owed = balance_owed - NEW.amount - WHERE id = NEW.xact; - - ELSIF NOT NEW.voided AND OLD.voided THEN - - IF OLD.id = old_billing.id THEN - UPDATE money.materialized_billable_xact_summary - SET last_billing_ts = old_billing.billing_ts, - last_billing_note = old_billing.note, - last_billing_type = old_billing.billing_type - WHERE id = OLD.xact; - END IF; - - UPDATE money.materialized_billable_xact_summary - SET total_owed = total_owed + NEW.amount, - balance_owed = balance_owed + NEW.amount - WHERE id = NEW.xact; - - ELSE - UPDATE money.materialized_billable_xact_summary - SET total_owed = total_owed - (OLD.amount - NEW.amount), + UPDATE money.materialized_billable_xact_summary + SET total_owed = total_owed - (OLD.amount - NEW.amount), balance_owed = balance_owed - (OLD.amount - NEW.amount) - WHERE id = NEW.xact; - END IF; + WHERE id = NEW.xact; RETURN NEW; END; @@ -372,8 +265,8 @@ DECLARE prev_billing money.billing%ROWTYPE; old_billing money.billing%ROWTYPE; BEGIN - SELECT * INTO prev_billing FROM money.billing WHERE xact = OLD.xact AND NOT voided ORDER BY billing_ts DESC LIMIT 1 OFFSET 1; - SELECT * INTO old_billing FROM money.billing WHERE xact = OLD.xact AND NOT voided ORDER BY billing_ts DESC LIMIT 1; + SELECT * INTO prev_billing FROM money.billing WHERE xact = OLD.xact ORDER BY billing_ts DESC LIMIT 1 OFFSET 1; + SELECT * INTO old_billing FROM money.billing WHERE xact = OLD.xact ORDER BY billing_ts DESC LIMIT 1; IF OLD.id = old_billing.id THEN UPDATE money.materialized_billable_xact_summary @@ -383,12 +276,10 @@ BEGIN WHERE id = OLD.xact; END IF; - IF NOT OLD.voided THEN - UPDATE money.materialized_billable_xact_summary - SET total_owed = total_owed - OLD.amount, - balance_owed = balance_owed + OLD.amount - WHERE id = OLD.xact; - END IF; + UPDATE money.materialized_billable_xact_summary + SET total_owed = total_owed - OLD.amount, + balance_owed = balance_owed + OLD.amount + WHERE id = OLD.xact; RETURN OLD; END; @@ -539,6 +430,17 @@ CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.forgive_payment FOR EAC CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.forgive_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('forgive_payment'); CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.forgive_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('forgive_payment'); +CREATE TABLE money.void_payment () INHERITS (money.bnm_payment); +ALTER TABLE money.void_payment ADD PRIMARY KEY (id); +CREATE INDEX money_void_id_idx ON money.void_payment (id); +CREATE INDEX money_void_payment_xact_idx ON money.void_payment (xact); +CREATE INDEX money_void_payment_payment_ts_idx ON money.void_payment (payment_ts); +CREATE INDEX money_void_payment_accepting_usr_idx ON money.void_payment (accepting_usr); + +CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.void_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('void_payment'); +CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.void_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('void_payment'); +CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.void_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('void_payment'); + CREATE TABLE money.work_payment () INHERITS (money.bnm_payment); ALTER TABLE money.work_payment ADD PRIMARY KEY (id); 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 d626c1da40..88051810eb 100644 --- a/Open-ILS/src/sql/Pg/950.data.seed-values.sql +++ b/Open-ILS/src/sql/Pg/950.data.seed-values.sql @@ -3527,33 +3527,6 @@ INSERT into config.org_unit_setting_type 'coust', 'description'), 'bool', null) -,( 'circ.forgive_lost_on_checkin', 'circ', - oils_i18n_gettext('circ.forgive_lost_on_checkin', - 'Forgive lost item billing when returned', - 'coust', 'label'), - oils_i18n_gettext('circ.forgive_lost_on_checkin', - 'Forgive lost item billing when returned', - 'coust', 'description'), - 'bool', null) - -,( 'circ.forgive_lost_proc_fee_on_checkin', 'circ', - oils_i18n_gettext('circ.forgive_lost_proc_fee_on_checkin', - 'Forgive processing fee on lost item return', - 'coust', 'label'), - oils_i18n_gettext('circ.forgive_lost_proc_fee_on_checkin', - 'Forgive processing fee when lost item returned', - 'coust', 'description'), - 'bool', null) - -,( 'circ.forgive_overdue_on_lost', 'finance', - oils_i18n_gettext('circ.forgive_overdue_on_lost', - 'Forgive overdue fines when items are marked lost', - 'coust', 'label'), - oils_i18n_gettext('circ.forgive_overdue_on_lost', - 'Forgive overdue fines when items are marked lost', - 'coust', 'description'), - 'bool', null) - ,( 'circ.void_lost_on_checkin', 'circ', oils_i18n_gettext('circ.void_lost_on_checkin', 'Void lost item billing when returned', diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.lost_forgive_not_void.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.data.lost_forgive_not_void.sql deleted file mode 100644 index 170064d4e9..0000000000 --- a/Open-ILS/src/sql/Pg/upgrade/XXXX.data.lost_forgive_not_void.sql +++ /dev/null @@ -1,43 +0,0 @@ --- Evergreen DB patch XXXX.data.lost_forgive_not_void.sql --- --- Insert new org unit settings for Forgive (not void) --- regarding Lost items --- -BEGIN; - - --- check whether patch can be applied -SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); - -INSERT into config.org_unit_setting_type -( name, grp, label, description, datatype, fm_class ) VALUES - -( 'circ.forgive_lost_on_checkin', 'circ', - oils_i18n_gettext('circ.forgive_lost_on_checkin', - 'Forgive lost item billing when returned', - 'coust', 'label'), - oils_i18n_gettext('circ.forgive_lost_on_checkin', - 'Forgive lost item billing when returned', - 'coust', 'description'), - 'bool', null) - -,( 'circ.forgive_lost_proc_fee_on_checkin', 'circ', - oils_i18n_gettext('circ.forgive_lost_proc_fee_on_checkin', - 'Forgive processing fee on lost item return', - 'coust', 'label'), - oils_i18n_gettext('circ.forgive_lost_proc_fee_on_checkin', - 'Forgive processing fee when lost item returned', - 'coust', 'description'), - 'bool', null) - -,( 'circ.forgive_overdue_on_lost', 'finance', - oils_i18n_gettext('circ.forgive_overdue_on_lost', - 'Forgive overdue fines when items are marked lost', - 'coust', 'label'), - oils_i18n_gettext('circ.forgive_overdue_on_lost', - 'Forgive overdue fines when items are marked lost', - 'coust', 'description'), - 'bool', null) -; - -COMMIT; diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.money.void_payment.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.money.void_payment.sql new file mode 100644 index 0000000000..610625ec19 --- /dev/null +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.money.void_payment.sql @@ -0,0 +1,196 @@ +-- Add table and triggers for the new void payment type. + +BEGIN; + +-- SELECT evergreen.upgrade_deps_block_check('XXXX', :eg_version); + +-- Create the money.void_payment table and associated triggers. +CREATE TABLE money.void_payment () INHERITS (money.bnm_payment); +ALTER TABLE money.void_payment ADD PRIMARY KEY (id); +CREATE INDEX money_void_id_idx ON money.void_payment (id); +CREATE INDEX money_void_payment_xact_idx ON money.void_payment (xact); +CREATE INDEX money_void_payment_payment_ts_idx ON money.void_payment (payment_ts); +CREATE INDEX money_void_payment_accepting_usr_idx ON money.void_payment (accepting_usr); + +CREATE TRIGGER mat_summary_add_tgr AFTER INSERT ON money.void_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_add ('void_payment'); +CREATE TRIGGER mat_summary_upd_tgr AFTER UPDATE ON money.void_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_update ('void_payment'); +CREATE TRIGGER mat_summary_del_tgr BEFORE DELETE ON money.void_payment FOR EACH ROW EXECUTE PROCEDURE money.materialized_summary_payment_del ('void_payment'); + + +-- Create money.void_payment entries for the existing voided bills. +INSERT INTO money.void_payment +(xact, payment_ts, amount, amount_collected, note, accepting_usr) +SELECT xact, void_time, amount, amount, 'Converted from voided billing.', + COALESCE(voider, 1) +FROM money.billing +WHERE voided = TRUE; + +-- Drop the voided, void_time and voider columns from money.billing. +ALTER TABLE money.billing DROP COLUMN voided CASCADE; +ALTER TABLE money.billing DROP COLUMN void_time CASCADE; +ALTER TABLE money.billing DROP COLUMN voider CASCADE; + +-- Recreate billing summary views now that voided is out of the picture. +CREATE OR REPLACE VIEW money.transaction_billing_type_summary AS + SELECT xact, + billing_type AS last_billing_type, + LAST(note) AS last_billing_note, + MAX(billing_ts) AS last_billing_ts, + SUM(COALESCE(amount,0)) AS total_owed + FROM money.billing + GROUP BY xact,billing_type + ORDER BY MAX(billing_ts); + +CREATE OR REPLACE VIEW money.transaction_billing_summary AS + SELECT xact, + LAST(billing_type) AS last_billing_type, + LAST(note) AS last_billing_note, + MAX(billing_ts) AS last_billing_ts, + SUM(COALESCE(amount,0)) AS total_owed + FROM money.billing + GROUP BY xact + ORDER BY MAX(billing_ts); + +CREATE OR REPLACE VIEW money.open_transaction_billing_type_summary AS + SELECT xact, + billing_type AS last_billing_type, + LAST(note) AS last_billing_note, + MAX(billing_ts) AS last_billing_ts, + SUM(COALESCE(amount,0)) AS total_owed + FROM money.billing + GROUP BY xact,billing_type + ORDER BY MAX(billing_ts); + +CREATE OR REPLACE VIEW money.open_transaction_billing_summary AS + SELECT xact, + LAST(billing_type) AS last_billing_type, + LAST(note) AS last_billing_note, + MAX(billing_ts) AS last_billing_ts, + SUM(COALESCE(amount,0)) AS total_owed + FROM money.billing + GROUP BY xact + ORDER BY MAX(billing_ts); + +CREATE OR REPLACE VIEW money.billable_xact_summary AS + SELECT xact.id, + xact.usr, + xact.xact_start, + xact.xact_finish, + COALESCE(credit.amount, 0.0::numeric) AS total_paid, + credit.payment_ts AS last_payment_ts, + credit.note AS last_payment_note, + credit.payment_type AS last_payment_type, + COALESCE(debit.amount, 0.0::numeric) AS total_owed, + debit.billing_ts AS last_billing_ts, + debit.note AS last_billing_note, + debit.billing_type AS last_billing_type, + COALESCE(debit.amount, 0.0::numeric) - COALESCE(credit.amount, 0.0::numeric) AS balance_owed, + p.relname AS xact_type + FROM money.billable_xact xact + JOIN pg_class p ON xact.tableoid = p.oid + LEFT JOIN ( + SELECT billing.xact, + sum(billing.amount) AS amount, + max(billing.billing_ts) AS billing_ts, + last(billing.note) AS note, + last(billing.billing_type) AS billing_type + FROM money.billing + GROUP BY billing.xact + ) debit ON xact.id = debit.xact + LEFT JOIN ( + SELECT payment_view.xact, + sum(payment_view.amount) AS amount, + max(payment_view.payment_ts) AS payment_ts, + last(payment_view.note) AS note, + last(payment_view.payment_type) AS payment_type + FROM money.payment_view + WHERE payment_view.voided IS FALSE + GROUP BY payment_view.xact + ) credit ON xact.id = credit.xact + ORDER BY debit.billing_ts, credit.payment_ts; + +-- Drop billing summary views that include voided. +DROP VIEW money.transaction_billing_with_void_summary; +DROP VIEW money.transaction_payment_with_void_summary; +DROP VIEW money.billable_xact_with_void_summary; + +-- Alter trigger functions as necessary. +/* BEFORE or AFTER trigger */ +CREATE OR REPLACE FUNCTION money.materialized_summary_billing_add () RETURNS TRIGGER AS $$ +BEGIN + UPDATE money.materialized_billable_xact_summary + SET total_owed = COALESCE(total_owed, 0.0::numeric) + NEW.amount, + last_billing_ts = NEW.billing_ts, + last_billing_note = NEW.note, + last_billing_type = NEW.billing_type, + balance_owed = balance_owed + NEW.amount + WHERE id = NEW.xact; + + RETURN NEW; +END; +$$ LANGUAGE PLPGSQL; + +/* AFTER trigger only! */ +CREATE OR REPLACE FUNCTION money.materialized_summary_billing_update () RETURNS TRIGGER AS $$ +DECLARE + old_billing money.billing%ROWTYPE; + old_voided money.billing%ROWTYPE; +BEGIN + + SELECT * INTO old_billing FROM money.billing WHERE xact = NEW.xact ORDER BY billing_ts DESC LIMIT 1; + + UPDATE money.materialized_billable_xact_summary + SET total_owed = total_owed - (OLD.amount - NEW.amount), + balance_owed = balance_owed - (OLD.amount - NEW.amount) + WHERE id = NEW.xact; + + RETURN NEW; +END; +$$ LANGUAGE PLPGSQL; + +/* BEFORE trigger only! */ +CREATE OR REPLACE FUNCTION money.materialized_summary_billing_del () RETURNS TRIGGER AS $$ +DECLARE + prev_billing money.billing%ROWTYPE; + old_billing money.billing%ROWTYPE; +BEGIN + SELECT * INTO prev_billing FROM money.billing WHERE xact = OLD.xact ORDER BY billing_ts DESC LIMIT 1 OFFSET 1; + SELECT * INTO old_billing FROM money.billing WHERE xact = OLD.xact ORDER BY billing_ts DESC LIMIT 1; + + IF OLD.id = old_billing.id THEN + UPDATE money.materialized_billable_xact_summary + SET last_billing_ts = prev_billing.billing_ts, + last_billing_note = prev_billing.note, + last_billing_type = prev_billing.billing_type + WHERE id = OLD.xact; + END IF; + + UPDATE money.materialized_billable_xact_summary + SET total_owed = total_owed - OLD.amount, + balance_owed = balance_owed + OLD.amount + WHERE id = OLD.xact; + + RETURN OLD; +END; +$$ LANGUAGE PLPGSQL; + +-- Update money.materialized_billable_xact_summary for changes in bills and payments. +-- Dyrcona had some lame DO thing, and tsbere sped it up with the below: +WITH xact_billing AS ( +SELECT xact, SUM(amount) AS total FROM money.billing GROUP BY xact +), +xact_payment AS ( +SELECT xact, SUM(amount) AS total FROM money.payment GROUP BY xact +), +xact_summary AS ( +SELECT xact, mb.total AS billing, mp.total AS payment, mb.total - mp.total AS balance +FROM xact_billing mb JOIN xact_payment mp USING (xact) +) +UPDATE money.materialized_billable_xact_summary +SET total_paid = xs.payment, + total_owed = xs.billing, + balance_owed = xs.balance +FROM xact_summary xs +WHERE xs.xact = id; + +COMMIT; diff --git a/Open-ILS/web/opac/locale/en-US/lang.dtd b/Open-ILS/web/opac/locale/en-US/lang.dtd index 0476324fbe..70063d8ae5 100644 --- a/Open-ILS/web/opac/locale/en-US/lang.dtd +++ b/Open-ILS/web/opac/locale/en-US/lang.dtd @@ -2140,8 +2140,6 @@ - - @@ -2183,14 +2181,10 @@ - - - -