1 dojo.require('dojo.date.locale');
2 dojo.require('dojo.date.stamp');
3 dojo.require('dijit.form.CheckBox');
4 dojo.require('dijit.form.CurrencyTextBox');
5 dojo.require('dijit.form.NumberTextBox');
6 dojo.require('openils.User');
7 dojo.require('openils.Util');
8 dojo.require('openils.CGI');
9 dojo.require('openils.PermaCrud');
10 dojo.require('openils.widget.EditPane');
11 dojo.require('openils.widget.AutoFieldWidget');
12 dojo.require('openils.widget.ProgressDialog');
14 dojo.requireLocalization('openils.acq', 'acq');
15 var localeStrings = dojo.i18n.getLocalization('openils.acq', 'acq');
17 var fundLabelFormat = ['${0} (${1})', 'code', 'year'];
18 var fundSearchFormat = ['${0} (${1})', 'code', 'year'];
20 var cgi = new openils.CGI();
21 var pcrud = new openils.PermaCrud();
32 var widgetRegistry = {acqie : {}, acqii : {}};
34 function nodeByName(name, context) {
35 return dojo.query('[name='+name+']', context)[0];
40 attachLi = cgi.param('attach_li');
41 attachPo = cgi.param('attach_po');
43 itemTypes = pcrud.retrieveAll('aiit');
45 if(cgi.param('create')) {
49 fieldmapper.standardRequest(
50 ['open-ils.acq', 'open-ils.acq.invoice.retrieve'],
52 params : [openils.User.authtoken, invoiceId],
53 oncomplete : function(r) {
54 invoice = openils.Util.readResponse(r);
62 function renderInvoice() {
64 // in create mode, let the LI or PO render the invoice with seed data
65 if( !(cgi.param('create') && (attachPo || attachLi)) ) {
66 invoicePane = drawInvoicePane(dojo.byId('acq-view-invoice-div'), invoice);
69 dojo.byId('acq-invoice-new-item').onclick = function() {
70 var item = new fieldmapper.acqii();
89 addInvoiceEntry(entry);
94 if(attachLi) doAttachLi();
95 if(attachPo) doAttachPo();
98 function doAttachLi() {
100 fieldmapper.standardRequest(
101 ["open-ils.acq", "open-ils.acq.lineitem.retrieve"], {
103 params: [openils.User.authtoken, attachLi, {
107 flesh_li_details : true,
108 flesh_fund_debit : true
110 oncomplete: function(r) {
111 lineitem = openils.Util.readResponse(r);
113 if(cgi.param('create')) {
114 // render the invoice using some seed data from the Lineitem
115 var invoiceArgs = {provider : lineitem.provider(), shipper : lineitem.provider()};
116 invoicePane = drawInvoicePane(dojo.byId('acq-view-invoice-div'), null, invoiceArgs);
119 var entry = new fieldmapper.acqie();
120 entry.id(virtualId--);
122 entry.lineitem(lineitem);
123 entry.purchase_order(lineitem.purchase_order());
124 addInvoiceEntry(entry);
130 function doAttachPo() {
131 fieldmapper.standardRequest(
132 ['open-ils.acq', 'open-ils.acq.purchase_order.retrieve'],
134 params: [openils.User.authtoken, attachPo, {
135 flesh_lineitems : true,
137 flesh_lineitem_details : true,
138 flesh_fund_debit : true
140 oncomplete: function(r) {
141 var po = openils.Util.readResponse(r);
143 if(cgi.param('create')) {
144 // render the invoice using some seed data from the PO
145 var invoiceArgs = {provider : po.provider(), shipper : po.provider()};
146 invoicePane = drawInvoicePane(dojo.byId('acq-view-invoice-div'), null, invoiceArgs);
149 dojo.forEach(po.lineitems(),
151 var entry = new fieldmapper.acqie();
152 entry.id(virtualId--);
154 entry.lineitem(lineitem);
155 entry.purchase_order(po);
156 lineitem.purchase_order(po);
157 addInvoiceEntry(entry);
165 function updateTotalCost() {
167 if(!totalAmountBox) {
168 totalAmountBox = new dijit.form.CurrencyTextBox(
169 {style : 'width: 5em'}, dojo.byId('acq-invoice-total-invoiced'));
171 for(var id in widgetRegistry.acqii)
172 if(!widgetRegistry.acqii[id]._object.isdeleted())
173 total += widgetRegistry.acqii[id].cost_billed.getFormattedValue();
174 for(var id in widgetRegistry.acqie)
175 if(!widgetRegistry.acqie[id]._object.isdeleted())
176 total += widgetRegistry.acqie[id].cost_billed.getFormattedValue();
177 totalAmountBox.attr('value', total);
181 function registerWidget(obj, field, widget, callback) {
182 var blob = widgetRegistry[obj.classname];
184 blob[obj.id()] = {_object : obj};
185 blob[obj.id()][field] = widget;
188 dojo.connect(w, 'onChange',
194 if(callback) callback(w, ww);
200 function addInvoiceItem(item) {
201 itemTbody = dojo.byId('acq-invoice-item-tbody');
202 if(itemTemplate == null) {
203 itemTemplate = itemTbody.removeChild(dojo.byId('acq-invoice-item-template'));
206 var row = itemTemplate.cloneNode(true);
207 var itemType = itemTypes.filter(function(t) { return (t.code() == item.inv_item_type()) })[0];
210 ['title', 'author', 'cost_billed'],
215 new openils.widget.AutoFieldWidget({
219 dijitArgs : (field == 'cost_billed') ? {required : true, style : 'width: 5em'} : null,
220 parentNode : nodeByName(field, row)
227 /* ----------- fund -------------- */
228 var itemType = itemTypes.filter(function(t) { return (t.code() == item.inv_item_type()) })[0];
234 labelFormat : fundLabelFormat,
235 searchFormat : fundSearchFormat,
236 parentNode : nodeByName('fund', row)
239 if(item.fund_debit()) {
240 fundArgs.readOnly = true;
242 fundArgs.searchFilter = {active : 't'}
243 if(itemType && openils.Util.isTrue(itemType.prorate()))
244 fundArgs.disabled = true;
247 var fundWidget = new openils.widget.AutoFieldWidget(fundArgs);
248 registerWidget(item, 'fund', fundWidget);
250 /* ---------- inv_item_type ------------- */
255 new openils.widget.AutoFieldWidget({
257 fmField : 'inv_item_type',
258 parentNode : nodeByName('inv_item_type', row),
259 dijitArgs : {required : true}
262 // When the inv_item_type is set to prorate=true, don't allow the user the edit the fund
263 // since this charge will be prorated against (potentially) multiple funds
264 dojo.connect(w, 'onChange',
266 if(!item.fund_debit()) {
267 var itemType = itemTypes.filter(function(t) { return (t.code() == w.attr('value')) })[0];
268 if(!itemType) return;
269 if(openils.Util.isTrue(itemType.prorate())) {
270 fundWidget.widget.attr('disabled', true);
271 fundWidget.widget.attr('value', '');
273 fundWidget.widget.attr('disabled', false);
281 nodeByName('delete', row).onclick = function() {
282 var cost = widgetRegistry.acqii[item.id()].cost_billed.getFormattedValue();
283 var msg = dojo.string.substitute(
284 localeStrings.INVOICE_CONFIRM_ITEM_DELETE, [
286 widgetRegistry.acqii[item.id()].inv_item_type.getFormattedValue()
289 if(!confirm(msg)) return;
290 itemTbody.removeChild(row);
291 item.isdeleted(true);
293 delete widgetRegistry.acqii[item.id()];
297 itemTbody.appendChild(row);
301 function addInvoiceEntry(entry) {
302 entryTbody = dojo.byId('acq-invoice-entry-tbody');
303 if(entryTemplate == null) {
304 entryTemplate = entryTbody.removeChild(dojo.byId('acq-invoice-entry-template'));
307 if(dojo.query('[lineitem=' + entry.lineitem().id() +']', entryTbody)[0])
308 // Is it ever valid to have multiple entries for 1 lineitem in a single invoice?
311 var row = entryTemplate.cloneNode(true);
312 row.setAttribute('lineitem', entry.lineitem().id());
313 var lineitem = entry.lineitem();
316 if(liMarcAttr(lineitem, 'isbn')) idents.push(liMarcAttr(lineitem, 'isbn'));
317 if(liMarcAttr(lineitem, 'upc')) idents.push(liMarcAttr(lineitem, 'upc'));
318 if(liMarcAttr(lineitem, 'issn')) idents.push(liMarcAttr(lineitem, 'issn'));
320 var lids = lineitem.lineitem_details();
321 var numOrdered = lids.length;
322 var numReceived = lids.filter(function(lid) { return (lid.recv_time() != null) }).length;
323 var numInvoiced = lids.filter(function(lid) { return !openils.Util.isTrue(lid.fund_debit().encumbrance()) }).length;
327 var po = entry.purchase_order();
333 nodeByName('title_details', row).innerHTML =
334 dojo.string.substitute(
335 localeStrings.INVOICE_TITLE_DETAILS, [
336 liMarcAttr(lineitem, 'title'),
337 liMarcAttr(lineitem, 'author'),
341 Number(lineitem.estimated_unit_price()).toFixed(2),
342 (Number(lineitem.estimated_unit_price()) * numOrdered).toFixed(2),
353 ['inv_item_count', 'phys_item_count', 'cost_billed'],
355 var dijitArgs = {required : true, constraints : {min: 0}, style : 'width:5em'};
356 if(entry.isnew() && field == 'phys_item_count') dijitArgs.value = numReceived;
360 new openils.widget.AutoFieldWidget({
364 dijitArgs : dijitArgs,
365 parentNode : nodeByName(field, row)
371 nodeByName('detach', row).onclick = function() {
372 var cost = widgetRegistry.acqie[entry.id()].cost_billed.getFormattedValue();
373 var msg = dojo.string.substitute(
374 localeStrings.INVOICE_CONFIRM_ENTRY_DETACH, [
376 liMarcAttr(lineitem, 'title'),
377 liMarcAttr(lineitem, 'author'),
381 if(!confirm(msg)) return;
382 entryTbody.removeChild(row);
383 entry.isdeleted(true);
385 delete widgetRegistry.acqie[entry.id()];
389 entryTbody.appendChild(row);
393 function liMarcAttr(lineitem, name) {
394 var attr = lineitem.attributes().filter(
397 attr.attr_type() == 'lineitem_marc_attr_definition' &&
398 attr.attr_name() == name)
402 return (attr) ? attr.attr_value() : '';
405 function saveChanges() {
407 progressDialog.show(true);
409 var updateItems = [];
410 for(var id in widgetRegistry.acqii) {
411 var reg = widgetRegistry.acqii[id];
412 var item = reg._object;
413 if(item.ischanged() || item.isnew() || item.isdeleted()) {
414 updateItems.push(item);
415 if(item.isnew()) item.id(null);
416 for(var field in reg) {
417 if(field != '_object')
418 item[field]( reg[field].getFormattedValue() );
422 if(item.purchase_order() != null && typeof item.purchase_order() == 'object')
423 item.purchase_order( item.purchase_order().id() );
427 var updateEntries = [];
428 for(var id in widgetRegistry.acqie) {
429 var reg = widgetRegistry.acqie[id];
430 var entry = reg._object;
431 if(entry.ischanged() || entry.isnew() || entry.isdeleted()) {
432 entry.lineitem(entry.lineitem().id());
433 entry.purchase_order(entry.purchase_order().id());
434 updateEntries.push(entry);
435 if(entry.isnew()) entry.id(null);
437 for(var field in reg) {
438 if(field != '_object')
439 entry[field]( reg[field].getFormattedValue() );
443 dojo.forEach(['purchase_order', 'lineitem'],
445 if(entry[field]() != null && typeof entry[field]() == 'object')
446 entry[field]( entry[field]().id() );
453 invoice = new fieldmapper.acqinv();
456 invoice.ischanged(true); // for now, just always update
459 dojo.forEach(invoicePane.fieldList,
461 invoice[field.name]( field.widget.getFormattedValue() );
465 fieldmapper.standardRequest(
466 ['open-ils.acq', 'open-ils.acq.invoice.update'],
468 params : [openils.User.authtoken, invoice, updateEntries, updateItems],
469 oncomplete : function(r) {
470 progressDialog.hide();
471 var invoice = openils.Util.readResponse(r);
473 location.href = oilsBasePath + '/acq/invoice/view/' + invoice.id();
480 function processInvoice() {
481 progressDialog.show(true);
483 fieldmapper.standardRequest(
484 ['open-ils.acq', 'open-ils.acq.invoice.process'],
486 params : [openils.User.authtoken, invoice.id()],
487 oncomplete : function(r) {
488 progressDialog.hide();
489 var invoice = openils.Util.readResponse(r);
491 location.href = oilsBasePath + '/acq/invoice/view/' + invoice.id();
501 openils.Util.addOnLoad(init);