added support for closing and re-opening invoices; viewing closed invoices as read...
authorerickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 16 Apr 2010 21:08:59 +0000 (21:08 +0000)
committererickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 16 Apr 2010 21:08:59 +0000 (21:08 +0000)
git-svn-id: svn://svn.open-ils.org/ILS/trunk@16262 dcc99617-32d9-48b4-a31d-7c20da2025e4

Open-ILS/web/css/skin/default.css
Open-ILS/web/css/skin/default/acq.css
Open-ILS/web/js/ui/default/acq/invoice/common.js
Open-ILS/web/js/ui/default/acq/invoice/view.js
Open-ILS/web/templates/default/acq/invoice/view.tt2

index 980907d..5ea73e9 100644 (file)
@@ -108,4 +108,9 @@ table { border-collapse: collapse; }
 
 .oils-progress-dialog { width: 300px; }
 
-
+.openils-widget-editpane-ro-name-cell {
+    font-weight: bold;
+}
+.openils-widget-editpane-ro-value-cell {
+    text-decoration: underline;
+}
index 96eaeaa..62619d3 100644 (file)
@@ -198,7 +198,7 @@ span[name="notes_alert_flag"] {color: #c00;font-weight: bold;font-size: 110%;mar
 /* INVOICING */
 #oils-acq-invoice-table td { padding: 5px; }
 .oils-acq-invoice-table td { padding: 5px; vertical-align: bottom;}
-.oils-acq-invoice-table thead td { font-weight: bold; background: #e0e0e0;}
+.oils-acq-invoice-table thead th { font-weight: bold; background: #e0e0e0;}
 #acq-invoice-new-msg { font-weight: bold; margin: 10px;}
 #acq-invoice-li-details { padding: 10px; font-weight: bold; border: 1px solid #888; margin: 10px; }
 #acq-invoice-create { margin: 10px; }
@@ -207,6 +207,8 @@ span[name="notes_alert_flag"] {color: #c00;font-weight: bold;font-size: 110%;mar
 .acq-invoice-row td { border-bottom: 1px solid #e0e0e0; }
 .acq-invoice-invalid-amount input { color: red; font-weight: bold; }
 .acq-link-invoice-dialog td,.acq-link-invoice-dialog th {padding-top: 10px;}
+.acq-invoice-paid-col {background : #E0E0E0; text-align: center;}
+.acq-invoice-center-col { text-align: center; }
 
 #acq-unified-heading { margin-bottom: 10px; }
 #acq-unified-heading-actual { float: left; width: 50%; font-size: 120%; font-weight: bold; }
index 00d2567..b52f38c 100644 (file)
@@ -20,10 +20,12 @@ function drawInvoicePane(parentNode, inv, args) {
 
     var pane = new openils.widget.EditPane({
         fmObject : inv,
+        paneStackCount : 2,
         fmClass : 'acqinv',
         mode : (inv) ? 'edit' : 'create',
         hideActionButtons : true,
         overrideWidgetArgs : override,
+        readOnly : (inv) && openils.Util.isTrue(inv.complete()),
         requiredFields : [
             'inv_ident', 
             'recv_date', 
@@ -38,7 +40,7 @@ function drawInvoicePane(parentNode, inv, args) {
             'provider', 
             'shipper'
         ],
-        suppressFields : ['id']
+        suppressFields : ['id', 'complete']
     });
 
     pane.startup();
index 37527e5..69db886 100644 (file)
@@ -77,6 +77,24 @@ function renderInvoice() {
 
     updateTotalCost();
 
+    if(invoice && openils.Util.isTrue(invoice.complete())) {
+
+        dojo.forEach( // hide widgets that should not be visible for a completed invoice
+            dojo.query('.hide-complete'), 
+            function(node) { openils.Util.hide(node); }
+        );
+
+        new openils.User().getPermOrgList(
+            'ACQ_INVOICE_REOPEN', 
+            function (orgs) {
+                if(orgs.indexOf(invoice.receiver()) >= 0)
+                    openils.Util.show('acq-invoice-reopen-button-wrapper', 'inline');
+            }, 
+            true, 
+            true
+        );
+    }
+
     if(invoice) {
         dojo.forEach(
             invoice.items(),
@@ -169,22 +187,23 @@ function updateTotalCost() {
     var totalCost = 0;    
     for(var id in widgetRegistry.acqii) 
         if(!widgetRegistry.acqii[id]._object.isdeleted())
-            totalCost += widgetRegistry.acqii[id].cost_billed.getFormattedValue();
+            totalCost += Number(widgetRegistry.acqii[id].cost_billed.getFormattedValue());
     for(var id in widgetRegistry.acqie) 
         if(!widgetRegistry.acqie[id]._object.isdeleted())
-            totalCost += widgetRegistry.acqie[id].cost_billed.getFormattedValue();
+            totalCost += Number(widgetRegistry.acqie[id].cost_billed.getFormattedValue());
     totalInvoicedBox.attr('value', totalCost);
 
     totalPaid = 0;    
     for(var id in widgetRegistry.acqii) 
         if(!widgetRegistry.acqii[id]._object.isdeleted())
-            totalPaid += widgetRegistry.acqii[id].amount_paid.getFormattedValue();
+            totalPaid += Number(widgetRegistry.acqii[id].amount_paid.getFormattedValue());
     for(var id in widgetRegistry.acqie) 
         if(!widgetRegistry.acqie[id]._object.isdeleted())
-            totalPaid += widgetRegistry.acqie[id].amount_paid.getFormattedValue();
+            totalPaid += Number(widgetRegistry.acqie[id].amount_paid.getFormattedValue());
     totalPaidBox.attr('value', totalPaid);
 
     var buttonsDisabled = false;
+
     if(totalPaid > totalCost || totalPaid < 0) {
         openils.Util.addCSSClass(totalPaidBox.domNode, 'acq-invoice-invalid-amount');
         invoiceSaveButton.attr('disabled', true);
@@ -208,6 +227,12 @@ function updateTotalCost() {
         }
     }
 
+    if(totalPaid == totalCost) { // XXX: too rigid?
+        invoiceCloseButton.attr('disabled', false);
+    } else {
+        invoiceCloseButton.attr('disabled', true);
+    }
+
     balanceOwedBox.attr('value', (totalCost - totalPaid));
 }
 
@@ -243,6 +268,13 @@ function addInvoiceItem(item) {
     dojo.forEach(
         ['title', 'author', 'cost_billed', 'amount_paid'], 
         function(field) {
+            
+            var args;
+            if(field == 'title' || field == 'author') {
+                args = {style : 'width:10em'};
+            } else if(field == 'cost_billed' || field == 'amount_paid') {
+                args = {required : true, style : 'width: 6em'};
+            }
             registerWidget(
                 item,
                 field,
@@ -250,7 +282,8 @@ function addInvoiceItem(item) {
                     fmClass : 'acqii',
                     fmObject : item,
                     fmField : field,
-                    dijitArgs : (field == 'cost_billed' || field == 'amount_paid') ? {required : true, style : 'width: 6em'} : null,
+                    readOnly : invoice && openils.Util.isTrue(invoice.complete()),
+                    dijitArgs : args,
                     parentNode : nodeByName(field, row)
                 })
             )
@@ -265,6 +298,7 @@ function addInvoiceItem(item) {
         fmField : 'fund',
         labelFormat : fundLabelFormat,
         searchFormat : fundSearchFormat,
+        readOnly : invoice && openils.Util.isTrue(invoice.complete()),
         parentNode : nodeByName('fund', row)
     }
 
@@ -288,6 +322,7 @@ function addInvoiceItem(item) {
             fmObject : item,
             fmField : 'inv_item_type',
             parentNode : nodeByName('inv_item_type', row),
+            readOnly : invoice && openils.Util.isTrue(invoice.complete()),
             dijitArgs : {required : true}
         }),
         function(w, ww) {
@@ -331,6 +366,11 @@ function addInvoiceItem(item) {
 }
 
 function addInvoiceEntry(entry) {
+
+    openils.Util.removeCSSClass(dojo.byId('acq-invoice-entry-header'), 'hidden');
+    openils.Util.removeCSSClass(dojo.byId('acq-invoice-entry-thead'), 'hidden');
+    openils.Util.removeCSSClass(dojo.byId('acq-invoice-entry-tbody'), 'hidden');
+
     entryTbody = dojo.byId('acq-invoice-entry-tbody');
     if(entryTemplate == null) {
         entryTemplate = entryTbody.removeChild(dojo.byId('acq-invoice-entry-template'));
@@ -394,6 +434,7 @@ function addInvoiceEntry(entry) {
                     fmClass : 'acqie',
                     fmField : field,
                     dijitArgs : dijitArgs,
+                    readOnly : invoice && openils.Util.isTrue(invoice.complete()),
                     parentNode : nodeByName(field, row)
                 })
             );
@@ -434,65 +475,75 @@ function liMarcAttr(lineitem, name) {
     return (attr) ? attr.attr_value() : '';
 }
 
-function saveChanges(doProrate) {
+function saveChanges(doProrate, doClose, doReopen) {
     
     progressDialog.show(true);
 
-    var updateItems = [];
-    for(var id in widgetRegistry.acqii) {
-        var reg = widgetRegistry.acqii[id];
-        var item = reg._object;
-        if(item.ischanged() || item.isnew() || item.isdeleted()) {
-            updateItems.push(item);
-            if(item.isnew()) item.id(null);
-            for(var field in reg) {
-                if(field != '_object')
-                    item[field]( reg[field].getFormattedValue() );
+    if(doReopen) {
+        invoice.complete('f');
+
+    } else {
+
+
+        var updateItems = [];
+        for(var id in widgetRegistry.acqii) {
+            var reg = widgetRegistry.acqii[id];
+            var item = reg._object;
+            if(item.ischanged() || item.isnew() || item.isdeleted()) {
+                updateItems.push(item);
+                if(item.isnew()) item.id(null);
+                for(var field in reg) {
+                    if(field != '_object')
+                        item[field]( reg[field].getFormattedValue() );
+                }
+                
+                // unflesh
+                if(item.purchase_order() != null && typeof item.purchase_order() == 'object')
+                    item.purchase_order( item.purchase_order().id() );
             }
-            
-            // unflesh
-            if(item.purchase_order() != null && typeof item.purchase_order() == 'object')
-                item.purchase_order( item.purchase_order().id() );
         }
-    }
 
-    var updateEntries = [];
-    for(var id in widgetRegistry.acqie) {
-        var reg = widgetRegistry.acqie[id];
-        var entry = reg._object;
-        if(entry.ischanged() || entry.isnew() || entry.isdeleted()) {
-            entry.lineitem(entry.lineitem().id());
-            entry.purchase_order(entry.purchase_order().id());
-            updateEntries.push(entry);
-            if(entry.isnew()) entry.id(null);
-
-            for(var field in reg) {
-                if(field != '_object')
-                    entry[field]( reg[field].getFormattedValue() );
-            }
-            
-            // unflesh
-            dojo.forEach(['purchase_order', 'lineitem'],
-                function(field) {
-                    if(entry[field]() != null && typeof entry[field]() == 'object')
-                        entry[field]( entry[field]().id() );
+        var updateEntries = [];
+        for(var id in widgetRegistry.acqie) {
+            var reg = widgetRegistry.acqie[id];
+            var entry = reg._object;
+            if(entry.ischanged() || entry.isnew() || entry.isdeleted()) {
+                entry.lineitem(entry.lineitem().id());
+                entry.purchase_order(entry.purchase_order().id());
+                updateEntries.push(entry);
+                if(entry.isnew()) entry.id(null);
+
+                for(var field in reg) {
+                    if(field != '_object')
+                        entry[field]( reg[field].getFormattedValue() );
                 }
-            );
+                
+                // unflesh
+                dojo.forEach(['purchase_order', 'lineitem'],
+                    function(field) {
+                        if(entry[field]() != null && typeof entry[field]() == 'object')
+                            entry[field]( entry[field]().id() );
+                    }
+                );
+            }
         }
-    }
 
-    if(!invoice) {
-        invoice = new fieldmapper.acqinv();
-        invoice.isnew(true);
-    } else {
-        invoice.ischanged(true); // for now, just always update
-    }
-
-    dojo.forEach(invoicePane.fieldList, 
-        function(field) {
-            invoice[field.name]( field.widget.getFormattedValue() );
+        if(!invoice) {
+            invoice = new fieldmapper.acqinv();
+            invoice.isnew(true);
+        } else {
+            invoice.ischanged(true); // for now, just always update
         }
-    );
+
+        dojo.forEach(invoicePane.fieldList, 
+            function(field) {
+                invoice[field.name]( field.widget.getFormattedValue() );
+            }
+        );
+
+        if(doClose) 
+            invoice.complete('t');
+    }
 
     fieldmapper.standardRequest(
         ['open-ils.acq', 'open-ils.acq.invoice.update'],
index 1195750..fe30fc1 100644 (file)
@@ -17,7 +17,7 @@
     <div dojoType="dijit.layout.ContentPane" layoutAlign="client">
         <table class='oils-acq-invoice-table'>
             <thead/>
-            <tbody>
+            <tbody id='acq-invoice-entry-header' class='hidden'>
                 <tr>
                     <td colspan='0'>
                         <h3>Bibliographic Items</h3>
                 </tr>
             </tbody>
             <!-- acq.invoice_entry -->
-            <thead>
-                <td colspan='3'>Title Details</td>
-                <td># Invoiced / # Received</td>
-                <td>Amount Billed</td>
-                <td>Amount Paid</td>
-                <td>Detach</td>
+            <thead id='acq-invoice-entry-thead' class='hidden'>
+                <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'>Billed</th>
+                    <th class='acq-invoice-paid-col'>Paid</th>
+                    <th class='acq-invoice-center-col hide-complete'>Detach</th>
+                </tr>
             </thead>
-            <tbody id='acq-invoice-entry-tbody'>
+            <tbody id='acq-invoice-entry-tbody' class='hidden'>
                 <tr id='acq-invoice-entry-template' class='acq-invoice-row'>
-                    <td colspan='3'>
+                    <td colspan='2'>
                         <div name='title_details'></div>
                         <div name='note'></div>
                     </td>
-                    <td nowrap='nowrap'>
-                        <span name='inv_item_count'></span>&nbsp;/&nbsp;<span name='phys_item_count'></span>
+                    <td class='acq-invoice-center-col'>
+                        <span name='inv_item_count'></span>
                     </td>
-                    <td><div name='cost_billed'/></td>
-                    <td><div name='amount_paid'/></td>
-                    <td><a href='javascript:void(0);' name='detach'>Detach</a></td>
+                    <td class='acq-invoice-center-col'>
+                        <span name='phys_item_count'></span>
+                    </td>
+                    <td class='acq-invoice-billed-col'><div name='cost_billed'/></td>
+                    <td class='acq-invoice-paid-col'><div name='amount_paid'/></td>
+                    <td class='acq-invoice-center-col hide-complete'><a href='javascript:void(0);' name='detach'>Detach</a></td>
                 </tr>
             </tbody>
             <tbody>
             </tbody>
             <!-- acq.invoice_item -->
             <thead>
-                <td>Charge Type</td>
-                <td>Title / Description (optional)</td>
-                <td>Author (optional)</td>
-                <td>Fund</td>
-                <td>Amount Billed</td>
-                <td>Amount Paid</td>
-                <td>Delete</td>
+                <tr>
+                    <th>Charge Type</th>
+                    <th>Title/Description</th>
+                    <th>Author</th>
+                    <th class='acq-invoice-center-col'>Fund</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'>Delete</th>
+                </tr>
             </thead>
             <tbody id='acq-invoice-item-tbody'>
                 <tr id='acq-invoice-item-template' class='acq-invoice-row acq-invoice-item-row'>
                     <td><div name='inv_item_type'/></td>
                     <td><div name='title'/></td>
                     <td><div name='author'/></td>
-                    <td><div name='fund'/></td>
-                    <td><div name='cost_billed'/></td>
-                    <td><div name='amount_paid'/></td>
-                    <td><a href='javascript:void(0);' name='delete'>Delete</a></td>
+                    <td class='acq-invoice-center-col'><div name='fund'/></td>
+                    <td class='acq-invoice-center-col' class='acq-invoice-billed-col'><div name='cost_billed'/></td>
+                    <td class='acq-invoice-paid-col'><div name='amount_paid'/></td>
+                    <td class='acq-invoice-center-col' class='hide-complete acq-invoice-balance-col'><a href='javascript:void(0);' name='delete'>Delete</a></td>
                 </tr>
             </tbody>
-            <tbody>
+            <tbody class='hide-complete'>
                 <tr>
                     <td colspan='0'>
                         <a href='javascript:void(0);' id='acq-invoice-new-item'>Add Charge...</a>
             </tbody>
             <thead>
                 <tr>
-                    <td colspan='4'/>
-                    <td>Total Invoiced</td>
-                    <td>Total Paid</td>
-                    <td>Balance Owed</td>
+                    <th colspan='4'/>
+                    <th class='acq-invoice-center-col' class='acq-invoice-billed-col'>Total</th>
+                    <th class='acq-invoice-paid-col'>Total</th>
+                    <th class='acq-invoice-center-col' class='acq-invoice-balance-col'>Balance</th>
                 </tr>
             </thead>
             <tbody>
                 <tr>
                     <td colspan='4' style='text-align:right;'>
-                        <button jsId='invoiceSaveButton' 
-                            dojoType='dijit.form.Button' onclick='saveChanges();'>Save Changes</button>
-                        <button jsId='invoiceProrateButton' 
-                            dojoType='dijit.form.Button' onclick='saveChanges(true);'>Save &amp; Prorate Charges</button>
+                        <button jsId='invoiceSaveButton' class='hide-complete'
+                            dojoType='dijit.form.Button' onclick='saveChanges();'>Save</button>
+                        <button jsId='invoiceProrateButton' class='hide-complete'
+                            dojoType='dijit.form.Button' onclick='saveChanges(true);'>Save &amp; Prorate</button>
+                        <button jsId='invoiceCloseButton' class='hide-complete'
+                            dojoType='dijit.form.Button' onclick='saveChanges(false, true);'>Save &amp; Close</button>
+                        <span class='hidden' id='acq-invoice-reopen-button-wrapper'>
+                            <button jsId='invoiceReopenButton' 
+                                dojoType='dijit.form.Button' onclick='saveChanges(false, false, true);'>Reopen Invoice</button>
+                        </span>
                     </td>
-                    <td><div jsId='totalInvoicedBox' dojoType='dijit.form.CurrencyTextBox' style='width:6em;'/></td>
-                    <td><div jsId='totalPaidBox' dojoType='dijit.form.CurrencyTextBox' style='width:6em;'/></td>
-                    <td><div jsId='balanceOwedBox' dojoType='dijit.form.CurrencyTextBox' style='width:6em;'/></td>
+                    <td class='acq-invoice-center-col'><div jsId='totalInvoicedBox' dojoType='dijit.form.CurrencyTextBox' style='width:6em;'/></td>
+                    <td class='acq-invoice-paid-col'><div jsId='totalPaidBox' dojoType='dijit.form.CurrencyTextBox' style='width:6em;'/></td>
+                    <td class='acq-invoice-center-col'><div jsId='balanceOwedBox' dojoType='dijit.form.CurrencyTextBox' style='width:6em;'/></td>
                 </tr>
             </tbody>
         </table>