Loosened some restrictions on invoicing. It is now possible to invoice
authorerickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Wed, 28 Apr 2010 15:24:31 +0000 (15:24 +0000)
committererickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Wed, 28 Apr 2010 15:24:31 +0000 (15:24 +0000)
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

Open-ILS/src/perlmods/OpenILS/Application/Acq/Invoice.pm
Open-ILS/src/perlmods/OpenILS/Application/Acq/Order.pm
Open-ILS/web/js/dojo/openils/acq/nls/acq.js
Open-ILS/web/js/ui/default/acq/common/li_table.js
Open-ILS/web/js/ui/default/acq/invoice/view.js
Open-ILS/web/templates/default/acq/common/li_table.tt2
Open-ILS/web/templates/default/acq/invoice/view.tt2

index e435c47..7842494 100644 (file)
@@ -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
     };
 
index b51bb75..6217933 100644 (file)
@@ -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}}};
 }
 
index c1a5336..b4e89c9 100644 (file)
@@ -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.",
index 55b8284..6563eba 100644 (file)
@@ -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;
             }
         }
index abe6824..c4770c2 100644 (file)
@@ -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();
index 627286e..2e90632 100644 (file)
                             <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>
index c269675..6ad0e9a 100644 (file)
@@ -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>
         <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 %]