From 4bc4a07e4038705db6eb57be08c7680cf52aa49b Mon Sep 17 00:00:00 2001 From: erickson Date: Wed, 7 Apr 2010 14:52:12 +0000 Subject: [PATCH] More Invoice UI work. This covers: New view interface Creating new invoices directly in the view UI Creating invices from PO/LI Attaching PO/LI data to an existing invoice UI for handling of prorated item types Support for creating a new invoice fromt the po view page git-svn-id: svn://svn.open-ils.org/ILS/trunk@16154 dcc99617-32d9-48b4-a31d-7c20da2025e4 --- Open-ILS/web/css/skin/default/acq.css | 2 + Open-ILS/web/js/ui/default/acq/common/li_table.js | 2 +- Open-ILS/web/js/ui/default/acq/invoice/attach.js | 162 ------------ Open-ILS/web/js/ui/default/acq/invoice/common.js | 10 +- Open-ILS/web/js/ui/default/acq/invoice/view.js | 288 ++++++++++++++++++++- Open-ILS/web/js/ui/default/acq/po/view_po.js | 5 + .../web/templates/default/acq/invoice/attach.tt2 | 31 --- .../web/templates/default/acq/invoice/view.tt2 | 96 ++++++- Open-ILS/web/templates/default/acq/po/view.tt2 | 8 +- 9 files changed, 398 insertions(+), 206 deletions(-) delete mode 100644 Open-ILS/web/js/ui/default/acq/invoice/attach.js delete mode 100644 Open-ILS/web/templates/default/acq/invoice/attach.tt2 diff --git a/Open-ILS/web/css/skin/default/acq.css b/Open-ILS/web/css/skin/default/acq.css index 024f32dd63..ea0dea1aa0 100644 --- a/Open-ILS/web/css/skin/default/acq.css +++ b/Open-ILS/web/css/skin/default/acq.css @@ -197,6 +197,8 @@ 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;} #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; } 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 896a3fb530..21020b8c49 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 @@ -376,7 +376,7 @@ function AcqLiTable() { actViewInvoice.disabled = false; actNewInvoice.onclick = function() { - location.href = oilsBasePath + '/acq/invoice/attach?create=1&attach_li=' + li.id(); + location.href = oilsBasePath + '/acq/invoice/view?create=1&attach_li=' + li.id(); nodeByName("action_none", row).selected = true; }; actLinkInvoice.onclick = function() { diff --git a/Open-ILS/web/js/ui/default/acq/invoice/attach.js b/Open-ILS/web/js/ui/default/acq/invoice/attach.js deleted file mode 100644 index 1f49ce99b8..0000000000 --- a/Open-ILS/web/js/ui/default/acq/invoice/attach.js +++ /dev/null @@ -1,162 +0,0 @@ -dojo.require('dojo.date.locale'); -dojo.require('dojo.date.stamp'); -dojo.require('dijit.layout.ContentPane'); -dojo.require('dijit.form.TextBox'); -dojo.require('dijit.form.NumberTextBox'); -dojo.require('dijit.form.CurrencyTextBox'); -dojo.require('openils.User'); -dojo.require('openils.Util'); -dojo.require('openils.PermaCrud'); -dojo.require('openils.widget.AutoFieldWidget'); - -dojo.requireLocalization('openils.acq', 'acq'); -var localeStrings = dojo.i18n.getLocalization('openils.acq', 'acq'); - -var pcrud = new openils.PermaCrud(); -var cgi = new openils.CGI(); -var doCreate = false; -var invoiceId; -var lineitem; -var invoicePane; -var entryPane; - -function init() { - - invoiceId = cgi.param('invoice_id'); - doCreate = cgi.param('create'); - attachLi = cgi.param('attach_li'); - - invoicePane = drawInvoicePane(dojo.byId('acq-view-invoice-div')); - - fieldmapper.standardRequest( - ["open-ils.acq", "open-ils.acq.lineitem.retrieve"], { - async: true, - params: [openils.User.authtoken, attachLi, { - flesh_attrs: true, - flesh_li_details: true, - flesh_cancel_reason: true, - flesh_po : true, - flesh_pl : true - }], - oncomplete: function(r) { - lineitem = openils.Util.readResponse(r); - drawPage(); - } - } - ); - - dojo.connect(createInvoiceButton, 'onClick', function() { createInvoice(); }); -} - -function liMarcAttr(name) { - var attr = lineitem.attributes().filter( - function(attr) { - if( - attr.attr_type() == 'lineitem_marc_attr_definition' && - attr.attr_name() == name) - return attr - } - )[0]; - return (attr) ? attr.attr_value() : ''; -} - -function drawPage() { - - var idents = []; - if(liMarcAttr('isbn')) idents.push(liMarcAttr('isbn')); - if(liMarcAttr('upc')) idents.push(liMarcAttr('upc')); - if(liMarcAttr('issn')) idents.push(liMarcAttr('issn')); - - var orderDate = ''; - var po = lineitem.purchase_order(); - if(po.order_date()) { - var dt = dojo.date.stamp.fromISOString(po.order_date()); - orderDate = dojo.date.locale.format(dt, {selector:'date'}); - } - - dojo.byId('acq-invoice-li-details').innerHTML = - dojo.string.substitute( - localeStrings.INVOICE_ITEM_DETAILS, - [ - liMarcAttr('title'), - liMarcAttr('author'), - idents.join(','), - lineitem.estimated_unit_price() || '', - lineitem.id(), - lineitem.purchase_order().name(), - orderDate - ] - ); - - //invoicePo.attr('value', lineitem.purchase_order().name()); - //invoicePo.attr('disabled', true); - - //numCopiesInvoiced.attr('value', lineitem.lineitem_details().length); - - var numReceived = 0; - dojo.forEach(lineitem.lineitem_details(), function(lid) { if(lid.recv_time) numReceived++ }); - //numCopiesReceived.attr('value', numReceived); - - entryPane = new openils.widget.EditPane({ - fmClass : 'acqie', - mode : 'create', - hideActionButtons : true, - existingTable : invoicePane.table, - overrideWidgetArgs : { - inv_item_count : {widgetValue : numReceived}, - phys_item_count : {widgetValue : numReceived} - }, - fieldOrder : [ - 'purchase_order', - 'inv_item_count', - 'phys_item_count', - 'cost_billed', - 'note' - ], - suppressFields : [ - 'invoice', - 'purchase_order', - 'lineitem', - 'actual_cost' - ] - }); - entryPane.startup(); - -} - - -function createInvoice() { - - var inv = new fieldmapper.acqinv(); - dojo.forEach(invoicePane.fieldList, - function(field) { - inv[field.name]( field.widget.getFormattedValue() ); - } - ); - - var entry = new fieldmapper.acqie(); - dojo.forEach(entryPane.fieldList, - function(field) { - entry[field.name]( field.widget.getFormattedValue() ); - } - ); - entry.purchase_order(lineitem.purchase_order().id()); - entry.lineitem(lineitem.id()); - - fieldmapper.standardRequest( - ['open-ils.acq', 'open-ils.acq.invoice.create'], - { - params : [openils.User.authtoken, inv, [entry]], - oncomplete : function(r) { - var resp = openils.Util.readResponse(r); - if(resp) { - location.href = - location.href.replace(/invoice\/attach.*/, 'invoice/view/' + resp.id()); - } - } - } - ); -} - -openils.Util.addOnLoad(init); - diff --git a/Open-ILS/web/js/ui/default/acq/invoice/common.js b/Open-ILS/web/js/ui/default/acq/invoice/common.js index 953669127b..c03e8cf685 100644 --- a/Open-ILS/web/js/ui/default/acq/invoice/common.js +++ b/Open-ILS/web/js/ui/default/acq/invoice/common.js @@ -2,7 +2,8 @@ dojo.require('dojo.date.stamp'); dojo.require('openils.User'); dojo.require('openils.widget.EditPane'); -function drawInvoicePane(parentNode, inv) { +function drawInvoicePane(parentNode, inv, args) { + args = args || {}; var override; if(!inv) { @@ -13,6 +14,10 @@ function drawInvoicePane(parentNode, inv) { }; } + for(var field in args) { + override[field] = {widgetValue : args[field]}; + } + var pane = new openils.widget.EditPane({ fmObject : inv, fmClass : 'acqinv', @@ -26,7 +31,8 @@ function drawInvoicePane(parentNode, inv) { 'inv_type', 'provider', 'shipper' - ] + ], + suppressFields : ['id'] }); pane.startup(); 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 79028a24d2..9d1b90fe64 100644 --- a/Open-ILS/web/js/ui/default/acq/invoice/view.js +++ b/Open-ILS/web/js/ui/default/acq/invoice/view.js @@ -1,30 +1,306 @@ dojo.require('dojo.date.locale'); dojo.require('dojo.date.stamp'); +dojo.require('dijit.form.CheckBox'); +dojo.require('dijit.form.CurrencyTextBox'); +dojo.require('dijit.form.NumberTextBox'); dojo.require('openils.User'); dojo.require('openils.Util'); +dojo.require('openils.CGI'); dojo.require('openils.PermaCrud'); dojo.require('openils.widget.EditPane'); +dojo.require('openils.widget.AutoFieldWidget'); dojo.requireLocalization('openils.acq', 'acq'); var localeStrings = dojo.i18n.getLocalization('openils.acq', 'acq'); +var fundLabelFormat = ['${0} (${1})', 'code', 'year']; +var fundSearchFormat = ['${0} (${1})', 'code', 'year']; + +var cgi = new openils.CGI(); var pcrud = new openils.PermaCrud(); +var attachLi; +var attachPo; var invoice; +var itemTbody; +var itemTemplate; +var entryTemplate; +var totalAmountBox; +var invoicePane; +var itemTypes; + +function nodeByName(name, context) { + return dojo.query('[name='+name+']', context)[0]; +} function init() { + attachLi = cgi.param('attach_li'); + attachPo = cgi.param('attach_po'); + + itemTypes = pcrud.retrieveAll('aiit'); + + if(cgi.param('create')) { + renderInvoice(); + + } else { + fieldmapper.standardRequest( + ['open-ils.acq', 'open-ils.acq.invoice.retrieve'], + { + params : [openils.User.authtoken, invoiceId], + oncomplete : function(r) { + invoice = openils.Util.readResponse(r); + renderInvoice(); + } + } + ); + } +} + +function renderInvoice() { + + // in create mode, let the LI or PO render the invoice with seed data + if( !(cgi.param('create') && (attachPo || attachLi)) ) { + invoicePane = drawInvoicePane(dojo.byId('acq-view-invoice-div'), invoice); + } + + dojo.byId('acq-invoice-new-item').onclick = function() { + addInvoiceItem(new fieldmapper.acqii()); + } + + addToTotal(0); + + if(invoice) { + dojo.forEach( + invoice.items(), + function(item) { + addInvoiceItem(item); + } + ); + + dojo.forEach( + invoice.entries(), + function(entry) { + addInvoiceEntry(entry); + } + ); + } + + if(attachLi) doAttachLi(); + if(attachPo) doAttachPo(); +} + +function doAttachLi() { + fieldmapper.standardRequest( - ['open-ils.acq', 'open-ils.acq.invoice.retrieve'], - { - params : [openils.User.authtoken, invoiceId], - oncomplete : function(r) { - invoice = openils.Util.readResponse(r); - drawInvoicePane(dojo.byId('acq-view-invoice-div'), invoice); + ["open-ils.acq", "open-ils.acq.lineitem.retrieve"], { + async: true, + params: [openils.User.authtoken, attachLi, { + clear_marc : true, + flesh_attrs : true, + flesh_po : true, + }], + oncomplete: function(r) { + lineitem = openils.Util.readResponse(r); + + if(cgi.param('create')) { + // render the invoice using some seed data from the Lineitem + var invoiceArgs = {provider : lineitem.provider(), shipper : lineitem.provider()}; + invoicePane = drawInvoicePane(dojo.byId('acq-view-invoice-div'), null, invoiceArgs); + } + + var entry = new fieldmapper.acqie(); + entry.isnew(true); + entry.lineitem(lineitem); + addInvoiceEntry(entry); } } ); } +function doAttachPo() { + fieldmapper.standardRequest( + ['open-ils.acq', 'open-ils.acq.purchase_order.retrieve'], + { async: true, + params: [openils.User.authtoken, attachPo, { + flesh_lineitems : true, + clear_marc : true + }], + oncomplete: function(r) { + var po = openils.Util.readResponse(r); + + if(cgi.param('create')) { + // render the invoice using some seed data from the PO + var invoiceArgs = {provider : po.provider(), shipper : po.provider()}; + invoicePane = drawInvoicePane(dojo.byId('acq-view-invoice-div'), null, invoiceArgs); + } + + dojo.forEach(po.lineitems(), + function(lineitem) { + var entry = new fieldmapper.acqie(); + entry.isnew(true); + entry.lineitem(lineitem); + addInvoiceEntry(entry); + } + ); + } + } + ); +} + +function addToTotal(amount) { + + var oldTotal = 0; + if(totalAmountBox) { + oldTotal = totalAmountBox.attr('value'); + } else { + totalAmountBox = new dijit.form.CurrencyTextBox( + {style : 'width: 5em'}, dojo.byId('acq-invoice-total-invoiced')); + } + + totalAmountBox.attr('value', Number(oldTotal + amount)); +} + +function addInvoiceItem(item) { + itemTbody = dojo.byId('acq-invoice-item-tbody'); + if(itemTemplate == null) { + itemTemplate = itemTbody.removeChild(dojo.byId('acq-invoice-item-template')); + } + + var row = itemTemplate.cloneNode(true); + var itemType = itemTypes.filter(function(t) { return (t.code() == item.inv_item_type()) })[0]; + + new dijit.form.TextBox({}, nodeByName('title', row)); + new dijit.form.TextBox({}, nodeByName('author', row)); + new dijit.form.CurrencyTextBox({required : true, style : 'width: 5em'}, nodeByName('cost_billed', row)); + + + var fundDebit = item.fund_debit(); + var fundFilter = {active : 't'}; + if(fundDebit) { + + // If a fund debit exists, this item has been "applied" to the invoice + fundFilter = {'-or' : [{id : fundDebit.fund()}, fundFilter]} + + } else { + + fundDebit = new fieldmapper.acqfdeb(); + //new dijit.form.CheckBox({}, nodeByName('prorate', row)); + } + + var itemType = itemTypes.filter(function(t) { return (t.code() == item.inv_item_type()) })[0]; + + var fundWidget = new openils.widget.AutoFieldWidget({ + fmObject : fundDebit, + fmField : 'fund', + labelFormat : fundLabelFormat, + searchFormat : fundSearchFormat, + searchFilter : fundFilter, + dijitArgs : + (!item.fund_debit() && itemType && openils.Util.isTrue(itemType.prorate())) ? + {disabled : true} : {}, + parentNode : nodeByName('fund', row) + }); + fundWidget.build(); + + + new openils.widget.AutoFieldWidget({ + fmObject : item, + fmField : 'inv_item_type', + parentNode : nodeByName('inv_item_type', row), + dijitArgs : {required : true} + }).build( + function(w, ww) { + // When the inv_item_type is set to prorate=true, don't allow the user the edit the fund + // since this charge will be prorated against (potentially) multiple funds + dojo.connect(w, 'onChange', + function() { + if(!item.fund_debit()) { + var itemType = itemTypes.filter(function(t) { return (t.code() == w.attr('value')) })[0]; + if(openils.Util.isTrue(itemType.prorate())) { + fundWidget.widget.attr('disabled', true); + fundWidget.widget.attr('value', ''); + } else { + fundWidget.widget.attr('disabled', false); + } + } + } + ); + } + ); + + nodeByName('delete', row).onclick = function() { + // TODO: confirm, etc. + itemTbody.removeChild(row); + } + + itemTbody.appendChild(row); +} + +function addInvoiceEntry(entry) { + entryTbody = dojo.byId('acq-invoice-entry-tbody'); + if(entryTemplate == null) { + entryTemplate = entryTbody.removeChild(dojo.byId('acq-invoice-entry-template')); + } + + if(dojo.query('[lineitem=' + entry.lineitem().id() +']', entryTbody)[0]) + // Is it ever valid to have multiple entries for 1 lineitem in a single invoice? + return; + + var row = entryTemplate.cloneNode(true); + row.setAttribute('lineitem', entry.lineitem().id()); + var lineitem = entry.lineitem(); + + var idents = []; + if(liMarcAttr(lineitem, 'isbn')) idents.push(liMarcAttr(lineitem, 'isbn')); + if(liMarcAttr(lineitem, 'upc')) idents.push(liMarcAttr(lineitem, 'upc')); + if(liMarcAttr(lineitem, 'issn')) idents.push(liMarcAttr(lineitem, 'issn')); + + nodeByName('title', row).innerHTML = liMarcAttr(lineitem, 'title'); + nodeByName('author', row).innerHTML = liMarcAttr(lineitem, 'author'); + nodeByName('idents', row).innerHTML = idents.join(','); + + if(entry.purchase_order()) { + openils.Util.show(nodeByName('purchase_order_span', row), 'inline'); + nodeByName('purchase_order', row).innerHTML = entry.purchase_order().name(); + nodeByName('purchase_order', row).onclick = function() { + location.href = oilsBasePath + '/acq/po/view/ ' + entry.purchase_order().id(); + } + } + + new dijit.form.NumberTextBox( + {value : entry.inv_item_count(), required : true, constraints : {min: 0}, style : 'width:5em'}, + nodeByName('inv_item_count', row)); + + new dijit.form.NumberTextBox( + {value : entry.phys_item_count(), required : true, constraints : {min: 0}, style : 'width:5em'}, + nodeByName('phys_item_count', row)); + + new dijit.form.CurrencyTextBox( + {value : entry.cost_billed(), required : true, style : 'width: 5em'}, + nodeByName('cost_billed', row)); + + nodeByName('detach', row).onclick = function() { + // TODO: confirm, etc. + entryTbody.removeChild(row); + } + + entryTbody.appendChild(row); +} + +function liMarcAttr(lineitem, name) { + var attr = lineitem.attributes().filter( + function(attr) { + if( + attr.attr_type() == 'lineitem_marc_attr_definition' && + attr.attr_name() == name) + return attr + } + )[0]; + return (attr) ? attr.attr_value() : ''; +} + + + openils.Util.addOnLoad(init); diff --git a/Open-ILS/web/js/ui/default/acq/po/view_po.js b/Open-ILS/web/js/ui/default/acq/po/view_po.js index f804a31a8d..f4c886fe56 100644 --- a/Open-ILS/web/js/ui/default/acq/po/view_po.js +++ b/Open-ILS/web/js/ui/default/acq/po/view_po.js @@ -287,6 +287,11 @@ function renderPo() { if (PO.lineitem_count() > 1) openils.Util.show("acq-po-split"); } + + dojo.byId('acq-po-create-invoice-link').onclick = + function() { + location.href = oilsBasePath + '/acq/invoice/view?create=1&attach_po=' + poId; + }; } diff --git a/Open-ILS/web/templates/default/acq/invoice/attach.tt2 b/Open-ILS/web/templates/default/acq/invoice/attach.tt2 deleted file mode 100644 index a05ec426a1..0000000000 --- a/Open-ILS/web/templates/default/acq/invoice/attach.tt2 +++ /dev/null @@ -1,31 +0,0 @@ -[% WRAPPER 'default/base.tt2' %] -[% ctx.page_title = 'Attach Invoice Entry' %] - - - -
- -
-
Attach Invoice Entry
-
-
- -
-
- -
- This will create a new invoice. To link this item to an existing invoice, - click here. -
- -
- - -
-
- -
- -
-
-[% END %] diff --git a/Open-ILS/web/templates/default/acq/invoice/view.tt2 b/Open-ILS/web/templates/default/acq/invoice/view.tt2 index cd883046c5..4180bd9e94 100644 --- a/Open-ILS/web/templates/default/acq/invoice/view.tt2 +++ b/Open-ILS/web/templates/default/acq/invoice/view.tt2 @@ -1,5 +1,5 @@ [% WRAPPER 'default/base.tt2' %] -[% ctx.page_title = 'Invoice' %] +[% ctx.page_title = 'Invoicing' %] @@ -14,5 +14,99 @@
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bibliographic Items

+
ISBN/UPC/ISSNTitleAuthor# Items Invoiced / # ReceivedAmount BilledDetach
+ + +
+  /  +
Detach
+

Taxes, Fees, Misc.

+
Charge TypeTitle / Description (optional)Author (optional)FundAmount BilledDelete
Delete
+ Add Invoice Item... +
+

+
+ Total Amount
+ + +
+
+
[% END %] diff --git a/Open-ILS/web/templates/default/acq/po/view.tt2 b/Open-ILS/web/templates/default/acq/po/view.tt2 index aae3b53740..67ae8827bf 100644 --- a/Open-ILS/web/templates/default/acq/po/view.tt2 +++ b/Open-ILS/web/templates/default/acq/po/view.tt2 @@ -50,10 +50,12 @@ - - Invoice(s) + + Invoicing - (0) + View Invoices(0) / + Create Invoice / + Link Invoice -- 2.11.0