From: erickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Date: Wed, 28 Apr 2010 15:24:31 +0000 (+0000)
Subject: Loosened some restrictions on invoicing.  It is now possible to invoice
X-Git-Url: https://old-git.evergreen-ils.org/?a=commitdiff_plain;h=e26241b5b9b8ad1e2bea02dff7ea9c14a606380e;p=evergreen%2Fmasslnc.git

Loosened some restrictions on invoicing.  It is now possible to invoice
items that have not yet been received.  It is also possible to invoice
for cancelled items, assuming the debit for the cancelled item remains.

git-svn-id: svn://svn.open-ils.org/ILS/trunk@16333 dcc99617-32d9-48b4-a31d-7c20da2025e4
---

diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Acq/Invoice.pm b/Open-ILS/src/perlmods/OpenILS/Application/Acq/Invoice.pm
index e435c4700d..7842494f37 100644
--- a/Open-ILS/src/perlmods/OpenILS/Application/Acq/Invoice.pm
+++ b/Open-ILS/src/perlmods/OpenILS/Application/Acq/Invoice.pm
@@ -179,6 +179,7 @@ sub update_entry_debits {
 sub entry_amount_per_item {
     my $entry = shift;
     return $entry->amount_paid if $U->is_true($entry->billed_per_item);
+    return 0 if $entry->phys_item_count == 0;
     return $entry->amount_paid / $entry->phys_item_count;
 }
 
@@ -193,7 +194,6 @@ sub find_entry_debits {
         from => {
             acqfdeb => {
                 acqlid => {
-                    filter => {cancel_reason => undef, recv_time => {'!=' => undef}},
                     join => {
                         jub =>  {
                             join => {
@@ -207,7 +207,7 @@ sub find_entry_debits {
             }
         },
         where => {'+acqfdeb' => {encumbrance => $encumbrance}},
-        order_by => {'acqlid' => ['recv_time']},
+        order_by => {'acqlid' => ['recv_time']}, # un-received items will sort to the end
         limit => $entry->phys_item_count
     };
 
diff --git a/Open-ILS/src/perlmods/OpenILS/Application/Acq/Order.pm b/Open-ILS/src/perlmods/OpenILS/Application/Acq/Order.pm
index b51bb75ff7..6217933fa0 100644
--- a/Open-ILS/src/perlmods/OpenILS/Application/Acq/Order.pm
+++ b/Open-ILS/src/perlmods/OpenILS/Application/Acq/Order.pm
@@ -646,6 +646,9 @@ sub create_lineitem_debits {
 sub create_lineitem_detail_debit {
     my ($mgr, $li, $lid, $dry_run, $no_translate) = @_;
 
+    # don't create the debit if one already exists
+    return $mgr->editor->retrieve_acq_fund_debit($lid->fund_debit) if $lid->fund_debit;
+
     my $li_id = ref($li) ? $li->id : $li;
 
     unless(ref $li and ref $li->provider) {
@@ -2275,7 +2278,7 @@ sub cancel_purchase_order {
         $mgr->editor->allowed("CREATE_PURCHASE_ORDER", $po->ordering_agency);
 
     $po->state("cancelled");
-    $po->cancel_reason($cancel_reason);
+    $po->cancel_reason($cancel_reason->id);
 
     my $li_ids = $mgr->editor->search_acq_lineitem(
         {"purchase_order" => $po_id}, {"idlist" => 1}
@@ -2436,7 +2439,7 @@ sub cancel_lineitem {
     );
 
     $li->state("cancelled");
-    $li->cancel_reason($cancel_reason);
+    $li->cancel_reason($cancel_reason->id);
 
     my $lids = $mgr->editor->search_acq_lineitem_detail([{
         "lineitem" => $li_id
@@ -2469,7 +2472,7 @@ sub cancel_lineitem {
     # Attempt to delete the gathered copies (this will also handle volume deletion and bib deletion)
     # Another edge case, if we have a bib but not copies, are we supposed to delete the bib?
     if (scalar(@$copies)>0) {
-        my $override = 0;
+        my $override = 1;
         my $delete_stats = undef;
         my $retarget_holds = [];
         my $cat_evt = OpenILS::Application::Cat::AssetCommon->update_fleshed_copies(
@@ -2533,9 +2536,6 @@ sub cancel_lineitem {
         }
     }
 
-    # TODO delete the associated fund debits?
-    # TODO who/what/where/how do we indicate this change for electronic orders?
-
     update_lineitem($mgr, $li) or return 0;
     $result->{"li"} = {
         $li_id => {
@@ -2627,28 +2627,28 @@ sub cancel_lineitem_detail {
         $lid->lineitem->purchase_order->ordering_agency
     ) or (! $lid->lineitem->purchase_order);
 
-    $lid->cancel_reason($cancel_reason);
+    $lid->cancel_reason($cancel_reason->id);
 
-    # TODO who/what/where/how do we indicate this change for electronic orders?
+    unless($U->is_true($cancel_reason->keep_debits)) {
+        my $debit_id = $lid->fund_debit;
+        $lid->clear_fund_debit;
 
-    my $debit_id = $lid->fund_debit;
-    $lid->clear_fund_debit;
+        if($debit_id) {
+            # item is cancelled.  Remove the fund debit.
+            my $debit = $mgr->editor->retrieve_acq_fund_debit($debit_id);
+            if (!$U->is_true($debit->encumbrance)) {
+                $mgr->editor->rollback;
+                return OpenILS::Event->new('ACQ_NOT_CANCELABLE', 
+                    note => "Debit is marked as paid: $debit_id");
+            }
+            $mgr->editor->delete_acq_fund_debit($debit) or return $mgr->editor->die_event;
+        }
+    }
 
     # XXX LIDs don't have either an editor or a edit_time field. Should we
     # update these on the LI when we alter an LID?
     $mgr->editor->update_acq_lineitem_detail($lid) or return 0;
 
-    if($debit_id) {
-        # item is cancelled.  Remove the fund debit.
-        my $debit = $mgr->editor->retrieve_acq_fund_debit($debit_id);
-        if (!$U->is_true($debit->encumbrance)) {
-            $mgr->editor->rollback;
-            return OpenILS::Event->new('ACQ_NOT_CANCELABLE', 
-                note => "Debit is marked as paid: $debit_id");
-        }
-        $mgr->editor->delete_acq_fund_debit($debit) or return $mgr->editor->die_event;
-    }
-
     return {"lid" => {$lid_id => {"cancel_reason" => $cancel_reason}}};
 }
 
diff --git a/Open-ILS/web/js/dojo/openils/acq/nls/acq.js b/Open-ILS/web/js/dojo/openils/acq/nls/acq.js
index c1a53365fc..b4e89c9181 100644
--- a/Open-ILS/web/js/dojo/openils/acq/nls/acq.js
+++ b/Open-ILS/web/js/dojo/openils/acq/nls/acq.js
@@ -67,8 +67,8 @@
             "<a style='padding-right: 10px;' href='${11}/acq/po/view/${12}'>PO#${13} ${18}</a>" +
             "<a style='padding-right: 10px;' href='${11}/acq/picklist/view/${14}'>${15}</a></div>",
     'INVOICE_CONFIRM_PRORATE' : "Prorate charges?\n\nAny subsequent changes to the invoice that would affect prorated amounts should be resolved manually.",
-    'INVOICE_EXTRA_COPIES' : "You are invoicing <b>${0}</b> more copies than originally ordered.  <br/>The order will be updated to reflect the additional copies" +
-        "<br/><br/>After saving the invoice, you may finish editing and importing the new copies from the lineitem details page.",
+    'INVOICE_EXTRA_COPIES' : "You are attempting to invoice <b>${0}</b> more copies than originally ordered.  <br/><br/>To add these items to the original order, " +
+        "select a fund and choose 'Add New Items' below.  <br/>After saving the invoice, you may finish editing and importing the new copies from the lineitem details page.",
     //'INVOICE_EXTRA_COPIES_CATALOG' : "Add <b>${0}</b> new copies to the catalog?",
     'UNNAMED': "Unnamed",
     'NO_FIND_INVOICE': "Could not find that invoice.\nNote that the Invoice # field is case-sensitive.",
diff --git a/Open-ILS/web/js/ui/default/acq/common/li_table.js b/Open-ILS/web/js/ui/default/acq/common/li_table.js
index 55b8284994..6563eba0c6 100644
--- a/Open-ILS/web/js/ui/default/acq/common/li_table.js
+++ b/Open-ILS/web/js/ui/default/acq/common/li_table.js
@@ -349,7 +349,9 @@ function AcqLiTable() {
 
         /* of course I'd rather just populate a <span> element inside the
          * option element, but it seems you can't actually have any elements
-         * inside option elements */
+         * inside option elements 
+         * TODO: move to dojo/i18n
+         * */
         option.innerHTML = option.innerHTML.replace(
             /(^.+)(.*)( existing.+$)/, "$1" + String(count) + "$3"
         );
@@ -438,6 +440,28 @@ function AcqLiTable() {
         /* handle links that appear/disappear based on whether LI is received */
         if (this.isPO) {
             var self = this;
+
+            actNewInvoice.onclick = function() {
+                location.href = oilsBasePath + '/acq/invoice/view?create=1&attach_li=' + li.id();
+                nodeByName("action_none", row).selected = true;
+            };
+            actLinkInvoice.onclick = function() {
+                self.invoiceLinkDialogManager.target = li;
+                acqLitLinkInvoiceDialog.show();
+                nodeByName("action_none", row).selected = true;
+            };
+            actViewInvoice.onclick = function() {
+                location.href = oilsBasePath +
+                    "/acq/search/unified?so=" +
+                    base64Encode({"jub":[{"id": li.id()}]}) +
+                    "&rt=invoice";
+                nodeByName("action_none", row).selected = true;
+            };
+
+            actNewInvoice.disabled = false;
+            actLinkInvoice.disabled = false;
+            actViewInvoice.disabled = false;
+
             switch(li.state()) {
                 case "on-order":
                     actReceive.disabled = false;
@@ -447,6 +471,7 @@ function AcqLiTable() {
                         nodeByName("action_none", row).selected = true;
                     };
                     return;
+
                 case "received":
                     actUnRecv.disabled = false;
                     actUnRecv.onclick = function() {
@@ -464,27 +489,6 @@ function AcqLiTable() {
                     actHoldingsMaint.disabled = false;
                     actHoldingsMaint.onclick = self.generateMakeRecTab( li.eg_bib_id(), 'copy_browser', row );
 
-                    actNewInvoice.disabled = false;
-                    actLinkInvoice.disabled = false;
-                    actViewInvoice.disabled = false;
-
-                    actNewInvoice.onclick = function() {
-                        location.href = oilsBasePath + '/acq/invoice/view?create=1&attach_li=' + li.id();
-                        nodeByName("action_none", row).selected = true;
-                    };
-                    actLinkInvoice.onclick = function() {
-                        self.invoiceLinkDialogManager.target = li;
-                        acqLitLinkInvoiceDialog.show();
-                        nodeByName("action_none", row).selected = true;
-                    };
-                    actViewInvoice.onclick = function() {
-                        location.href = oilsBasePath +
-                            "/acq/search/unified?so=" +
-                            base64Encode({"jub":[{"id": li.id()}]}) +
-                            "&rt=invoice";
-                        nodeByName("action_none", row).selected = true;
-                    };
-
                     return;
             }
         }
diff --git a/Open-ILS/web/js/ui/default/acq/invoice/view.js b/Open-ILS/web/js/ui/default/acq/invoice/view.js
index abe6824fb4..c4770c22df 100644
--- a/Open-ILS/web/js/ui/default/acq/invoice/view.js
+++ b/Open-ILS/web/js/ui/default/acq/invoice/view.js
@@ -69,6 +69,7 @@ function init() {
         searchFilter : {active : 't'},
         labelFormat : fundLabelFormat,
         searchFormat : fundSearchFormat,
+        dijitArgs : {required : true},
         parentNode : dojo.byId('acq-invoice-extra-copies-fund')
     });
     extraCopiesFund.build();
@@ -289,6 +290,7 @@ function addInvoiceItem(item) {
         labelFormat : fundLabelFormat,
         searchFormat : fundSearchFormat,
         readOnly : invoice && openils.Util.isTrue(invoice.complete()),
+        dijitArgs : {required : true},
         parentNode : nodeByName('fund', row)
     }
 
@@ -379,39 +381,42 @@ function addInvoiceEntry(entry) {
             entry.lineitem(li);
             entry.purchase_order(li.purchase_order());
             nodeByName('title_details', row).innerHTML = html;
-        }
-    );
 
-    dojo.forEach(
-        ['inv_item_count', 'phys_item_count', 'cost_billed', 'amount_paid'],
-        function(field) {
-            var dijitArgs = {required : true, constraints : {min: 0}, style : 'width:6em'};
-            if(entry.isnew() && field == 'phys_item_count') dijitArgs.value = numReceived;
-            registerWidget(
-                entry, 
-                field,
-                new openils.widget.AutoFieldWidget({
-                    fmObject : entry,
-                    fmClass : 'acqie',
-                    fmField : field,
-                    dijitArgs : dijitArgs,
-                    readOnly : invoice && openils.Util.isTrue(invoice.complete()),
-                    parentNode : nodeByName(field, row)
-                }),
-                function(w) {    
-                    if(field == 'phys_item_count') {
-                        dojo.connect(w, 'onChange', 
-                            function() {
-                                // staff entered a higher number in the receive field than was originally ordered
-                                if(Number(this.attr('value')) > entry.lineitem().item_count()) {
-                                    storeExtraCopies(
-                                        entry.lineitem().id(), 
-                                        Number(this.attr('value')) - entry.lineitem().item_count()
-                                    );
-                                }
-                            }
-                        )
+            dojo.forEach(
+                ['inv_item_count', 'phys_item_count', 'cost_billed', 'amount_paid'],
+                function(field) {
+                    var dijitArgs = {required : true, constraints : {min: 0}, style : 'width:6em'};
+                    if(entry.isnew() && field == 'phys_item_count') {
+                        // by default, attempt to pay for all received and as-of-yet-un-invoiced items
+                        dijitArgs.value = (Number(li.order_summary().recv_count()) - Number(li.order_summary().invoice_count())) || 0;
                     }
+                    registerWidget(
+                        entry, 
+                        field,
+                        new openils.widget.AutoFieldWidget({
+                            fmObject : entry,
+                            fmClass : 'acqie',
+                            fmField : field,
+                            dijitArgs : dijitArgs,
+                            readOnly : invoice && openils.Util.isTrue(invoice.complete()),
+                            parentNode : nodeByName(field, row)
+                        }),
+                        function(w) {    
+                            if(field == 'phys_item_count') {
+                                dojo.connect(w, 'onChange', 
+                                    function() {
+                                        // staff entered a higher number in the receive field than was originally ordered
+                                        // taking into account already invoiced items
+                                        var extra = Number(this.attr('value')) - 
+                                            (Number(entry.lineitem().item_count()) - Number(entry.lineitem().order_summary().invoice_count()));
+                                        if(extra > 0) {
+                                            storeExtraCopies(entry, extra);
+                                        }
+                                    }
+                                )
+                            }
+                        }
+                    );
                 }
             );
         }
@@ -565,7 +570,7 @@ function prorateInvoice(invoice) {
     );
 }
 
-function storeExtraCopies(liId, numExtra) {
+function storeExtraCopies(entry, numExtra) {
 
     dojo.byId('acq-invoice-extra-copies-message').innerHTML = 
         dojo.string.substitute(
@@ -576,7 +581,7 @@ function storeExtraCopies(liId, numExtra) {
         extraCopiesGo, 
         'onClick',
         function() {
-            extraCopies[liId] = {
+            extraCopies[entry.lineitem().id()] = {
                 numExtra : numExtra, 
                 fund : extraCopiesFund.widget.attr('value')
             }
@@ -586,9 +591,12 @@ function storeExtraCopies(liId, numExtra) {
     );
 
     dojo.connect(
-       extraCopiesCancel, 
-       'onClick',
-       function() { extraItemsDialog.hide() }
+        extraCopiesCancel, 
+        'onClick',
+        function() { 
+            widgetRegistry.acqie[entry.id()].phys_item_count.widget.attr('value', '');
+            extraItemsDialog.hide() 
+        }
     );
 
     extraItemsDialog.show();
diff --git a/Open-ILS/web/templates/default/acq/common/li_table.tt2 b/Open-ILS/web/templates/default/acq/common/li_table.tt2
index 627286e07d..2e90632520 100644
--- a/Open-ILS/web/templates/default/acq/common/li_table.tt2
+++ b/Open-ILS/web/templates/default/acq/common/li_table.tt2
@@ -114,7 +114,7 @@
                             <option name='action_link_invoice' disabled='disabled'>Link to Invoice</option>
                             <option name='action_view_invoice' disabled='disabled'>View Invoice(s)</option>
                             <option name='action_view_claim_policy'>Apply Claim Policy</option>
-                            <option name='action_manage_claims' disabled='disabled'>Manage Claims ( existing)</option>
+                            <option name='action_manage_claims' disabled='disabled'>Claims ( existing)</option>
                         </select>
                     </td>
                     <td><span name='li_state'></span></td>
diff --git a/Open-ILS/web/templates/default/acq/invoice/view.tt2 b/Open-ILS/web/templates/default/acq/invoice/view.tt2
index c269675d72..6ad0e9a3a4 100644
--- a/Open-ILS/web/templates/default/acq/invoice/view.tt2
+++ b/Open-ILS/web/templates/default/acq/invoice/view.tt2
@@ -29,7 +29,7 @@
                 <tr>
                     <th colspan='2'>Title Details</th>
                     <th class='acq-invoice-center-col'># Invoiced</th>
-                    <th class='acq-invoice-center-col'># Received</th>
+                    <th class='acq-invoice-center-col'># Paid</th>
                     <th class='acq-invoice-center-col'>Billed</th>
                     <th class='acq-invoice-paid-col'>Paid</th>
                     <th class='acq-invoice-center-col hide-complete'>Detach</th>
@@ -133,15 +133,11 @@
         <br/>
         Select a fund for the new items: <div id='acq-invoice-extra-copies-fund'></div>
         <br/><br/>
-        <!--
-        <span id='acq-invoice-extra-copies-add-msg'></span>
-        <input dojoType='dijit.form.CheckBox' jsId='extraCopiesInCatalogCheckbox'></input>
-        -->
         <br/><br/>
         <span style='padding-right: 10px;'>
             <button dojoType='dijit.form.Button' jsId='extraCopiesCancel'>Cancel</button>
         </span>
-        <button dojoType='dijit.form.Button' jsId='extraCopiesGo'>Continue</button>
+        <button dojoType='dijit.form.Button' jsId='extraCopiesGo'>Add New Items</button>
     </div>
 </div>
 [% END %]