[open-ils-commits] [GIT] Evergreen ILS branch master updated. 72a8c6a0004602e7eae6c1b3cfa4704df8e8618a

Evergreen Git git at git.evergreen-ils.org
Thu Feb 25 20:41:31 EST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Evergreen ILS".

The branch, master has been updated
       via  72a8c6a0004602e7eae6c1b3cfa4704df8e8618a (commit)
       via  cf3ae6d8c01f1006dfffce25420e0ef931ccaf07 (commit)
       via  78364a52cdc0168640b94232ef70bb293f665092 (commit)
       via  b2beeb68119835c3df27fcee88b459cd41d6e77a (commit)
       via  f4ac2ee44d8a3886c874b7426690166d19229204 (commit)
      from  431d6372122256e1f7b8f7e893f32c6b64a42181 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 72a8c6a0004602e7eae6c1b3cfa4704df8e8618a
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu Feb 25 13:33:20 2016 -0500

    LP#1333254 Improve entry debit maintenance for inv. open/close.
    
    Improve handling of debit->entry links for invoices that cross the
    open/close boundary, modifying the number of items invoiced on an entry,
    and rolling back invoice entry debits.
    
    Prior to this, some debits would be unnecessarily linked to entries and
    fail to clean up properly when rolled back.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm
index fa01606..a8126f4 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm
@@ -85,7 +85,7 @@ sub build_invoice_impl {
                 $e->create_acq_invoice_entry($entry) or return $e->die_event;
                 return $evt if $evt = uncancel_copies_as_needed($e, $entry);
                 return $evt if $evt = update_entry_debits(
-                    $e, $entry, 0, $inv_closing, $inv_reopening);
+                    $e, $entry, 'unlinked', $inv_closing, $inv_reopening);
             } elsif ($entry->isdeleted) {
                 # XXX Deleting entries does not recancel anything previously
                 # uncanceled.
@@ -97,15 +97,19 @@ sub build_invoice_impl {
 
                 if ($orig_entry->amount_paid != $entry->amount_paid or
                     $entry->phys_item_count != $orig_entry->phys_item_count) {
-                    return $evt if $evt = rollback_entry_debits($e,$orig_entry);
+                    return $evt if $evt = rollback_entry_debits(
+                        $e, $orig_entry, $orig_entry);
 
                     # XXX Updates can only uncancel more LIDs when
                     # phys_item_count goes up, but cannot recancel them when
                     # phys_item_count goes down.
                     return $evt if $evt = uncancel_copies_as_needed($e, $entry);
 
+                    # debits were rolled back (encumbrance=t) above, so now 
+                    # search for un-invoiced, potentially linked debits 
+                    # to (re-) invoice.
                     return $evt if $evt = update_entry_debits(
-                        $e, $entry, 1, $inv_closing, $inv_reopening);
+                        $e, $entry, 'all', $inv_closing, $inv_reopening);
                 }
 
                 $e->update_acq_invoice_entry($entry) or return $e->die_event;
@@ -300,7 +304,7 @@ sub handle_invoice_state_change {
 
     my @debits;
     for my $entry (@{$invoice->entries}) {
-        push(@debits, @{find_entry_debits($e, $entry, 1, $enc_find)});
+        push(@debits, @{find_linked_entry_debits($e, $entry, $enc_find)});
     }
 
     for my $item (@{$invoice->items}) {
@@ -340,10 +344,26 @@ sub build_invoice_api {
 }
 
 
+# 1. set encumbrance=true
+# 2. unlink debit entries.
 sub rollback_entry_debits {
-    my($e, $entry) = @_;
-    my $debits = find_entry_debits($e, $entry, 1, 'f', entry_amount_per_item($entry));
-    my $lineitem = $e->retrieve_acq_lineitem($entry->lineitem) or return $e->die_event;
+    my($e, $entry, $orig_entry) = @_;
+
+    # when modifying an entry, roll back all debits that were 
+    # affected given the previous state of the entry.
+    my $need_count = $orig_entry ? 
+        $orig_entry->phys_item_count : $entry->phys_item_count;
+
+    # Un-link all linked debits when rolling back
+    my $debits = find_linked_entry_debits($e, $entry);
+
+    # Additionally, find legacy dis-encumbered debits that link 
+    # to this entry via lineitem.
+    push (@$debits, @{find_non_linked_debits(
+        $e, $entry->lineitem, $need_count, undef, 'f')});
+
+    my $lineitem = $e->retrieve_acq_lineitem($entry->lineitem) 
+        or return $e->die_event;
 
     for my $debit (@$debits) {
         # revert to the original estimated amount re-encumber
@@ -364,10 +384,10 @@ sub rollback_entry_debits {
 # inv_closing -- invoice is going from complete=f to t.
 # inv_reopening -- invoice is going from complete=t to f.
 sub update_entry_debits {
-    my($e, $entry, $invoiced, $inv_closing, $inv_reopening) = @_;
+    my($e, $entry, $link_state, $inv_closing, $inv_reopening) = @_;
 
     my $debits = find_entry_debits(
-        $e, $entry, $invoiced, $inv_reopening ? 'f' : 't');
+        $e, $entry, $link_state, $inv_reopening ? 'f' : 't');
     return undef unless @$debits;
 
     if($entry->phys_item_count > @$debits) {
@@ -523,7 +543,7 @@ sub amounts_spent_per_fund {
 
     my %totals_by_fund;
     foreach my $entry (@$entries) {
-        my $debits = find_entry_debits($e, $entry, 1, "f") or return 0;
+        my $debits = find_entry_debits($e, $entry, 'linked', "f") or return 0;
         foreach (@$debits) {
             $totals_by_fund{$_->fund} ||= 0.0;
             $totals_by_fund{$_->fund} += $_->amount;
@@ -548,74 +568,106 @@ sub amounts_spent_per_fund {
     return \@totals;
 }
 
-# find fund debits related to an invoice entry.
-# invoiced -- debits already linked to this invoice
-sub find_entry_debits {
-    my($e, $entry, $invoiced, $encumbrance, $amount, $fallback) = @_;
+# Returns all debits linked to the provided invoice entry.
+# If an encumbrance value is provided, only debits matching the
+# encumbrance state are returned.
+sub find_linked_entry_debits {
+    my($e, $entry, $encumbrance) = @_;
 
     my $query = {
         select => {acqfdeb => ['id']},
-        # sort received items to the front
-        order_by => {'acqlid' => ['recv_time']}
+        order_by => {'acqlid' => ['recv_time']},
+        from => {acqfdeb => 'acqlid'},
+        where => {'+acqfdeb' => {invoice_entry => $entry->id}}
     };
 
-    if ($invoiced && !$fallback) { # previously invoiced
+    $query->{where}->{'+acqfdeb'}->{encumbrance} 
+        = $encumbrance if $encumbrance;
 
-        # Debits which have been invoiced will have a link to the last 
-        # invoice entry which affected them.
+    my $debits = $e->json_query($query);
 
-        $query->{from} = {acqfdeb => 'acqlid'};
-        $query->{where} = {'+acqfdeb' => {invoice_entry => $entry->id}};
+    return [] unless @$debits;
 
-    } else {
+    my $debit_ids = [map { $_->{id} } @$debits];
+    return $e->search_acq_fund_debit({id => $debit_ids});
+}
 
-        # For un-invoiced (or $fallback) debits, search for those 
-        # that are linked to the entry via the lineitem.
+# Returns all debits for the requested lineitem
+# that are not yet linked to an invoice entry.
+# If an encumbrance value is provided, only debits matching the
+# encumbrance state are returned.
+# note: only legacy debits can exist in a state where 
+# encumbrance=false and the debit is not linked to an entry.
+sub find_non_linked_debits {
+    my($e, $li_id, $count, $amount, $encumbrance) = @_;
 
-        $query->{from} = {
+    my $query = {
+        select => {acqfdeb => ['id']},
+        order_by => {'acqlid' => ['recv_time']},
+        where => {'+acqfdeb' => {invoice_entry => undef}},
+        from => {
             acqfdeb => {
                 acqlid => {
                     join => {
-                        jub =>  {
-                            join => {
-                                acqie => {
-                                    filter => {id => $entry->id}
-                                }
-                            }
+                        jub => {
+                            filter => {id => $li_id}
                         }
                     }
                 }
             }
-        };
-
-        $query->{where} = {'+acqfdeb' => {}}; # for later
-        $query->{where}->{'+acqfdeb'}->{amount} = $amount if $amount;
-        $query->{limit} = $entry->phys_item_count;
-    }
+        }
+    };
 
     $query->{where}->{'+acqfdeb'}->{encumbrance} = $encumbrance if $encumbrance;
+    $query->{where}->{'+acqfdeb'}->{amount} = $amount if $amount;
+    $query->{limit} = $count if defined $count;
 
     my $debits = $e->json_query($query);
+
+    return [] unless @$debits;
+
     my $debit_ids = [map { $_->{id} } @$debits];
+    return $e->search_acq_fund_debit({id => $debit_ids});
+}
+
+# find fund debits related to an invoice entry.
+# link_state -- 'linked', 'unlinked', 'all'
+# When link_state==undef, start with linked debits, then add unlinked debits.
+sub find_entry_debits {
+    my($e, $entry, $link_state, $encumbrance, $amount, $count) = @_;
 
-    if (!@$debit_ids) { # no debits found
+    my $need_count = $count || $entry->phys_item_count;
+    my $debits = [];
+
+    if ($link_state eq 'all' || $link_state eq 'linked') {
+        $debits = find_linked_entry_debits($e, $entry, $encumbrance);
+        return $debits if @$debits && scalar(@$debits) == $need_count;
+    }
+
+    # either we don't have enough linked debits to cover the need_count
+    # or we are not looking for linked debits.  Keep looking.
+
+    if ($link_state eq 'all' || $link_state eq 'unlinked') {
+
+        # If we found linked debits above, reduce the number of
+        # required debits remaining by the number already found.
+        $need_count = $need_count - scalar(@$debits);
+
+        push (@$debits, @{find_non_linked_debits(
+            $e, $entry->lineitem, $need_count, $amount, $encumbrance)});
+
+    } elsif (scalar(@$debits) == 0) {
 
         # if a lookup for previously invoiced debits returns zero
         # results, it may be becuase the debits were created before
         # the presence of the acq.fund_debit.invoice_entry column.
-        # Attempt to use the old-style lookup for these debits using the
-        # "$fallback" flag.
-        if ($invoiced && !$fallback) {
-            $logger->info(
-                "invoice: using debit fallback lookup for entry ".$entry->id);
-            return find_entry_debits(
-                $e, $entry, $invoiced, $encumbrance, $amount, 1);
-        }
+        # Fall back to using the old-style lookup.
 
-        return [];
+        push (@$debits, @{find_non_linked_debits(
+            $e, $entry->lineitem, $need_count, $amount, $encumbrance)});
     }
 
-    return $e->search_acq_fund_debit({id => $debit_ids});
+    return $debits;
 }
 
 
@@ -694,7 +746,7 @@ sub prorate_invoice {
 
     my @lid_debits;
     push(@lid_debits, 
-        @{find_entry_debits($e, $_, 1, 'f', entry_amount_per_item($_))}) 
+        @{find_entry_debits($e, $_, 'linked', 'f', entry_amount_per_item($_))}) 
         for @{$invoice->entries};
 
     my $inv_items = $e->search_acq_invoice_item([

commit cf3ae6d8c01f1006dfffce25420e0ef931ccaf07
Author: Bill Erickson <berickxx at gmail.com>
Date:   Wed Feb 24 12:35:53 2016 -0500

    LP#1333254 Support closing new invoices
    
    Allow invoices to be closed at create time (as originally intended) by
    fixing code thinko.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm
index 772b6fa..fa01606 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm
@@ -56,7 +56,7 @@ sub build_invoice_impl {
     if ($invoice->isnew) {
         $invoice->recv_method('PPR') unless $invoice->recv_method;
         $invoice->recv_date('now') unless $invoice->recv_date;
-        my $inv_closing = $U->is_true($invoice->complete);
+        $inv_closing = $U->is_true($invoice->complete);
         $e->create_acq_invoice($invoice) or return $e->die_event;
     } elsif ($invoice->isdeleted) {
         $e->delete_acq_invoice($invoice) or return $e->die_event;

commit 78364a52cdc0168640b94232ef70bb293f665092
Author: Bill Erickson <berickxx at gmail.com>
Date:   Mon Jan 4 14:38:28 2016 -0500

    LP#1333254 Release notes
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>

diff --git a/docs/RELEASE_NOTES_NEXT/Acquisitions/debits-paid-on-invoice-close.adoc b/docs/RELEASE_NOTES_NEXT/Acquisitions/debits-paid-on-invoice-close.adoc
new file mode 100644
index 0000000..23ea9e7
--- /dev/null
+++ b/docs/RELEASE_NOTES_NEXT/Acquisitions/debits-paid-on-invoice-close.adoc
@@ -0,0 +1,8 @@
+Disencumber Funds on Invoice Close
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Fund debits linked to an invoice are now marked as paid (encumbrance=false)
+when the invoice is marked as closed/complete instead of at invoice create
+time.  This is particularly useful for EDI invoices which may be 
+created well in advance of receipt and payment.
+

commit b2beeb68119835c3df27fcee88b459cd41d6e77a
Author: Bill Erickson <berickxx at gmail.com>
Date:   Mon Jan 4 15:24:18 2016 -0500

    LP#1333254 Perl live tests
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>

diff --git a/Open-ILS/src/perlmods/live_t/13-acq-invoicing.t b/Open-ILS/src/perlmods/live_t/13-acq-invoicing.t
index 1df01fa..82f9ec0 100644
--- a/Open-ILS/src/perlmods/live_t/13-acq-invoicing.t
+++ b/Open-ILS/src/perlmods/live_t/13-acq-invoicing.t
@@ -1,6 +1,6 @@
 #!perl
 use strict; use warnings;
-use Test::More tests => 4;
+use Test::More tests => 7;
 use OpenILS::Utils::TestUtils;
 use OpenILS::Utils::CStoreEditor qw/:funcs/;
 
@@ -44,9 +44,18 @@ my $req = $acq_ses->request(
     'open-ils.acq.invoice.update', $script->authtoken, $invoice, [$entry]);
 
 $invoice = $req->recv->content;
+$entry = $invoice->entries->[0];
 
 is(ref $invoice, 'Fieldmapper::acq::invoice', 'Invoice created');
 
+my $inv_debit = 
+    $e->search_acq_fund_debit({invoice_entry => $entry->id})->[0];
+
+isnt($inv_debit, undef, 'A fund_debit links to new invoice entry');
+
+is($inv_debit->encumbrance, 't', 
+    'Debit is still encumbered after invoice create');
+
 # Close the invoice.  LP#1333254. 
 $invoice->complete('t');
 $invoice->ischanged(1);
@@ -58,10 +67,22 @@ $invoice = $req->recv->content;
 
 is($invoice->complete, 't', 'Invoice is closed');
 
-$entry = $invoice->entries->[0];
-my $debits = $e->search_acq_fund_debit({id => [1,2]});
-my @matching = grep { ($_->invoice_entry || '') eq $entry->id } @$debits;
+$inv_debit = $e->retrieve_acq_fund_debit($inv_debit->id);
+
+is($inv_debit->encumbrance, 'f', 
+    'Debit is disencumbered after invoice close');
+
+# re-open the invoice
+$invoice->complete('f');
+$invoice->ischanged(1);
+
+$req = $acq_ses->request(
+    'open-ils.acq.invoice.update', $script->authtoken, $invoice);
+
+$invoice = $req->recv->content;
+
+$inv_debit = $e->retrieve_acq_fund_debit($inv_debit->id);
 
-isnt(scalar(@matching), 0, 
-    'At least one fund_debit should link to new invoice entry');
+is($inv_debit->encumbrance, 't', 
+    'Debit is re-encumbered when invoice is reopened');
 

commit f4ac2ee44d8a3886c874b7426690166d19229204
Author: Bill Erickson <berickxx at gmail.com>
Date:   Thu Dec 31 17:35:34 2015 -0500

    LP#1333254 Disencumber on invoice close
    
    Set encumbrance=false on invoiced fund debits when the invoice is closed
    (complete=true) instead of when the invoice is created.
    
    To test:
    
    1. Activate a purchase order.
    2. Create an invoice for the PO.
    3. Confirm PO shows same amount encumbered as befor invoicing and $0
       paid.
    4. Close the invoice.
    5. Confirm amount encumbered on the PO is reduced by the amount invoiced
       and the amount paid on the PO is increased by the amount invoiced.
    
    Signed-off-by: Bill Erickson <berickxx at gmail.com>
    Signed-off-by: Kathy Lussier <klussier at masslnc.org>

diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm
index 95071bb..772b6fa 100644
--- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm
+++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Invoice.pm
@@ -12,7 +12,7 @@ my $U = 'OpenILS::Application::AppUtils';
 
 # return nothing on success, event on failure
 sub _prepare_fund_debit_for_inv_item {
-    my ($debit, $item, $e) = @_;
+    my ($debit, $item, $e, $inv_closing) = @_;
 
     $debit->fund($item->fund);
     $debit->amount($item->amount_paid);
@@ -22,7 +22,7 @@ sub _prepare_fund_debit_for_inv_item {
     my $fund = $e->retrieve_acq_fund($item->fund) or return $e->die_event;
 
     $debit->origin_currency_type($fund->currency_type);
-    $debit->encumbrance('f');
+    $debit->encumbrance($inv_closing ? 'f' : 't');
     $debit->debit_type('direct_charge');
 
     return;
@@ -50,13 +50,28 @@ sub build_invoice_impl {
 
     $finalize_pos ||= [];
 
+    my $inv_closing = 0;
+    my $inv_reopening = 0;
+
     if ($invoice->isnew) {
         $invoice->recv_method('PPR') unless $invoice->recv_method;
         $invoice->recv_date('now') unless $invoice->recv_date;
+        my $inv_closing = $U->is_true($invoice->complete);
         $e->create_acq_invoice($invoice) or return $e->die_event;
     } elsif ($invoice->isdeleted) {
         $e->delete_acq_invoice($invoice) or return $e->die_event;
     } else {
+        my $orig_inv = $e->retrieve_acq_invoice($invoice->id)
+            or return $e->die_event;
+
+        $inv_closing = (
+            !$U->is_true($orig_inv->complete) && 
+            $U->is_true($invoice->complete));
+
+        $inv_reopening = (
+            $U->is_true($orig_inv->complete) && 
+            !$U->is_true($invoice->complete));
+
         $e->update_acq_invoice($invoice) or return $e->die_event;
     }
 
@@ -69,7 +84,8 @@ sub build_invoice_impl {
             if ($entry->isnew) {
                 $e->create_acq_invoice_entry($entry) or return $e->die_event;
                 return $evt if $evt = uncancel_copies_as_needed($e, $entry);
-                return $evt if $evt = update_entry_debits($e, $entry);
+                return $evt if $evt = update_entry_debits(
+                    $e, $entry, 0, $inv_closing, $inv_reopening);
             } elsif ($entry->isdeleted) {
                 # XXX Deleting entries does not recancel anything previously
                 # uncanceled.
@@ -88,7 +104,8 @@ sub build_invoice_impl {
                     # phys_item_count goes down.
                     return $evt if $evt = uncancel_copies_as_needed($e, $entry);
 
-                    return $evt if $evt = update_entry_debits($e, $entry);
+                    return $evt if $evt = update_entry_debits(
+                        $e, $entry, 1, $inv_closing, $inv_reopening);
                 }
 
                 $e->update_acq_invoice_entry($entry) or return $e->die_event;
@@ -145,8 +162,8 @@ sub build_invoice_impl {
                         $debit->isnew(1);
                     }
 
-                    return $evt if
-                        $evt = _prepare_fund_debit_for_inv_item($debit, $item, $e);
+                    return $evt if $evt = _prepare_fund_debit_for_inv_item(
+                        $debit, $item, $e, $inv_closing);
 
                     if ($debit->isnew) {
                         $e->create_acq_fund_debit($debit)
@@ -173,8 +190,11 @@ sub build_invoice_impl {
                     # so when that happens, just delete the extraneous
                     # debit (in the else block).
                     my $debit = $e->retrieve_acq_fund_debit($item->fund_debit);
-                    $debit->encumbrance('t');
-                    $e->update_acq_fund_debit($debit) or return $e->die_event;
+                    if (!$U->us_true($debit->encumbrance)) {
+                        $debit->encumbrance('t');
+                        $e->update_acq_fund_debit($debit) 
+                            or return $e->die_event;
+                    }
 
                 } elsif ($item->fund_debit) {
 
@@ -204,7 +224,8 @@ sub build_invoice_impl {
                     $debit->isnew(1);
 
                     return $evt if
-                        $evt = _prepare_fund_debit_for_inv_item($debit, $item, $e);
+                        $evt = _prepare_fund_debit_for_inv_item(
+                            $debit, $item, $e, $inv_closing);
                 } else {
                     $debit = $e->retrieve_acq_fund_debit($item->fund_debit) or
                         return $e->die_event;
@@ -249,6 +270,18 @@ sub build_invoice_impl {
     }
 
     $invoice = fetch_invoice_impl($e, $invoice->id);
+
+    # entries and items processed above may not represent every item or
+    # entry in the invoice.  This will synchronize any remaining debits.
+    if ($inv_closing || $inv_reopening) {
+
+        # inv_closing=false implies inv_reopening=true
+        $evt = handle_invoice_state_change($e, $invoice, $inv_closing);
+        return $evt if $evt;
+
+        $invoice = fetch_invoice_impl($e, $invoice->id);
+    }
+
     if ($do_commit) {
         $e->commit or return $e->die_event;
     }
@@ -256,6 +289,35 @@ sub build_invoice_impl {
     return $invoice;
 }
 
+# When an invoice opens or closes, ensure all linked debits match 
+# the open/close state of the invoice.
+# If $closing is false, code assumes the invoice is reopening.
+sub handle_invoice_state_change {
+    my ($e, $invoice, $closing) = @_;
+
+    my $enc_find = $closing ? 't' : 'f'; # debits to process
+    my $enc_set  = $closing ? 'f' : 't'; # new encumbrance value
+
+    my @debits;
+    for my $entry (@{$invoice->entries}) {
+        push(@debits, @{find_entry_debits($e, $entry, 1, $enc_find)});
+    }
+
+    for my $item (@{$invoice->items}) {
+        push(@debits, $item->fund_debit) if
+            $item->fund_debit && 
+            $item->fund_debit->encumbrance eq $enc_find;
+    }
+
+    # udpate all linked debits to match the state of the invoice
+    for my $debit (@debits) {
+        $debit->encumbrance($enc_set);
+        $e->update_acq_fund_debit($debit) or return $e->die_event;
+    }
+
+    return undef;
+}
+
 sub build_invoice_api {
     my($self, $conn, $auth, $invoice, $entries, $items, $finalize_pos) = @_;
 
@@ -280,7 +342,7 @@ sub build_invoice_api {
 
 sub rollback_entry_debits {
     my($e, $entry) = @_;
-    my $debits = find_entry_debits($e, $entry, 'f', entry_amount_per_item($entry));
+    my $debits = find_entry_debits($e, $entry, 1, 'f', entry_amount_per_item($entry));
     my $lineitem = $e->retrieve_acq_lineitem($entry->lineitem) or return $e->die_event;
 
     for my $debit (@$debits) {
@@ -298,10 +360,14 @@ sub rollback_entry_debits {
     return undef;
 }
 
+# invoiced -- debits already linked to this invoice
+# inv_closing -- invoice is going from complete=f to t.
+# inv_reopening -- invoice is going from complete=t to f.
 sub update_entry_debits {
-    my($e, $entry) = @_;
+    my($e, $entry, $invoiced, $inv_closing, $inv_reopening) = @_;
 
-    my $debits = find_entry_debits($e, $entry, 't');
+    my $debits = find_entry_debits(
+        $e, $entry, $invoiced, $inv_reopening ? 'f' : 't');
     return undef unless @$debits;
 
     if($entry->phys_item_count > @$debits) {
@@ -315,7 +381,7 @@ sub update_entry_debits {
     for my $debit (@$debits) {
         my $amount = entry_amount_per_item($entry);
         $debit->amount($amount);
-        $debit->encumbrance('f');
+        $debit->encumbrance($inv_closing ? 'f' : 't');
 
         # debit always reports the invoice_entry responsible
         # for its most recent modification.
@@ -363,7 +429,7 @@ sub uncancel_copies_as_needed {
         },
         where => {
             '+acqlid' => {lineitem => $li->id},
-            '+acqfdeb' => {encumbrance => 't'}  # not-yet invoiced copies
+            '+acqfdeb' => {invoice_entry => undef}  # not-yet invoiced copies
         },
         order_by => [{
             class => 'acqcr',
@@ -457,7 +523,7 @@ sub amounts_spent_per_fund {
 
     my %totals_by_fund;
     foreach my $entry (@$entries) {
-        my $debits = find_entry_debits($e, $entry, "f") or return 0;
+        my $debits = find_entry_debits($e, $entry, 1, "f") or return 0;
         foreach (@$debits) {
             $totals_by_fund{$_->fund} ||= 0.0;
             $totals_by_fund{$_->fund} += $_->amount;
@@ -483,8 +549,9 @@ sub amounts_spent_per_fund {
 }
 
 # find fund debits related to an invoice entry.
+# invoiced -- debits already linked to this invoice
 sub find_entry_debits {
-    my($e, $entry, $encumbrance, $amount, $fallback) = @_;
+    my($e, $entry, $invoiced, $encumbrance, $amount, $fallback) = @_;
 
     my $query = {
         select => {acqfdeb => ['id']},
@@ -492,10 +559,10 @@ sub find_entry_debits {
         order_by => {'acqlid' => ['recv_time']}
     };
 
-    if ($encumbrance eq 'f' and !$fallback) { # previously invoiced
+    if ($invoiced && !$fallback) { # previously invoiced
 
-        # Debits which have been invoiced (encumbrance = f) will have a 
-        # link to the last entry which affected them
+        # Debits which have been invoiced will have a link to the last 
+        # invoice entry which affected them.
 
         $query->{from} = {acqfdeb => 'acqlid'};
         $query->{where} = {'+acqfdeb' => {invoice_entry => $entry->id}};
@@ -521,26 +588,28 @@ sub find_entry_debits {
             }
         };
 
+        $query->{where} = {'+acqfdeb' => {}}; # for later
+        $query->{where}->{'+acqfdeb'}->{amount} = $amount if $amount;
         $query->{limit} = $entry->phys_item_count;
-        $query->{where} = {'+acqfdeb' => {encumbrance => $encumbrance}};
     }
 
-    $query->{where}->{'+acqfdeb'}->{amount} = $amount if $amount;
+    $query->{where}->{'+acqfdeb'}->{encumbrance} = $encumbrance if $encumbrance;
 
     my $debits = $e->json_query($query);
     my $debit_ids = [map { $_->{id} } @$debits];
 
     if (!@$debit_ids) { # no debits found
 
-        # if a lookup for previously invoiced debits (encumbrance=f) 
-        # returns zero results, it may be becuase the debits were
-        # created before the presence of the acq.fund_debit.invoice_entry
-        # column.  Attempt to use the old-style lookup for these debits
-        # using the "$fallback" flag.
-        if (!$fallback and $encumbrance eq 'f') {
+        # if a lookup for previously invoiced debits returns zero
+        # results, it may be becuase the debits were created before
+        # the presence of the acq.fund_debit.invoice_entry column.
+        # Attempt to use the old-style lookup for these debits using the
+        # "$fallback" flag.
+        if ($invoiced && !$fallback) {
             $logger->info(
                 "invoice: using debit fallback lookup for entry ".$entry->id);
-            return find_entry_debits($e, $entry, $encumbrance, $amount, 1);
+            return find_entry_debits(
+                $e, $entry, $invoiced, $encumbrance, $amount, 1);
         }
 
         return [];
@@ -624,7 +693,9 @@ sub prorate_invoice {
     return $e->die_event unless $e->allowed('CREATE_INVOICE', $invoice->receiver);
 
     my @lid_debits;
-    push(@lid_debits, @{find_entry_debits($e, $_, 'f', entry_amount_per_item($_))}) for @{$invoice->entries};
+    push(@lid_debits, 
+        @{find_entry_debits($e, $_, 1, 'f', entry_amount_per_item($_))}) 
+        for @{$invoice->entries};
 
     my $inv_items = $e->search_acq_invoice_item([
         {"invoice" => $invoice_id, "fund_debit" => {"!=" => undef}},
@@ -683,7 +754,7 @@ sub prorate_invoice {
             $debit->amount($prorated_amount);
             $debit->origin_amount($prorated_amount);
             $debit->origin_currency_type($e->retrieve_acq_fund($fund_id)->currency_type); # future: cache funds locally
-            $debit->encumbrance('f');
+            $debit->encumbrance('t'); # Set to 'f' when invoice is closed
             $debit->debit_type('prorated_charge');
 
             if($debit->isnew) {
@@ -863,10 +934,9 @@ sub finalize_blanket_po {
 
         my $debit = $item->fund_debit or next;
 
-        next unless $U->is_true($debit->encumbrance);
+        next if $debit->amount == 0;
 
         $debit->amount(0);
-        $debit->encumbrance('f');
         $e->update_acq_fund_debit($debit) or return $e->die_event;
     }
 

-----------------------------------------------------------------------

Summary of changes:
 .../lib/OpenILS/Application/Acq/Invoice.pm         |  244 +++++++++++++++-----
 Open-ILS/src/perlmods/live_t/13-acq-invoicing.t    |   33 +++-
 .../Acquisitions/debits-paid-on-invoice-close.adoc |    8 +
 3 files changed, 218 insertions(+), 67 deletions(-)
 create mode 100644 docs/RELEASE_NOTES_NEXT/Acquisitions/debits-paid-on-invoice-close.adoc


hooks/post-receive
-- 
Evergreen ILS


More information about the open-ils-commits mailing list