dojo.require('dijit.form.TextBox');
dojo.require('dijit.form.FilteringSelect');
dojo.require('dijit.form.Textarea');
+dojo.require('dijit.Tooltip');
dojo.require('dijit.ProgressBar');
-dojo.require('openils.User');
-dojo.require('openils.Util');
dojo.require('openils.acq.Lineitem');
dojo.require('openils.acq.PO');
dojo.require('openils.acq.Picklist');
dojo.require('dojo.data.ItemFileReadStore');
dojo.require('openils.widget.ProgressDialog');
dojo.require('openils.PermaCrud');
-dojo.require('openils.XUL');
+dojo.require("openils.widget.PCrudAutocompleteBox");
+dojo.require('openils.CGI');
-dojo.requireLocalization('openils.acq', 'acq');
-var localeStrings = dojo.i18n.getLocalization('openils.acq', 'acq');
+if (!localeStrings) { /* we can do this because javascript doesn't have block scope */
+ dojo.requireLocalization('openils.acq', 'acq');
+ var localeStrings = dojo.i18n.getLocalization('openils.acq', 'acq');
+}
const XUL_OPAC_WRAPPER = 'chrome://open_ils_staff_client/content/cat/opac.xul';
var li_exportable_attrs = ["issn", "isbn", "upc"];
+var fundLabelFormat = [
+ '<span class="fund_${0}">${1} (${2})</span>', 'id', 'code', 'year'
+];
+var fundSearchFormat = ['${0} (${1})', 'code', 'year'];
+
function nodeByName(name, context) {
return dojo.query('[name='+name+']', context)[0];
}
+// for caching linked users. e.g. lineitem_detail.receiver
+var userCache = {};
var liDetailBatchFields = ['fund', 'owning_lib', 'location', 'collection_code', 'circ_modifier', 'cn_label'];
var liDetailFields = liDetailBatchFields.concat(['barcode', 'note']);
+var fundStyles = {
+ "stop": "color: #c00; font-weight: bold;",
+ "warning": "color: #c93;"
+};
function AcqLiTable() {
this.liCache = {};
this.plCache = {};
this.poCache = {};
- this.dfaCache = {};
+ this.relCache = {};
+ this.haveFundClass = {}
+ this.fundBalanceState = {};
+ this.realDfaCache = {};
+ this.virtDfaCounts = {};
+ this.virtDfaId = -1;
this.dfeOffset = 0;
+ this.claimEligibleLidByLi = {};
+ this.claimEligibleLid = {};
this.toggleState = false;
this.tbody = dojo.byId('acq-lit-tbody');
this.selectors = [];
this.noteAcks = {};
this.authtoken = openils.User.authtoken;
+ this.pcrud = new openils.PermaCrud();
this.rowTemplate = this.tbody.removeChild(dojo.byId('acq-lit-row'));
this.copyTbody = dojo.byId('acq-lit-li-details-tbody');
this.copyRow = this.copyTbody.removeChild(dojo.byId('acq-lit-li-details-row'));
this.realCopiesTbody = dojo.byId('acq-lit-real-copies-tbody');
this.realCopiesRow = this.realCopiesTbody.removeChild(dojo.byId('acq-lit-real-copies-row'));
this._copy_fields_for_acqdf = ['owning_lib', 'location'];
+ this.skipInitialEligibilityCheck = false;
+ this.claimDialog = new ClaimDialogManager(
+ liClaimDialog, finalClaimDialog, this.claimEligibleLidByLi,
+ function(li) { /* callback that fires when claims are made */
+ self.fetchClaimInfo(li.id(), /* force update */ true);
+ }
+ );
+ this.vlAgent = new VLAgent();
- dojo.connect(acqLitLiActionsSelector, 'onChange',
- function() {
- self.applySelectedLiAction(this.attr('value'))
- acqLitLiActionsSelector.attr('value', '_');
- });
+ this.focusLineitem = new openils.CGI().param('focus_li');
+
+ dojo.byId("acq-lit-li-actions-selector").onchange = function() {
+ self.applySelectedLiAction(this.options[this.selectedIndex].value);
+ this.selectedIndex = 0;
+ };
acqLitCreatePoSubmit.onClick = function() {
- acqLitPoCreateDialog.hide();
- self._createPO(acqLitPoCreateDialog.getValues());
+ if (!self.createPoProviderSelector.attr("value") ||
+ !self.createPoAgencySelector.attr("value")) {
+ alert(localeStrings.CREATE_PO_INVALID);
+ return false;
+ } else if (self._confirmPoPrepaySituation()) {
+ acqLitPoCreateDialog.hide();
+ self._createPO(acqLitPoCreateDialog.getValues());
+ } else {
+ return false;
+ }
}
acqLitSavePlButton.onClick = function() {
}
- //dojo.byId('acq-lit-notes-new-button').onclick = function(){acqLitCreateLiNoteDialog.show();}
-
dojo.byId('acq-lit-select-toggle').onclick = function(){self.toggleSelect()};
dojo.byId('acq-lit-info-back-button').onclick = function(){self.show('list')};
dojo.byId('acq-lit-copies-back-button').onclick = function(){self.show('list')};
dojo.byId('acq-lit-notes-back-button').onclick = function(){self.show('list')};
dojo.byId('acq-lit-real-copies-back-button').onclick = function(){self.show('list')};
- this.reset = function() {
+ this.reset = function(keep_selectors) {
while(self.tbody.childNodes[0])
self.tbody.removeChild(self.tbody.childNodes[0]);
- self.selectors = [];
self.noteAcks = {};
+ self.relCache = {};
+
+ if (!keep_selectors)
+ self.selectors = [];
};
this.setNext = function(handler) {
}
};
+ /*
+ * Ensures this.focusLineitem is in view and causes a brief
+ * border around the lineitem to come to life then fade.
+ */
+ this.focusLi = function() {
+ if (!this.focusLineitem) return;
+
+ // set during addLineitem()
+ var node = dojo.byId('li-title-ref-' + this.focusLineitem);
+
+ // LI may not yet be rendered
+ if (!node) return;
+
+ // prevent numerous re-focuses
+ this.focusLineitem = null;
+
+ // causes the full row to be visible
+ dijit.scrollIntoView(node);
+
+ // may as well..
+ dojo.query('[attr=title]', node)[0].focus();
+
+ dojo.require('dojox.fx');
+
+ setTimeout(
+ function() {
+ dojox.fx.highlight({color : '#BB4433', node : node, duration : 2000}).play();
+ },
+ 100);
+ };
+
this.show = function(div) {
openils.Util.hide('acq-lit-table-div');
openils.Util.hide('acq-lit-info-div');
openils.Util.hide('acq-lit-li-details');
openils.Util.hide('acq-lit-notes-div');
openils.Util.hide('acq-lit-real-copies-div');
+ openils.Util.hide('acq-lit-asset-creator');
switch(div) {
case 'list':
openils.Util.show('acq-lit-table-div');
+ this.focusLi();
break;
case 'info':
openils.Util.show('acq-lit-info-div');
case 'notes':
openils.Util.show('acq-lit-notes-div');
break;
+ case 'asset-creator':
+ openils.Util.show('acq-lit-asset-creator');
+ break;
default:
if(div)
openils.Util.show(div);
};
+ this.getAll = function(callback, id_only) {
+ /* For some uses of the li table, we may not really know about "all"
+ * the lineitems that the user thinks we know about. If we're a paged
+ * picklist, for example, we only know about the lineitems we've
+ * displayed, but not necessarily all the lineitems on the picklist.
+ * So we reach out to pcrud to inform us.
+ */
+
+ var oncomplete = function(r) {
+ var id_list = openils.Util.readResponse(r);
+ if (id_only)
+ callback(id_list);
+ else
+ self.fetchLineitemsById(id_list, callback);
+ };
+
+ if (this.isPL) {
+ this.pcrud.search(
+ "jub", {"picklist": this.isPL}, {
+ "id_list": true, /* sic, even if id_only */
+ "async": true,
+ "oncomplete": oncomplete
+ }
+ );
+ return;
+ } else if (this.isPO) {
+ this.pcrud.search(
+ "jub", {"purchase_order": this.isPO}, {
+ "id_list": true,
+ "async": true,
+ "oncomplete": oncomplete
+ }
+ );
+ return;
+ } else if (this.isUni && this.pager) {
+ this.pager.getAllLineitemIDs(oncomplete);
+ return;
+ }
+
+ /* If execution reaches this point, we don't need or can't perform
+ * any special tricks to find out the "real" list of "all" lineitems
+ * in this context, so we fall back to the old method.
+ */
+ callback(this.getSelected(true, null, id_only));
+ };
+
/** @param all If true, assume all are selected */
- this.getSelected = function(all) {
- var selected = [];
- dojo.forEach(self.selectors,
+ this.getSelected = function(
+ all,
+ callback /* If you want a "good" idea of "all" lineitems, you must
+ provide a callback that accepts an array parameter, rather than
+ relying on the return value of this method itself. */,
+ id_only
+ ) {
+ if (all && callback)
+ return this.getAll(callback, id_only);
+
+ var indices = {}; /* use to uniqify. needed in paging situations. */
+ dojo.forEach(this.selectors,
function(i) {
if(i.checked || all)
- selected.push(self.liCache[i.parentNode.parentNode.getAttribute('li')]);
+ indices[i.parentNode.parentNode.getAttribute('li')] = true;
}
);
- return selected;
+
+ var result = openils.Util.objectProperties(indices);
+
+ if (!id_only)
+ result = result.map(function(liId) { return self.liCache[liId]; });
+
+ if (callback)
+ callback(result);
+ else
+ return result;
};
this.setRowAttr = function(td, liWrapper, field, type) {
td.appendChild(document.createTextNode(val));
};
+ this.setClaimPolicyControl = function(li, row) {
+ if (!self.claimPolicyPicker) {
+ self.claimPolicyPicker = true; /* prevents a race condition */
+ new openils.widget.AutoFieldWidget({
+ "parentNode": "acq-lit-li-claim-policy",
+ "fmClass": "acqclp",
+ "selfReference": true,
+ "dijitArgs": {"required": true}
+ }).build(function(w) { self.claimPolicyPicker = w; });
+ }
+
+ if (!row) row = this._findLiRow(li);
+
+ var actViewPolicy = nodeByName("action_view_claim_policy", row);
+ if (li.claim_policy())
+ actViewPolicy.innerHTML = localeStrings.CHANGE_CLAIM_POLICY;
+
+ if (!actViewPolicy.onclick) {
+ actViewPolicy.onclick = function() {
+ if (li.claim_policy())
+ self.claimPolicyPicker.attr("value", li.claim_policy());
+ liClaimPolicyDialog.show();
+ liClaimPolicySave.onClick = function() {
+ self.changeClaimPolicy(
+ [li], self.claimPolicyPicker.attr("value"),
+ function() {
+ self.setClaimPolicyControl(li, row);
+ self.reconsiderClaimControl(li, row);
+ liClaimPolicyDialog.hide();
+ }
+ );
+ }
+ };
+ }
+ };
+
+ this.fetchClaimInfo = function(liId, force, callback, row) {
+ this._fetchLineitem(
+ liId, function(full) {
+ self.liCache[full.id()] = full;
+ self.checkClaimEligibility(full, callback, row);
+ }, force
+ );
+ }
+
/**
* Inserts a single lineitem into the growing table of lineitems
* @param {Object} li The lineitem object to insert
this.addLineitem = function(li, skip_final_placement) {
this.liCache[li.id()] = li;
+ // insert the row right away so that final order isn't
+ // dependent on how long subsequent async request take
+ // for a given line item
+ var row = self.rowTemplate.cloneNode(true);
+ if (!skip_final_placement) {
+ self.tbody.appendChild(row);
+ }
+ self.selectors.push(dojo.query('[name=selectbox]', row)[0]);
+
// sort the lineitem notes on edit_time
if(!li.lineitem_notes()) li.lineitem_notes([]);
var liWrapper = new openils.acq.Lineitem({lineitem:li});
- var row = self.rowTemplate.cloneNode(true);
row.setAttribute('li', li.id());
var tds = dojo.query('[attr]', row);
dojo.forEach(tds, function(td) {self.setRowAttr(td, liWrapper, td.getAttribute('attr'), td.getAttribute('attr_type'));});
dojo.query('[name=source_label]', row)[0].appendChild(document.createTextNode(li.source_label()));
- var isbn = liWrapper.findAttr('isbn', 'lineitem_marc_attr_definition');
- if(isbn) {
- // XXX media prefix for added content
- dojo.query('[name=jacket]', row)[0].setAttribute('src', '/opac/extras/ac/jacket/small/' + isbn);
+ // so we can scroll to it later
+ dojo.query('[name=bib-info-cell]', row)[0].id = 'li-title-ref-' + li.id();
+
+ var identifier =
+ liWrapper.findAttr("isbn", "lineitem_marc_attr_definition") ||
+ liWrapper.findAttr("upc", "lineitem_marc_attr_definition");
+
+ // XXX media prefix for added content
+ if (identifier) {
+ nodeByName("jacket", row).setAttribute(
+ "src", "/opac/extras/ac/jacket/small/" + identifier
+ );
+ }
+
+ nodeByName("liid", row).innerHTML += li.id();
+
+ if(li.eg_bib_id()) {
+ openils.Util.show(nodeByName('catalog', row), 'inline');
+ nodeByName("catalog_link", row).onclick = this.generateMakeRecTab(li.eg_bib_id());
+ } else {
+ openils.Util.show(nodeByName('link_to_catalog', row), 'inline');
+ nodeByName("link_to_catalog_link", row).onclick = function() { self.drawBibFinder(li) };
+ }
+
+ if (li.queued_record()) {
+ this.pcrud.retrieve('vqbr', li.queued_record(),
+ { async : true,
+ oncomplete : function(r) {
+ var qrec = openils.Util.readResponse(r);
+ openils.Util.show(nodeByName('queue', row), 'inline');
+ var link = nodeByName("queue_link", row);
+ link.onclick = function() {
+ // open a new tab to the vandelay queue for this record
+ openils.XUL.newTabEasy(
+ oilsBasePath + '/vandelay/vandelay?qtype=bib&qid=' + qrec.queue()
+ );
+ }
+ }
+ }
+ );
}
+ nodeByName("worksheet_link", row).href =
+ oilsBasePath + "/acq/lineitem/worksheet/" + li.id() +
+ '?source=' + encodeURIComponent(location.pathname + location.search)
+
+ nodeByName("show_requests_link", row).href =
+ oilsBasePath + "/acq/picklist/user_request?lineitem=" + li.id() +
+ '?source=' + encodeURIComponent(location.pathname + location.search)
+
dojo.query('[attr=title]', row)[0].onclick = function() {self.drawInfo(li.id())};
dojo.query('[name=copieslink]', row)[0].onclick = function() {self.drawCopies(li.id())};
- dojo.query('[name=notes_count]', row)[0].innerHTML = li.lineitem_notes().length;
dojo.query('[name=noteslink]', row)[0].onclick = function() {self.drawLiNotes(li)};
+ if (!this.skipInitialEligibilityCheck)
+ this.fetchClaimInfo(
+ li.id(),
+ false,
+ function(full) { self.setClaimPolicyControl(full, row) },
+ row
+ );
+
+ this.updateLiNotesCount(li, row);
+
// show which PO this lineitem is a member of
if(li.purchase_order() && !this.isPO) {
var po =
{params: [
this.authtoken, li.purchase_order(), {
"flesh_price_summary": true,
+ "flesh_provider" : true,
"flesh_lineitem_count": true
}
]});
if(po && !this.isMeta) {
openils.Util.show(nodeByName('po', row), 'inline');
var link = nodeByName('po_link', row);
- link.setAttribute('href', oilsBasePath + '/acq/po/view/' + li.purchase_order());
- link.innerHTML = 'PO: ' + po.name(); // TODO i18n
+ link.setAttribute('href', oilsBasePath +
+ '/acq/po/view/' + li.purchase_order() +
+ '?focus_li=' + li.id() +
+ '&source=' + encodeURIComponent(location.pathname + location.search)
+ );
+ link.innerHTML += po.name();
+
+ openils.Util.show(nodeByName('pro', row), 'inline');
+ link = nodeByName('pro_link', row);
+ link.setAttribute('href', oilsBasePath + '/conify/global/acq/provider/' + po.provider().id())
+ link.innerHTML += po.provider().code();
}
}
// show which picklist this lineitem is a member of
- if(li.picklist() && (this.isPO || this.isMeta)) {
+ if(li.picklist() && (this.isPO || this.isMeta || this.isUni)) {
var pl =
this.plCache[li.picklist()] =
this.plCache[li.picklist()] ||
fieldmapper.standardRequest(
- ['open-ils.acq', 'open-ils.acq.picklist.retrieve'],
+ ['open-ils.acq', 'open-ils.acq.picklist.retrieve.authoritative'],
{params: [this.authtoken, li.picklist()]});
- if(pl) {
- openils.Util.show(nodeByName('pl', row), 'inline');
- var link = nodeByName('pl_link', row);
- link.setAttribute('href', oilsBasePath + '/acq/picklist/view/' + li.picklist());
- link.innerHTML = 'PL: '+pl.name(); // TODO i18n
+ if (pl) {
+ if (pl.name() == "") {
+ openils.Util.show(nodeByName("bib_origin", row), "inline");
+
+ } else {
+
+ openils.Util.show(nodeByName('pl', row), 'inline');
+ var link = nodeByName('pl_link', row);
+ link.setAttribute('href', oilsBasePath +
+ '/acq/picklist/view/' + li.picklist() +
+ '?focus_li=' + li.id() +
+ '&source=' + encodeURIComponent(location.pathname + location.search)
+ );
+ link.innerHTML += pl.name();
+ }
}
}
countNode.innerHTML = count;
countNode.id = 'acq-lit-copy-count-label-' + li.id();
- // lineitem state
- nodeByName('li_state', row).innerHTML = li.state(); // TODO i18n state labels
// lineitem price
var priceInput = dojo.query('[name=price]', row)[0];
- var priceData = liWrapper.getPrice();
- priceInput.value = (priceData) ? priceData.price : '';
+ priceInput.value = li.estimated_unit_price() || '';
priceInput.onchange = function() { self.updateLiPrice(priceInput, li) };
// show either "mark received" or "unreceive" as appropriate
- this.updateLiReceivedness(li, row);
+ this.updateLiState(li, row);
- if (!skip_final_placement) {
- self.tbody.appendChild(row);
- self.selectors.push(dojo.query('[name=selectbox]', row)[0]);
- } else {
+ if (skip_final_placement) {
return row;
}
+
+ // the last LI may be rendered after the call to show('list'),
+ // so make sure it's focused if necessary.
+ if (this.focusLineitem == li.id())
+ this.focusLi();
+ };
+
+ this._liCountClaims = function(li) {
+ var total = 0;
+ for (var i = 0; i < li.lineitem_details().length; i++)
+ total += li.lineitem_details()[i].claims().length;
+ return total;
+ };
+
+ this._findLiRow = function(li) {
+ return dojo.query('tr[li="' + li.id() + '"]', "acq-lit-tbody")[0];
+ };
+
+ this.reconsiderClaimControl = function(li, row) {
+ if (!row) row = this._findLiRow(li);
+ var option = nodeByName("action_manage_claims", row);
+ var eligible = this.claimEligibleLidByLi[li.id()].length;
+ var count = this._liCountClaims(li);
+
+ option.disabled = !(count || eligible);
+ option.innerHTML =
+ dojo.string.substitute(localeStrings.NUM_CLAIMS_EXISTING, [count]);
+ option.onclick = function() { self.claimDialog.show(li); };
+ };
+
+ this.clearEligibility = function(li) {
+ this.claimEligibleLidByLi[li.id()] = [];
+
+ if (li.lineitem_details()) {
+ li.lineitem_details().forEach(
+ function(lid) { delete self.claimEligibleLid[lid.id()]; }
+ );
+ }
+
+ if (this.copyCache) {
+ var to_del = [];
+ for (var k in this.copyCache) {
+ if (this.copyCache[k].lineitem() == li.id())
+ to_del.push(k);
+ }
+ to_del.forEach(
+ function(k) { delete self.claimEligibleLid[k]; }
+ );
+ }
+ };
+
+ this.checkClaimEligibility = function(li, callback, row) {
+ /* Assume always eligible, i.e. from this interface we don't care about
+ * claim eligibility any more. this is where the user would force a
+ * claime. */
+ this.clearEligibility(li);
+ this.claimEligibleLidByLi[li.id()] = li.lineitem_details().map(
+ function(lid) { return lid.id(); }
+ );
+ li.lineitem_details().forEach(
+ function(lid) { self.claimEligibleLid[lid.id()] = true; }
+ );
+ this.reconsiderClaimControl(li, row);
+ if (callback) callback(li);
+ /*
+ this.clearEligibility(li);
+ fieldmapper.standardRequest(
+ ["open-ils.acq", "open-ils.acq.claim.eligible.lineitem_detail"], {
+ "params": [openils.User.authtoken, {"lineitem": li.id()}],
+ "async": true,
+ "onresponse": function(r) {
+ if (r = openils.Util.readResponse(r)) {
+ self.claimEligibleLidByLi[li.id()].push(
+ r.lineitem_detail()
+ );
+ self.claimEligibleLid[r.lineitem_detail()] = true;
+ }
+ },
+ "oncomplete": function() {
+ self.reconsiderClaimControl(li, row);
+ if (typeof(callback) == "function")
+ callback();
+ }
+ }
+ );
+ */
};
- this.updateLiReceivedness = function(li, row) {
- if (typeof(row) == "undefined")
- row = dojo.query('tr[li="' + li.id() + '"]', "acq-lit-tbody")[0];
+ this.updateLiNotesCount = function(li, row) {
+ if (!row) row = this._findLiRow(li);
- var recv_link = nodeByName("receive_link", row);
- var unrecv_link = nodeByName("unreceive_link", row);
- var real_copies_link = nodeByName("real_copies_link", row);
+ var has_notes = (li.lineitem_notes().filter(
+ function(o) { return Boolean (o.alert_text()); }
+ ).length > 0);
+
+ /* U+2691 is the code point for a filled-in flag character */
+ nodeByName("notes_alert_flag", row).innerHTML =
+ has_notes ? "⚑" : "";
+ nodeByName("noteslink", row).style.fontStyle =
+ has_notes ? "italic" : "normal";
+ nodeByName("notes_count", row).innerHTML = li.lineitem_notes().length;
+ };
+
+ /* XXX NOT related to _updateLiState(). rethink */
+ this.updateLiState = function(li, row) {
+ if (!row) row = this._findLiRow(li);
+
+ var actReceive = nodeByName("action_mark_recv", row);
+ var actUnRecv = nodeByName("action_mark_unrecv", row);
+ var actUpdateBarcodes = nodeByName("action_update_barcodes", row);
+ var actHoldingsMaint = nodeByName("action_holdings_maint", row);
+ var actNewInvoice = nodeByName('action_new_invoice', row);
+ var actLinkInvoice = nodeByName('action_link_invoice', row);
+ var actViewInvoice = nodeByName('action_view_invoice', row);
+
+ // always allow access to LI history
+ nodeByName('action_view_history', row).onclick =
+ function() { location.href = oilsBasePath + '/acq/lineitem/history/' + li.id(); };
/* handle row coloring for based on LI state */
openils.Util.removeCSSClass(row, /^oils-acq-li-state-/);
openils.Util.addCSSClass(row, "oils-acq-li-state-" + li.state());
- /* handle links that appear/disappear based on whether LI is received */
- if (this.isPO) {
- var self = this;
- switch(li.state()) {
- case "on-order":
- openils.Util.hide(real_copies_link);
- openils.Util.hide(unrecv_link);
- openils.Util.show(recv_link, "inline");
- recv_link.onclick = function() {
- if (self.checkLiAlerts(li.id()))
- self.issueReceive(li);
- };
- return;
- case "received":
- openils.Util.hide(recv_link);
- openils.Util.show(unrecv_link, "inline");
- unrecv_link.onclick = function() {
- if (confirm(localeStrings.UNRECEIVE_LI))
- self.issueReceive(li, /* rollback */ true);
- };
- // TODO we should allow editing before receipt, in which case the
- // test should be "if 1 or more real (acp) copies exist
- openils.Util.show(real_copies_link);
- real_copies_link.onclick = function() {
- self.showRealCopies(li);
- }
- return;
+ // Expose invoice actions for any lineitem that is linked to a PO
+ if( li.purchase_order() ) {
+
+ 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() {
+ if (!self.invoiceLinkDialogManager) {
+ self.invoiceLinkDialogManager =
+ new InvoiceLinkDialogManager("li");
+ }
+ 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;
+ };
+ }
+
+
+ /*
+ * If we haven't fleshed the lineitem_details, default to allowing access to the
+ * holdings maintenence actions. The alternative is to flesh LIDs on every lineitem,
+ * but that will add to page render time. Let's see if this will suffice...
+ */
+ var lids = li.lineitem_details();
+ if( !lids ||
+ (lids && !lids.filter(function(lid) { return lid.eg_copy_id() })[0] )) {
+
+ actUpdateBarcodes.disabled = false;
+ actUpdateBarcodes.onclick = function() {
+ self.showRealCopyEditUI(li);
+ nodeByName("action_none", row).selected = true;
}
+ actHoldingsMaint.disabled = false;
+ actHoldingsMaint.onclick =
+ self.generateMakeRecTab( li.eg_bib_id(), 'copy_browser', row );
}
- openils.Util.hide(recv_link);
- openils.Util.hide(unrecv_link);
- openils.Util.hide(real_copies_link);
+ var state_cell = nodeByName("li_state", row);
+
+ switch(li.state()) {
+
+ case 'cancelled':
+ if(typeof li.cancel_reason() == "object") {
+ var holds_state = dojo.create(
+ "span", {
+ "style": "border-bottom: 1px dashed #000;",
+ "innerHTML": li.state()
+ }, state_cell, "only"
+ );
+ new dijit.Tooltip(
+ {
+ "label": "<em>" + li.cancel_reason().label() +
+ "</em><br />" + li.cancel_reason().description(),
+ "connectId": [holds_state]
+ }, dojo.create("span", null, state_cell, "last")
+ );
+ }
+ return; // all done
+
+ case "on-order":
+ actReceive.disabled = false;
+ actReceive.onclick = function() {
+ if (self.checkLiAlerts(li.id()))
+ self.issueReceive(li);
+ nodeByName("action_none", row).selected = true;
+ };
+ break;
+
+ case "received":
+ actUnRecv.disabled = false;
+ actUnRecv.onclick = function() {
+ if (confirm(localeStrings.UNRECEIVE_LI))
+ self.issueReceive(li, /* rollback */ true);
+ nodeByName("action_none", row).selected = true;
+ };
+ break;
+ }
+
+ state_cell.innerHTML = li.state(); // TODO i18n state labels
};
this._setAlertStore = function() {
- acqLitNoteAlertSelector.store = new dojo.data.ItemFileReadStore(
+ acqLitAlertAlertText.store = new dojo.data.ItemFileReadStore(
{
"data": acqliat.toStoreData(
- (new openils.PermaCrud()).search(
- "acqliat", {"id": {"!=": null}}
+ this.pcrud.search(
+ "acqliat", {
+ "owning_lib": aou.orgNodeTrail(
+ aou.findOrgUnit(openils.User.user.ws_ou())
+ ).map(function(o) { return o.id(); })
+ }
)
)
}
);
- acqLitNoteAlertSelector.setValue(); /* make the store "live" */
- acqLitNoteAlertSelector._store_ready = true;
+ acqLitAlertAlertText.setValue(); /* make the store "live" */
+ acqLitAlertAlertText._store_ready = true;
};
/**
*/
this.drawLiNotes = function(li) {
var self = this;
+ this.focusLineitem = li.id();
- if (!acqLitNoteAlertSelector._store_ready) {
+ if (!acqLitAlertAlertText._store_ready)
this._setAlertStore();
- }
li.lineitem_notes(
li.lineitem_notes().sort(
this.liNotesTbody.removeChild(this.liNotesTbody.childNodes[0]);
this.show('notes');
- acqLitCreateLiNoteSubmit.onClick = function() {
+ acqLitCreateNoteSubmit.onClick = function() {
var value = acqLitCreateNoteText.attr('value');
if(!value) return;
var note = new fieldmapper.acqlin();
note.isnew(true);
+ note.vendor_public(
+ Boolean(acqLitCreateNoteVendorPublic.attr('checked'))
+ );
note.value(value);
note.lineitem(li.id());
- if (acqLitNoteAlertSelector.item)
- note.alert_text(Number(acqLitNoteAlertSelector.item.id));
self.updateLiNotes(li, note);
+ acqLitCreateNoteVendorPublic.attr("checked", false);
+ acqLitCreateNoteText.attr("value", "");
}
- dojo.byId('acq-lit-notes-save-button').onclick = function() {
- self.updateLiNotes(li);
+ acqLitCreateAlertSubmit.onClick = function() {
+ if (!acqLitAlertAlertText.item) {
+ alert(localeStrings.ALERT_UNSELECTED);
+ return;
+ }
+
+ var alert_text = new fieldmapper.acqliat().fromStoreItem(
+ acqLitAlertAlertText.item
+ );
+ var value = acqLitAlertNoteValue.attr("value") || "";
+
+ var note = new fieldmapper.acqlin();
+ note.isnew(true);
+ note.lineitem(li.id());
+ note.value(value);
+ note.alert_text(alert_text);
+
+ self.updateLiNotes(li, note);
}
dojo.forEach(li.lineitem_notes(), function(note) { self.addLiNote(li, note) });
if(note.isdeleted()) return;
var self = this;
var row = self.liNotesRow.cloneNode(true);
- dojo.query('[name=value]', row)[0].innerHTML = note.value();
+ nodeByName("value", row).innerHTML = note.value();
+ var alert_node = nodeByName("alert_code", row);
+ if (note.alert_text()) {
+ alert_node.innerHTML = dojo.string.substitute(
+ "[${0}] ${1}", [
+ aou.findOrgUnit(note.alert_text().owning_lib()).shortname(),
+ note.alert_text().code()
+ ]
+ );
+ if (note.alert_text().description()) {
+ new dijit.Tooltip(
+ {
+ "connectId": [alert_node],
+ "label": note.alert_text().description()
+ }, dojo.create("span", null, alert_node, "after")
+ );
+ }
+ }
- dojo.query('[name=delete]', row)[0].onclick = function() {
+ if (openils.Util.isTrue(note.vendor_public()))
+ nodeByName("vendor_public", row).innerHTML =
+ localeStrings.VENDOR_PUBLIC;
+
+ nodeByName("delete", row).onclick = function() {
note.isdeleted(true);
self.liNotesTbody.removeChild(row);
+ self.updateLiNotes(li);
};
if(note.edit_time()) {
- dojo.query('[name=edit_time]', row)[0].innerHTML =
+ nodeByName("edit_time", row).innerHTML =
dojo.date.locale.format(
dojo.date.stamp.fromISOString(note.edit_time()),
{formatLength:'short'});
}
progressDialog.hide();
+ self.updateLiNotesCount(li);
self.drawLiNotes(li);
return;
}
}
this.updateLiPrice = function(input, li) {
-
+ var self = this;
var price = input.value;
- var liWrapper = new openils.acq.Lineitem({lineitem:li});
- var oldPrice = liWrapper.getPrice() || null;
-
- if(oldPrice) oldPrice = oldPrice.price;
- if(price == oldPrice) return;
+ if(Number(price) == Number(li.estimated_unit_price())) return;
fieldmapper.standardRequest(
['open-ils.acq', 'open-ils.acq.lineitem.price.set'],
- { async : true,
+ { async : false, // redundant w/ timeout
+ timeout : 10,
params : [this.authtoken, li.id(), price],
oncomplete : function(r) {
openils.Util.readResponse(r);
+ li.estimated_unit_price(price); // update local copy
+
+ /*
+ * If this is a PO and every visible lineitem has a price,
+ * check again to see if this PO can be activated. Note that
+ * every visible lineitem having a price does not guarantee it can
+ * be activated, which is why we still make the call. Having a price
+ * set for every visiable lineitem is just the lowest barrier to entry.
+ */
+ if (self.isPO) {
+ var priceNodes = dojo.query('[name=price]', dojo.byId('acq-lit-tbody'));
+ var allSet = true;
+ dojo.forEach(priceNodes, function(node) { if (node.value == '') allSet = false});
+ if (allSet) checkCouldActivatePo();
+ }
}
}
);
}
this.drawInfo = function(liId) {
+ this.focusLineitem = liId;
+ if (!this._isRelatedViewer) {
+ var d = dojo.byId("acq-lit-info-related");
+ if (!this.relCache[liId]) {
+ fieldmapper.standardRequest(
+ [
+ "open-ils.acq",
+ "open-ils.acq.lineitems_for_bib.by_lineitem_id.count"
+ ], {
+ "async": true,
+ "params": [openils.User.authtoken, liId],
+ "onresponse": function(r) {
+ self.relCache[liId] = openils.Util.readResponse(r);
+ nodeByName("related_number", d).innerHTML =
+ self.relCache[liId];
+ openils.Util[
+ self.relCache[liId] >1 ? "show" : "hide"
+ ](d);
+ }
+ }
+ );
+ } else {
+ nodeByName("related_number", d).innerHTML = this.relCache[liId];
+ openils.Util[this.relCache[liId] > 1 ? "show" : "hide"](d);
+ }
+ }
+
this.show('info');
openils.acq.Lineitem.fetchAttrDefs(
function() {
);
};
- this._fetchLineitem = function(liId, handler) {
+ /* For a given list of lineitem ids, build a list of full lineitems
+ * re-using the fetching logic that is otherwise typical to use in this
+ * module.
+ *
+ * If we've already got a lineitem in the cache, just use that.
+ *
+ * Once we've built a list of lineitems, call callback(thatlist).
+ */
+ this.fetchLineitemsById = function(id_list, callback) {
+ var total = id_list.length;
+ var result_list = [];
+
+ var inner = function(li) {
+ result_list.push(li)
+ if (--total <= 0)
+ callback(result_list);
+ };
+
+ id_list.forEach(function(id) { self._fetchLineitem(id, inner); });
+ };
+
+ this._fetchLineitem = function(liId, handler, force) {
var li = this.liCache[liId];
- if(li && li.marc() && li.lineitem_details())
+ if(li && li.marc() && li.lineitem_details() && !force)
return handler(li);
fieldmapper.standardRequest(
- ['open-ils.acq', 'open-ils.acq.lineitem.retrieve'],
+ ['open-ils.acq', 'open-ils.acq.lineitem.retrieve.authoritative'],
{ async: true,
params: [self.authtoken, liId, {
flesh_attrs: true,
+ flesh_cancel_reason: true,
flesh_li_details: true,
+ flesh_notes: true,
flesh_fund_debit: true }],
oncomplete: function(r) {
var li = openils.Util.readResponse(r);
+ self.liCache[liId] = li;
handler(li)
}
}
this.infoTbody.appendChild(row);
}
- if(li.eg_bib_id()) {
- openils.Util.show('acq-lit-info-cat-link');
- var link = dojo.byId('acq-lit-info-cat-link').getElementsByTagName('a')[0];
-
- if(openils.XUL.isXUL()) {
-
- var makeRecTab = function() {
- xulG.new_tab(
- XUL_OPAC_WRAPPER,
- {tab_name: localeStrings.XUL_RECORD_DETAIL_PAGE, browser:false},
- {
- no_xulG : false,
- show_nav_buttons : true,
- show_print_button : true,
- opac_url : xulG.url_prefix(xulG.urls.opac_rdetail + '?r=' + li.eg_bib_id())
- }
- );
+ if (!this._isRelatedViewer) {
+ nodeByName("rel_link", dojo.byId("acq-lit-info-related")).href =
+ oilsBasePath + "/acq/lineitem/related/" + li.id();
+ }
+
+ };
+
+ this.generateMakeRecTab = function(bib_id,default_view, row) {
+ return function() {
+ xulG.new_tab(
+ XUL_OPAC_WRAPPER,
+ {tab_name: localeStrings.XUL_RECORD_DETAIL_PAGE, browser:false},
+ {
+ no_xulG : false,
+ show_nav_buttons : true,
+ show_print_button : true,
+ opac_url : xulG.url_prefix('opac_rdetail|' + bib_id),
+ default_view : default_view
}
- link.setAttribute('href', 'javascript:void(0);');
- link.onclick = makeRecTab;
+ );
- } else {
- var href = link.getAttribute('href');
- if(href.match(/=$/))
- link.setAttribute('href', href + li.eg_bib_id());
- }
- } else {
- openils.Util.hide('acq-lit-info-cat-link');
+ if(row) nodeByName("action_none", row).selected = true;
}
};
);
}
- this.drawCopies = function(liId) {
+ this.drawCopies = function(liId, force_fetch) {
+ this.focusLineitem = liId;
+ if (typeof force_fetch == "undefined")
+ force_fetch = false;
+
+ var cgi = new openils.CGI();
+ var source = cgi.param('source');
+ if (source && source.match(/invoice/)) {
+ // got here from the invoice page, show the 'return-to-invoice' button
+ var cgi = new openils.CGI({url : source});
+ cgi.param('focus_li', liId);
+ openils.Util.show(dojo.byId('acq-lit-copies-back-to-invoice-button-wrapper'), 'inline');
+ var button = dojo.byId('acq-lit-copies-back-to-invoice-button');
+ button.onclick = function() { location.href = cgi.url() };
+ }
+
+ openils.acq.Lineitem.fetchAndRender(liId, {},
+ function(li, html) {
+ dojo.byId('acq-lit-copies-li-summary').innerHTML = html;
+ }
+ );
+
this.show('copies');
var self = this;
this.copyCache = {};
this.copyWidgetCache = {};
this.oldCopyWidgetCache = {};
- this.dfaCache = {};
+ this.virtDfaCounts = {};
+ this.realDfaCache = {};
this.dfeOffset = 0;
acqLitSaveCopies.onClick = function() { self.saveCopyChanges(liId) };
this._drawBatchCopyWidgets();
+ this._drawDistribApplied(liId);
+
this._fetchDistribFormulas(
function() {
openils.acq.Lineitem.fetchAttrDefs(
function() {
- self._fetchLineitem(liId, function(li){self._drawCopies(li);});
+ self._fetchLineitem(liId, function(li){self._drawCopies(li);}, force_fetch);
}
);
}
);
};
- /**
- * Insert a new row into the distribution formula selection form
- */
- this._addDistribFormulaRow = function() {
- var self = this;
-
- if (!self.distribForms) {
- // no formulas, hide the form
- openils.Util.hide('acq-lit-distrib-formula-tbody');
- return;
+ this._saveDistribAppliedTemplates = function() {
+ if (!this._appliedDistribTemplate) {
+ this._appliedDistribTemplate =
+ dojo.byId("acq-lit-distrib-applied-tbody").
+ removeChild(dojo.byId("acq-lit-distrib-applied-row"));
+ dojo.attr(this._appliedDistribTemplate, "id");
}
+ };
- if(!this.distribFormulaTemplate)
- this.distribFormulaTemplate =
- dojo.byId('acq-lit-distrib-formula-tbody').removeChild(dojo.byId('acq-lit-distrib-form-row'));
-
- var row = this.distribFormulaTemplate.cloneNode(true);
- dojo.place(row, "acq-lit-distrib-formula-tbody", "only");
+ this._drawDistribApplied = function(liId) {
+ /* Build this table while hidden to prevent rendering artifacts */
+ openils.Util.hide("acq-lit-distrib-applied-tbody");
- this.dfSelector = new dijit.form.FilteringSelect(
- {"labelAttr": "dynLabel", "labelType": "html"},
- nodeByName("selector", row)
- );
- this._updateFormulaStore();
- this.dfSelector.fetchProperties =
- {"sort": [{"attribute": "use_count", "descending": true}]};
+ this._saveDistribAppliedTemplates();
- var apply = new dijit.form.Button(
- {"label": localeStrings.APPLY},
- nodeByName('set_button', row)
- );
+ /* Remove any rows in the table from previous populations */
+ dojo.query("tr[formula]", "acq-lit-distrib-applied-tbody").
+ forEach(dojo.destroy);
- var reset = new dijit.form.Button(
- {"label": localeStrings.RESET_FORMULAE, "disabled": true},
- nodeByName("reset_button", row)
+ /* Unregister all dijits previously created (for some reason this isn't
+ * covered by the above destroy calls). */
+ dijit.registry.forEach(
+ function(w) { if (/^dfa-/.test(w.id)) w.destroyRecursive(); }
);
- dojo.connect(apply, 'onClick',
- function() {
- var form_id = self.dfSelector.attr("value");
- if(!form_id) return;
- self._applyDistribFormula(form_id);
- reset.attr("disabled", false);
+ /* Populate the table with our liId */
+ var total = 0;
+ fieldmapper.standardRequest(
+ ["open-ils.acq",
+ "open-ils.acq.distribution_formula_application.ranged.retrieve"],
+ {
+ "async": true,
+ "params": [self.authtoken, liId],
+ "onresponse": function(r) {
+ var dfa = openils.Util.readResponse(r);
+ if (dfa) {
+ total++;
+ self.realDfaCache[dfa.id()] = dfa;
+ self._drawDistribAppliedUnit(dfa);
+ }
+ },
+ "oncomplete": function() {
+ /* Reveal built table */
+ if (total) {
+ openils.Util.show(
+ "acq-lit-distrib-applied-tbody", "table-row-group"
+ );
+ }
+ }
+ }
+ );
+ };
+
+ this._drawDistribAppliedUnit = function(dfa) {
+ var new_row = false;
+ var row = dojo.query(
+ 'tr[formula="' + dfa.formula().id() + '"]',
+ "acq-lit-distrib-applied-tbody"
+ )[0];
+
+ if (!row) {
+ new_row = true;
+ row = dojo.clone(this._appliedDistribTemplate);
+ dojo.attr(row, "formula", dfa.formula().id());
+ dojo.query("th", row)[0].innerHTML = dfa.formula().name();
+ }
+
+ var td = dojo.query("td", row)[0];
+
+ dojo.create("span", {"id": "dfa-button-" + dfa.id()}, td, "last");
+ dojo.create("span", {"id": "dfa-tip-" + dfa.id()}, td, "last");
+
+ if (new_row)
+ dojo.place(row, "acq-lit-distrib-applied-tbody", "last");
+
+ new dijit.form.Button(
+ {
+ "onClick": function() {
+ if (confirm(localeStrings.EXPLAIN_DFA_MGMT))
+ self.deleteDfa(dfa);
+ },
+ "label": "X",
+ /* XXX I /cannot/ make the following work in as a CSS class
+ * for some reason. So frustrating... */
+ "style": function(id) {
+ return (id > 0 ?
+ "font-weight: bold; color: #c00;" :
+ "color: #666;");
+ }(dfa.id()) + "margin: 0 6px;display: inline;"
+ }, "dfa-button-" + dfa.id()
+ );
+ new dijit.Tooltip(
+ {
+ "connectId": ["dfa-button-" + dfa.id()],
+ "label": dojo.string.substitute(
+ localeStrings.DFA_TIP, dfa.id() > 0 ? [
+ openils.User.formalName(dfa.creator()),
+ dojo.date.locale.format(
+ dojo.date.stamp.fromISOString(dfa.create_time()),
+ {"formatLength":"short"}
+ )
+ ] : [localeStrings.ITS_YOU, localeStrings.JUST_NOW]
+ )
+ }, "dfa-tip-" + dfa.id()
+ );
+ }
+
+ this.deleteDfa = function(dfa) {
+ if (dfa.id() > 0) { /* real */
+ this.pcrud.eliminate(
+ dfa, {
+ "async": true,
+ "oncomplete": function() {
+ self._removeDistribApplied(dfa.id());
+ delete self.realDfaCache[dfa.id()];
+ }
+ }
+ );
+ } else { /* virtual */
+ if (--(this.virtDfaCounts[dfa.formula().id()]) < 0)
+ this.virtDfaCounts[dfa.formula().id()] = 0;
+ /* hasn't been saved yet, so no need to do anything server side */
+ this._removeDistribApplied(dfa.id());
+ }
+
+ };
+
+ this._removeDistribApplied = function(dfaId) {
+ var re = new RegExp("^dfa-\\w+-" + String(dfaId));
+ dijit.registry.forEach(
+ function(w) { if (re.test(w.id)) w.destroyRecursive(); }
+ );
+ this._removeDistribAppliedEmptyRows();
+ };
+
+ this._removeAllDistribAppliedVirtual = function() {
+ /* Unregister dijits */
+ dijit.registry.forEach(
+ function(w) { if (/^dfa-\w+--/.test(w.id)) w.destroyRecursive(); }
+ );
+ this._removeDistribAppliedEmptyRows();
+ };
+
+ this._removeDistribAppliedEmptyRows = function() {
+ /* Remove any rows with no DFA at all */
+ dojo.query("tr[formula] td", "acq-lit-distrib-applied-tbody").forEach(
+ function(o) {
+ if (o.childNodes.length < 1) dojo.destroy(o.parentNode);
+ }
+ );
+ };
+
+ /**
+ * Insert a new row into the distribution formula selection form
+ */
+ this._addDistribFormulaRow = function() {
+ var self = this;
+
+ if (!self.distribForms) {
+ // no formulas, hide the form
+ openils.Util.hide('acq-lit-distrib-formula-table');
+ return;
+ }
+
+ if(!this.distribFormulaTemplate)
+ this.distribFormulaTemplate =
+ dojo.byId('acq-lit-distrib-formula-tbody').removeChild(dojo.byId('acq-lit-distrib-form-row'));
+
+ var row = this.distribFormulaTemplate.cloneNode(true);
+ dojo.place(row, "acq-lit-distrib-formula-tbody", "only");
+
+ this.dfSelector = new dijit.form.FilteringSelect(
+ {"labelAttr": "dynLabel", "labelType": "html"},
+ nodeByName("selector", row)
+ );
+ this._updateFormulaStore();
+ this.dfSelector.fetchProperties =
+ {"sort": [{"attribute": "use_count", "descending": true}]};
+
+ var apply = new dijit.form.Button(
+ {"label": localeStrings.APPLY},
+ nodeByName('set_button', row)
+ );
+
+ var reset = new dijit.form.Button(
+ {"label": localeStrings.RESET_FORMULAE, "disabled": true},
+ nodeByName("reset_button", row)
+ );
+
+ dojo.connect(apply, 'onClick',
+ function() {
+ var form_id = self.dfSelector.attr("value");
+ if(!form_id) return;
+ self._applyDistribFormula(form_id);
+ reset.attr("disabled", false);
}
);
dojo.connect(reset, 'onClick',
function() {
self.restoreCopyFieldsBeforeDF();
- self.dfaCache = {};
+ self.virtDfaCounts = {};
+ self.virtDfaId = -1;
self.dfeOffset = 0;
self._updateFormulaStore();
+ self._removeAllDistribAppliedVirtual();
reset.attr("disabled", "true");
}
);
}
if (entries_applied) {
- this.dfaCache[formula.id()] = ++(this.dfaCache[formula.id()]) || 1;
+ this.virtDfaCounts[formula.id()] =
+ ++(this.virtDfaCounts[formula.id()]) || 1;
this._updateFormulaStore();
+ this._drawDistribAppliedUnit(
+ function(df) {
+ var dfa = new acqdfa();
+ dfa.formula(df); dfa.id(self.virtDfaId--); return dfa;
+ }(formula)
+ );
this.dfeOffset += entries_applied;
};
};
var obj = store_data.items[key];
obj.use_count = Number(obj.use_count); /* needed for sorting */
- if (this.dfaCache[obj.id])
- obj.use_count = obj.use_count + Number(this.dfaCache[obj.id]);
+ if (this.virtDfaCounts[obj.id])
+ obj.use_count = obj.use_count + Number(this.virtDfaCounts[obj.id]);
obj.dynLabel = "<span class='acq-lit-distrib-form-use-count'>[" +
obj.use_count + "]</span> " + obj.name;
* This method formerly would not refetch the DF formulas if they'd been
* loaded already, but now it always re-fetches, since use_count changes.
*/
+ /** TODO: port distrib-formula selector to autofieldwidget+pcrud/dojo store */
this._fetchDistribFormulas = function(onload) {
fieldmapper.standardRequest(
["open-ils.acq",
"open-ils.acq.distribution_formula.ranged.retrieve.atomic"],
{
"async": true,
- "params": [openils.User.authtoken],
+ "params": [openils.User.authtoken, 0, 500],
"oncomplete": function(r) {
self.distribForms = openils.Util.readResponse(r);
if(!self.distribForms || self.distribForms.length == 0) {
var widget = new openils.widget.AutoFieldWidget({
fmField : field,
fmClass : 'acqlid',
+ labelFormat : (field == 'fund') ? fundLabelFormat : null,
+ searchFormat : (field == 'fund') ? fundSearchFormat : null,
+ searchFilter : (field == 'fund') ? {"active": "t"} : null,
parentNode : dojo.query('[name='+field+']', row)[0],
orgLimitPerms : ['CREATE_PICKLIST'],
- dijitArgs : {required:false},
+ dijitArgs : {
+ "required": false,
+ "labelType": (field == "fund") ? "html" : null
+ },
+ noCache: (field == "fund"),
forceSync : true
});
widget.build(
function(w, ww) {
+ if (field == "fund" && w.store)
+ self._ensureCSSFundClasses(w.store);
self.copyBatchWidgets[field] = w;
}
);
+ if (field == "fund") {
+ dojo.connect(
+ widget.widget, "onChange", function(val) {
+ self._updateFundSelectorStyle(widget, val);
+ }
+ );
+ }
}
}
);
acqLitCopyCountInput.attr('value', self.copyCount()+'');
+ var rcvr = copy.receiver();
+ if (rcvr) {
+ if (!userCache[rcvr]) {
+ if(rcvr == openils.User.user.id()) {
+ userCache[rcvr] = openils.User.user;
+ } else {
+ userCache[rcvr] = fieldmapper.standardRequest(
+ ['open-ils.actor', 'open-ils.actor.user.retrieve'],
+ {params: [openils.User.authtoken, rcvr]}
+ );
+ }
+ }
+ dojo.query('[name=receiver]', row)[0].innerHTML = userCache[rcvr].usrname();
+ }
+
dojo.forEach(liDetailFields,
function(field) {
+ var searchFilter;
+ if (field == "fund") {
+ searchFilter = (copy.fund() ?
+ {"-or": {"active": "t", "id": copy.fund()}} :
+ {"active" : "t"});
+ } else {
+ searchFilter = null;
+ }
+
+ var readOnly = false;
+
+ // TODO: Add support for changing the owning_lib after real copies have been made.
+ // owning_lib is order data as much as its item data
+ if(copy.eg_copy_id() && ['owning_lib', 'location', 'circ_modifier', 'cn_label', 'barcode'].indexOf(field) >= 0) {
+ readOnly = true;
+ }
+
+ // TODO: add support for changing the fund after debits have been created
+ // Note: invoicing allows the change
+ if(copy.fund_debit() && field == 'fund') {
+ readOnly = true;
+ }
+
+
var widget = new openils.widget.AutoFieldWidget({
fmObject : copy,
fmField : field,
+ labelFormat : (field == 'fund') ? fundLabelFormat : null,
+ searchFormat : (field == 'fund') ? fundSearchFormat : null,
+ dijitArgs: {"labelType": (field == 'fund') ? "html" : null},
+ searchFilter : searchFilter,
+ noCache: (field == "fund"),
fmClass : 'acqlid',
parentNode : dojo.query('[name='+field+']', row)[0],
orgLimitPerms : ['CREATE_PICKLIST', 'CREATE_PURCHASE_ORDER'],
- readOnly : Boolean(copy.eg_copy_id())
+ readOnly : readOnly,
+ orgDefaultsToWs : true
});
+
widget.build(
// make sure we capture the value from any async widgets
function(w, ww) {
- copy[field](ww.getFormattedValue())
+
+ if (field == "fund" && w.store)
+ self._ensureCSSFundClasses(w.store);
+
+ if(!readOnly)
+ copy[field](ww.getFormattedValue())
+
self.copyWidgetCache[copy.id()][field] = w;
- }
- );
- dojo.connect(widget.widget, 'onChange',
- function(val) {
- if(copy.isnew() || val != copy[field]()) {
- // prevent setting ischanged() automatically on widget load for existing copies
- copy[field](widget.getFormattedValue())
- copy.ischanged(true);
- }
+
+ dojo.connect(w, 'onChange',
+ function(val) {
+ if (field == "fund")
+ self._updateFundSelectorStyle(widget, val);
+
+ if (!readOnly && (copy.isnew() || val != copy[field]())) {
+ // prevent setting ischanged() automatically on widget load for existing copies
+ copy[field](widget.getFormattedValue())
+ copy.ischanged(true);
+ }
+ }
+ );
}
);
}
);
- this.updateLidReceivedness(copy, row);
+ this.updateLidState(copy, row);
};
- this.updateLidReceivedness = function(copy, row) {
- if (typeof(row) == "undefined") {
- row = dojo.query(
- 'tr[copy_id="' + copy.id() + '"]', this.copyTbody
- )[0];
+ this._ensureCSSFundClass = function(id) {
+ if (!this.fundStyleSheet) {
+ dojo.create(
+ "style", {"type": "text/css"},
+ document.getElementsByTagName("head")[0], "last"
+ );
+ this.fundStyleSheet = document.styleSheets[
+ document.styleSheets.length - 1
+ ];
+ }
+
+ var cn = "fund_" + id;
+ if (!this.haveFundClass[cn]) {
+ fieldmapper.standardRequest(
+ ["open-ils.acq", "open-ils.acq.fund.check_balance_percentages"],
+ {
+ "params": [openils.User.authtoken, id],
+ "async": true,
+ "oncomplete": function(r) {
+ r = openils.Util.readResponse(r);
+ self.fundBalanceState[id] = r;
+ var style = "";
+ if (r[0] /* stop */)
+ style = fundStyles.stop;
+ else if (r[1] /* warning */)
+ style = fundStyles.warning;
+ self.fundStyleSheet.insertRule(
+ "." + cn + " { " + style + " }",
+ self.fundStyleSheet.cssRules.length
+ );
+ self.haveFundClass[cn] = true;
+ }
+ }
+ );
}
+ };
+
+ this._ensureCSSFundClasses = function(store) {
+ store.fetch({
+ "query": {"id": "*"},
+ "onItem": function(o) { self._ensureCSSFundClass(o.id[0]); }
+ });
+ };
+
+ this._updateFundSelectorStyle = function(widget, fund_id) {
+ openils.Util.removeCSSClass(widget.widget.domNode, /fund_\d+/);
+ openils.Util.addCSSClass(widget.widget.domNode, "fund_" + fund_id);
+ };
+ this.updateLidState = function(copy, row) {
var self = this;
+
+ if (typeof(row) == "undefined") {
+ row = dojo.query('tr[copy_id="' + copy.id() + '"]', this.copyTbody)[0];
+ }
+
+ // action links
var recv_link = nodeByName("receive", row);
var unrecv_link = nodeByName("unreceive", row);
var del_link = nodeByName("delete", row);
+ var cxl_link = nodeByName("cancel", row);
+ var claim_link = nodeByName("claim", row);
+ var cxl_reason_link = nodeByName("cancel_reason", row);
+
+ // by default, hide all the actions
+ openils.Util.hide(del_link.parentNode);
+ openils.Util.hide(recv_link);
+ openils.Util.hide(unrecv_link);
+ openils.Util.hide(cxl_link);
+ openils.Util.hide(claim_link);
+ openils.Util.hide(cxl_reason_link);
+
+ if (copy.id() > 0) { // real copies (LIDs)
+
+ if (copy.cancel_reason()) {
+
+ /* --------- cancelled -------------------------- */
+
+ /* XXX the following may leak memory in a long lived table:
+ * dijits may not get destroyed... not positive. revisit. */
+ var holds_reason = dojo.create(
+ "span", {
+ "style": "border-bottom: 1px dashed #000;",
+ "innerHTML": "Cancelled" /* XXX [sic] and i18n */
+ }, cxl_reason_link, "only"
+ );
+ new dijit.Tooltip(
+ {
+ "label": "<em>" + copy.cancel_reason().label() +
+ "</em><br />" + copy.cancel_reason().description(),
+ "connectId": [holds_reason]
+ }, dojo.create("span", null, cxl_reason_link, "last")
+ );
+ openils.Util.show(cxl_reason_link, "inline");
+
+ } else if (copy.recv_time()) {
+
+ /* --------- received -------------------------- */
+
+ openils.Util.show(unrecv_link, "inline");
+ unrecv_link.onclick = function() {
+ if (confirm(localeStrings.UNRECEIVE_LID))
+ self.issueReceive(copy, /* rollback */ true);
+ };
+
+ } else if (this.liCache[copy.lineitem()].state() == 'on-order') {
+
+ /* --------- on order -------------------------- */
+
+ openils.Util.show(recv_link, 'inline');
+ openils.Util.show(cxl_link, "inline");
+
+ recv_link.onclick = function() {
+ if (self.checkLiAlerts(copy.lineitem()))
+ self.issueReceive(copy);
+ };
+
+ cxl_link.onclick = function() { self.cancelLid(copy.id()) };
- if (this.isPO) {
- openils.Util.hide(del_link.parentNode);
-
- /* Avoid showing (un)receive links for virtual copies */
- if (copy.id() > 0) {
- if(copy.recv_time()) {
- openils.Util.hide(recv_link);
- openils.Util.show(unrecv_link);
- unrecv_link.onclick = function() {
- if (confirm(localeStrings.UNRECEIVE_LID))
- self.issueReceive(copy, /* rollback */ true);
- };
- } else {
- openils.Util.hide(unrecv_link);
- openils.Util.show(recv_link);
- recv_link.onclick = function() {
- if (self.checkLiAlerts(copy.lineitem()))
- self.issueReceive(copy);
- };
- }
} else {
- openils.Util.hide(unrecv_link);
- openils.Util.hide(recv_link);
+
+ /* --------- pre-order copies -------------------------- */
+
+ del_link.onclick = function() { self.deleteCopy(row) };
+ openils.Util.show(del_link.parentNode);
+
}
- } else {
- openils.Util.hide(unrecv_link);
- openils.Util.hide(recv_link);
+
+ } else {
+
+ /* --------- virtual copies -------------------------- */
del_link.onclick = function() { self.deleteCopy(row) };
openils.Util.show(del_link.parentNode);
}
- }
+ };
+
+ this.cancelLid = function(lid_id) {
+ lidCancelDialog._lid_id = lid_id;
+ openils.Util.show(lidCancelDialog.domNode.parentNode);
+ lidCancelDialog.show();
+ if (!lidCancelDialog._prepared) {
+ var widget = new openils.widget.AutoFieldWidget({
+ "fmField": "cancel_reason",
+ "fmClass": "acqlid",
+ "parentNode": dojo.byId("acq-lit-lid-cancel-reason"),
+ "orgLimitPerms": ["CREATE_PURCHASE_ORDER"],
+ "forceSync": true
+ });
+ widget.build(
+ function(w, ww) {
+ acqLidCancelButton.onClick = function() {
+ if (w.attr("value")) {
+ if (confirm(localeStrings.LID_CANCEL_CONFIRM)) {
+ self._cancelLid(
+ lidCancelDialog._lid_id,
+ w.attr("value")
+ );
+ }
+ lidCancelDialog.hide();
+ }
+ };
+ lidCancelDialog._prepared = true;
+ }
+ );
+ }
+ };
+
+ this._cancelLid = function(lid_id, reason) {
+ fieldmapper.standardRequest(
+ ["open-ils.acq", "open-ils.acq.lineitem_detail.cancel"], {
+ "params": [openils.User.authtoken, lid_id, reason],
+ "async": true,
+ "onresponse": function(r) {
+ if (r = openils.Util.readResponse(r)) {
+ if (r.lid) {
+ for (var id in r.lid) {
+ /* actually this should only iterate once */
+ self.copyCache[id].cancel_reason(
+ r.lid[id].cancel_reason
+ );
+ self.updateLidState(self.copyCache[id]);
+ }
+ }
+ }
+ }
+ }
+ );
+ };
this._confirmAlert = function(li, lin) {
return confirm(
localeStrings.CONFIRM_LI_ALERT, [
(new openils.acq.Lineitem({"lineitem": li})).findAttr(
"title", "lineitem_marc_attr_definition"
+ ), (
+ /* XXX it's really better add a parameter and to adjust
+ * the format string rather than do this concatenation
+ * here, but if someone wants this for 2.2 in a hurry,
+ * we can sidestep the problem of updating the strings
+ * while the translators are working. */
+ "[" +
+ aou.findOrgUnit(lin.alert_text().owning_lib()).shortname() +
+ "] " +
+ lin.alert_text().code()
),
- lin.alert_text().description(), lin.value()
+ lin.alert_text().description() || "",
+ lin.value()
]
)
);
this.copyTbody.removeChild(row);
}
- this._dfaCacheAsList = function() {
+ this._virtDfaCountsAsList = function() {
var L = [];
- for (var key in this.dfaCache) {
- for (var i = 0; i < this.dfaCache[key]; i++)
+ for (var key in this.virtDfaCounts) {
+ for (var i = 0; i < this.virtDfaCounts[key]; i++)
L.push(key);
}
return L;
}
+ this.confirmBreachedCopyFunds = function(copies) {
+ var stop = 0, warning = 0;
+ copies.forEach(
+ function(o) {
+ if (o.fund()) {
+ var state = self.fundBalanceState[o.fund()];
+ if (state[0] /* stop */)
+ stop++;
+ else if (state[1] /* warning */)
+ warning++;
+ }
+ }
+ );
+
+ if (stop) {
+ return confirm(localeStrings.CONFIRM_FUNDS_AT_STOP);
+ } else if (warning) {
+ return confirm(localeStrings.CONFIRM_FUNDS_AT_WARNING);
+ }
+ return true;
+ };
+
this.saveCopyChanges = function(liId) {
var self = this;
var copies = [];
}
}
- if (typeof(this._copy_count_cb) == "function") {
- this._copy_count_cb(liId, total);
- }
dojo.byId('acq-lit-copy-count-label-' + liId).innerHTML = total;
if (copies.length > 0) {
+ if (!this.confirmBreachedCopyFunds(copies))
+ return;
+
+ if (typeof(this._copy_count_cb) == "function")
+ this._copy_count_cb(liId, total);
+
openils.Util.show("acq-lit-update-copies-progress");
fieldmapper.standardRequest(
['open-ils.acq', 'open-ils.acq.lineitem_detail.cud.batch'],
litUpdateCopiesProgress.update(res);
},
oncomplete: function() {
- self.drawCopies(liId);
+ self.drawCopies(liId, true /* force_fetch */);
openils.Util.hide("acq-lit-update-copies-progress");
}
}
);
}
- var dfa_list = this._dfaCacheAsList();
+ var dfa_list = this._virtDfaCountsAsList();
if (dfa_list.length > 0) {
fieldmapper.standardRequest(
["open-ils.acq",
}
}
);
- this.dfaCache = {};
+ this.virtDfaCounts = {};
}
}
+ this._updateCreatePoPrepayCheckbox = function(prepay) {
+ var prepay = openils.Util.isTrue(prepay);
+ this._prepayRequiredByVendor = prepay;
+ dijit.byId("acq-lit-po-prepay").attr("checked", prepay);
+ };
+
+ this._confirmPoPrepaySituation = function() {
+ var want_prepay = dijit.byId("acq-lit-po-prepay").attr("checked");
+ if (want_prepay != this._prepayRequiredByVendor) {
+ return confirm(
+ want_prepay ?
+ localeStrings.VENDOR_SAYS_PREPAY_NOT_NEEDED :
+ localeStrings.VENDOR_SAYS_PREPAY_NEEDED
+ );
+ } else {
+ return true;
+ }
+ };
+
this.applySelectedLiAction = function(action) {
var self = this;
switch(action) {
break;
case 'create_order':
-
- if(!this.createPoProviderSelector) {
- var widget = new openils.widget.AutoFieldWidget({
- fmField : 'provider',
- fmClass : 'acqpo',
- searchFilter: {"active": "t"},
- parentNode : dojo.byId('acq-lit-po-provider'),
- });
- widget.build(
- function(w) { self.createPoProviderSelector = w; }
- );
- }
-
- if(!this.createPoAgencySelector) {
- var widget = new openils.widget.AutoFieldWidget({
- fmField : 'ordering_agency',
- fmClass : 'acqpo',
- parentNode : dojo.byId('acq-lit-po-agency'),
- orgLimitPerms : ['CREATE_PURCHASE_ORDER'],
- });
- widget.build(
- function(w) { self.createPoAgencySelector = w; }
- );
- }
-
-
+ this._loadPOSelect();
acqLitPoCreateDialog.show();
break;
case 'save_picklist':
- this._loadPLSelect();
acqLitSavePlDialog.show();
break;
this.printPO();
break;
+ case 'po_history':
+ location.href = oilsBasePath + '/acq/po/history/' + this.isPO;
+ break;
+
+ case 'batch_create_invoice':
+ this.batchCreateInvoice();
+ break;
+
+ case 'batch_link_invoice':
+ this.batchLinkInvoice();
+ break;
+
case 'receive_po':
this.receivePO();
break;
break;
case 'create_assets':
- this.createAssets();
+ this.showAssetCreator();
break;
case 'export_attr_list':
this.chooseExportAttr();
break;
+ case 'batch_apply_funds':
+ this.applyBatchLiFunds();
+ break;
+
case 'add_brief_record':
if(this.isPO)
location.href = oilsBasePath + '/acq/picklist/brief_record?po=' + this.isPO;
else
location.href = oilsBasePath + '/acq/picklist/brief_record?pl=' + this.isPL;
+
+ break;
+
+ case "cancel_lineitems":
+ this.maybeCancelLineitems();
+ break;
+
+ case "change_claim_policy":
+ var li_list = this.getSelected();
+ this.claimPolicyPicker.attr("value", null);
+ liClaimPolicyDialog.show();
+ liClaimPolicySave.onClick = function() {
+ self.changeClaimPolicy(
+ li_list,
+ self.claimPolicyPicker.attr("value"),
+ function() {
+ li_list.forEach(
+ function(li) {
+ self.setClaimPolicyControl(li);
+ self.reconsiderClaimControl(li);
+ }
+ );
+ liClaimPolicyDialog.hide();
+ }
+ )
+ };
+ break;
}
- }
+ };
+
+ this.changeClaimPolicy = function(li_list, value, callback) {
+ li_list.forEach(
+ function(li) { li.claim_policy(value); }
+ );
+ fieldmapper.standardRequest(
+ ["open-ils.acq", "open-ils.acq.lineitem.update"], {
+ "params": [openils.User.authtoken, li_list],
+ "async": true,
+ "oncomplete": function(r) {
+ r = openils.Util.readResponse(r);
+ if (callback) callback(r);
+ }
+ }
+ );
+ };
- this.createAssets = function() {
+ this.showAssetCreator = function(onAssetsCreated) {
if(!this.isPO) return;
- if(!confirm(localeStrings.CREATE_PO_ASSETS_CONFIRM)) return;
+ var self = this;
+
+ // first, let's see if this PO has any LI's that need to be merged/imported
+ self.pcrud.search('jub', {purchase_order : this.isPO, eg_bib_id : null}, {
+ id_list : true,
+ oncomplete : function(r) {
+ var resp = openils.Util.readResponse(r);
+ if (resp && resp.length) {
+ // PO has some non-linked jubs.
+
+ self.show('asset-creator');
+ if(!self.vlAgent.loaded)
+ self.vlAgent.init();
+
+ dojo.connect(assetCreatorButton, 'onClick',
+ function() { self.createAssets(onAssetsCreated) });
+
+ } else {
+
+ // all jubs linked, move on to asset creation
+ self.createAssets(onAssetsCreated, true);
+ }
+ }
+ });
+ }
+
+ this.createAssets = function(onAssetsCreated, noVl) {
this.show('acq-lit-progress-numbers');
var self = this;
+ var vlArgs = (noVl) ? {} : {vandelay : this.vlAgent.values()};
fieldmapper.standardRequest(
['open-ils.acq', 'open-ils.acq.purchase_order.assets.create'],
{ async: true,
- params: [this.authtoken, this.isPO],
+ params: [this.authtoken, this.isPO, vlArgs],
onresponse: function(r) {
var resp = openils.Util.readResponse(r);
- self._updateProgressNumbers(resp, true);
+ self._updateProgressNumbers(resp, !Boolean(onAssetsCreated), onAssetsCreated);
}
}
);
}
+ this.maybeCancelLineitems = function() {
+ openils.Util.show("acq-lit-cancel-reason", "inline");
+ if (!acqLitCancelLineitemsButton._prepared) {
+ var widget = new openils.widget.AutoFieldWidget({
+ "fmField": "cancel_reason",
+ "fmClass": "jub",
+ "parentNode": dojo.byId("acq-lit-cancel-reason-selector"),
+ "orgLimitPerms": ["CREATE_PURCHASE_ORDER"],
+ "forceSync": true
+ });
+ widget.build(
+ function(w, ww) {
+ acqLitCancelLineitemsButton.onClick = function() {
+ if (w.attr("value")) {
+ if (confirm(localeStrings.LI_CANCEL_CONFIRM)) {
+ self._cancelLineitems(w.attr("value"));
+ }
+ openils.Util.hide("acq-lit-cancel-reason");
+ }
+ };
+ acqLitCancelLineitemsButton._prepared = true;
+ }
+ );
+ }
+ };
+
+ this._cancelLineitems = function(reason) {
+ var id_list = this.getSelected().map(function(o) { return o.id(); });
+ fieldmapper.standardRequest(
+ ["open-ils.acq", "open-ils.acq.lineitem.cancel.batch"], {
+ "params": [openils.User.authtoken, id_list, reason],
+ "async": true,
+ "onresponse": function(r) {
+ if (r = openils.Util.readResponse(r)) {
+ if (r.li) {
+ for (var id in r.li) {
+ self.liCache[id].state(r.li[id].state);
+ self.liCache[id].cancel_reason(
+ r.li[id].cancel_reason
+ );
+ self.updateLiState(self.liCache[id]);
+ }
+ }
+ if (r.lid && self.copyCache) {
+ for (var id in r.lid) {
+ if (self.copyCache[id]) {
+ self.copyCache[id].cancel_reason(
+ r.lid[id].cancel_reason
+ );
+ self.updateLidState(self.copyCache[id]);
+ }
+ }
+ }
+ }
+ }
+ }
+ );
+ };
+
this.chooseExportAttr = function() {
if (!acqLitExportAttrSelector._li_setup) {
var self = this;
acqLitExportAttrSelector.store = new dojo.data.ItemFileReadStore(
{
- "data": acqliad.toStoreData(
- (new openils.PermaCrud()).search(
- "acqliad", {"code": li_exportable_attrs}
+ "data": acqlimad.toStoreData(
+ this.pcrud.search(
+ "acqlimad", {"code": li_exportable_attrs}
)
)
}
progressDialog.hide();
var evt = openils.Util.readResponse(r);
if(evt && evt.template_output()) {
- win = window.open('','', 'resizable,width=800,height=600,scrollbars=1');
- win.document.body.innerHTML = evt.template_output().data();
+ openils.Util.printHtmlString(evt.template_output().data());
}
}
}
);
- }
+ };
+ this.batchCreateInvoice = function() {
+ var liIds = this.getSelected(false, null, true /* id_list */)
+ if (!liIds.length) return;
+ var path = oilsBasePath + '/acq/invoice/view?create=1';
+ dojo.forEach(liIds, function(li, idx) { path += '&attach_li=' + li });
+ location.href = path;
+ };
+
+ this.batchLinkInvoice = function(create) {
+ var liIds = this.getSelected(false, null, true /* id_list */)
+ if (!liIds.length) return;
+ if (!self.invoiceLinkDialogManager) {
+ self.invoiceLinkDialogManager =
+ new InvoiceLinkDialogManager("li");
+ }
+ self.invoiceLinkDialogManager.target = liIds;
+ acqLitLinkInvoiceDialog.show();
+ };
this.receivePO = function() {
if (!this.isPO) return;
}
this.issueReceive = function(obj, rollback) {
- /* (For now) there shall be no marking LI or LIDs (un)received
- * except from the actual "view PO" interface. */
- if (!this.isPO) return;
-
var part =
{"jub": "lineitem", "acqlid": "lineitem_detail"}[obj.classname];
var method =
"async": true,
"params": [this.authtoken, obj.id()],
"onresponse": function(r) {
- self.handleReceive(openils.Util.readResponse(r));
- },
- "oncomplete": function() { progressDialog.hide(); }
+ if (r = openils.Util.readResponse(r)) {
+ self.fetchClaimInfo(
+ part == "lineitem" ? obj.id() : obj.lineitem(),
+ /* force */ true,
+ function() { self.handleReceive(r); }
+ );
+ progressDialog.hide();
+ }
+ }
}
);
};
for (var li_id in resp.li) {
for (var key in resp.li[li_id])
self.liCache[li_id][key](resp.li[li_id][key]);
- self.updateLiReceivedness(self.liCache[li_id]);
+ self.updateLiState(self.liCache[li_id]);
}
}
if (resp.po) {
for (var lid_id in resp.lid) {
for (var key in resp.lid[lid_id])
self.copyCache[lid_id][key](resp.lid[lid_id][key]);
- self.updateLidReceivedness(self.copyCache[lid_id]);
+ self.updateLidState(self.copyCache[lid_id]);
}
}
}
);
}
- this._updateProgressNumbers = function(resp, reloadOnComplete) {
- if(!resp) return;
- dojo.byId('acq-pl-lit-li-processed').innerHTML = resp.li;
- dojo.byId('acq-pl-lit-lid-processed').innerHTML = resp.lid;
- dojo.byId('acq-pl-lit-debits-processed').innerHTML = resp.debits_accrued;
- dojo.byId('acq-pl-lit-bibs-processed').innerHTML = resp.bibs;
- dojo.byId('acq-pl-lit-indexed-processed').innerHTML = resp.indexed;
- dojo.byId('acq-pl-lit-copies-processed').innerHTML = resp.copies;
- if(resp.complete && reloadOnComplete)
- location.href = location.href;
+ this._updateProgressNumbers = function(resp, reloadOnComplete, onComplete) {
+ this.vlAgent.handleResponse(resp,
+ function(resp, res) {
+ if(reloadOnComplete)
+ location.href = location.href;
+ if (onComplete)
+ onComplete(resp, res);
+ }
+ );
}
this._createPO = function(fields) {
- this.show('acq-lit-progress-numbers');
- var po = new fieldmapper.acqpo();
- po.provider(this.createPoProviderSelector.attr('value'));
- po.ordering_agency(this.createPoAgencySelector.attr('value'));
+ var wantall = (fields.create_from == "all");
+
+ /* If we're a picklist or purchase order already and the user wants
+ * all lineitems, we might have pages' worth of lineitems haven't all
+ * been loaded yet, so getSelected() won't find them. The server,
+ * however, should know about all our lineitems, so let's ask the
+ * server for a complete list.
+ */
+
+ if (wantall) {
+ this.getSelected(
+ true, function(list) {
+ self._createPOFromLineitems(fields, list);
+ }, /* id_list */ true
+ );
+ } else {
+ this._createPOFromLineitems(fields, this.getSelected(false, null, true /* id_list */));
+ }
+ };
+
+ this._createPOFromLineitems = function(fields, selected) {
+ if (selected.length == 0) return;
+ var self = this;
- var selected = this.getSelected( (fields.create_from == 'all') );
- if(selected.length == 0) return;
+ var po = new fieldmapper.acqpo();
+ po.provider(this.createPoProviderSelector.attr("value"));
+ po.ordering_agency(this.createPoAgencySelector.attr("value"));
+ po.prepayment_required(fields.prepayment_required[0] ? true : false);
- var max = selected.length * 3;
+ // if we're creating assets, delay the asset creation
+ // until after the PO is created. This will allow us to
+ // use showAssetCreator() directly.
- var self = this;
fieldmapper.standardRequest(
- ['open-ils.acq', 'open-ils.acq.purchase_order.create'],
+ ["open-ils.acq", "open-ils.acq.purchase_order.create"],
{ async: true,
params: [
openils.User.authtoken,
- po,
- {
- lineitems : selected.map(function(li) { return li.id() }),
- create_assets : fields.create_assets[0],
- }
+ po, {lineitems : selected}
],
-
onresponse : function(r) {
var resp = openils.Util.readResponse(r);
- self._updateProgressNumbers(resp);
- if(resp.complete)
- location.href = oilsBasePath + '/eg/acq/po/view/' + resp.purchase_order.id();
+ if (resp.complete) {
+ // self.isPO is needed for showAssetCreator();
+ self.isPO = resp.purchase_order.id();
+ var redir = oilsBasePath + "/acq/po/view/" + self.isPO;
+ if (fields.create_assets[0]) {
+ self.showAssetCreator(
+ function() {location.href = redir}
+ );
+ } else {
+ location.href = redir;
+ }
+ }
}
}
);
+ };
+
+
+ this.batchFundWidget = null;
+
+ this.applyBatchLiFunds = function() {
+
+ var liIds = this.getSelected().map(function(li) { return li.id(); });
+ if(liIds.length == 0) return; // warn?
+
+ var self = this;
+ batchFundUpdateDialog.show();
+
+ if(!this.batchFundWidget) {
+ this.batchFundWidget = new openils.widget.AutoFieldWidget({
+ fmClass : 'acqf',
+ selfReference : true,
+ labelFormat : fundLabelFormat,
+ searchFormat : fundSearchFormat,
+ searchFilter : {"active": "t"},
+ parentNode : dojo.byId('acq-lit-batch-fund-selector'),
+ orgLimitPerms : ['CREATE_PICKLIST', 'CREATE_PURCHASE_ORDER'],
+ dijitArgs : { "required": true, "labelType": "html" },
+ forceSync : true
+ });
+ this.batchFundWidget.build();
+ }
+
+ dojo.connect(batchFundUpdateCancel, 'onClick', function() { batchFundUpdateDialog.hide(); });
+ dojo.connect(batchFundUpdateSubmit, 'onClick',
+ function() {
+
+ // TODO: call .dry_run first to test thresholds
+ fieldmapper.standardRequest(
+ ['open-ils.acq', 'open-ils.acq.lineitem.fund.update.batch'],
+ {
+ params : [
+ openils.User.authtoken,
+ liIds,
+ self.batchFundWidget.widget.attr('value')
+ ],
+ oncomplete : function(r) {
+ var resp = openils.Util.readResponse(r);
+ if(resp) {
+ location.href = location.href;
+ }
+ }
+ }
+ )
+ }
+ );
}
this._deleteLiList = function(list, idx) {
if(idx == null) idx = 0;
if(idx >= list.length) return;
- var liId = list[idx].id();
+
+ var li = list[idx];
+ var liId = li.id();
+
+ if (this.isPO && (li.state() == "on-order" || li.state() == "received")) {
+ /* It makes little sense to delete a lineitem from a PO that has
+ * already been marked 'on-order'. Especially if EDI is in use,
+ * such a purchase order will probably have already been shipped
+ * off to a vendor, and mucking with it at this point could leave
+ * your data in a bad state that doesn't jive with reality.
+ *
+ * I could see making this restriction even firmer.
+ *
+ * I could also see adjusting the li state comparisons, extending
+ * the comparison to the PO's state, and/or providing functions
+ * that house the logic for comparing states in a single location.
+ *
+ * Yes, this will be really annoying if you have selected a lot
+ * of lineitems to cancel that have been ordered. You'll get a
+ * confirm dialog for each one.
+ */
+
+ if (!confirm(localeStrings.DEL_LI_FROM_PO)) {
+ self._deleteLiList(list, ++idx); /* move on to next in list */
+ return;
+ }
+ }
+
fieldmapper.standardRequest(
- ['open-ils.acq', 'open-ils.acq.lineitem.delete'],
+ ['open-ils.acq',
+ this.isPO ? 'open-ils.acq.purchase_order.lineitem.delete' : 'open-ils.acq.picklist.lineitem.delete'],
{ async: true,
params: [openils.User.authtoken, liId],
oncomplete: function(r) {
/* To run in Firefox directly, must set signed.applets.codebase_principal_support
to true in about:config */
- if(!openils.XUL.enableXPConnect()) return;
-
if(openils.XUL.isXUL()) {
- win = window.open('/xul/' + openils.XUL.buildId() + '/server/cat/marcedit.xul');
+ win = window.open('/xul/' + openils.XUL.buildId() + '/server/cat/marcedit.xul','','chrome');
} else {
- win = window.open('/xul/server/cat/marcedit.xul');
+ win = window.open('/xul/server/cat/marcedit.xul','','chrome');
}
var self = this;
win.xulG = {
- record : {marc : li.marc()},
+ record : {marc : li.marc(), "rtype": "bre"},
save : {
label: 'Save Record', // XXX I18N
func: function(xmlString) {
}
);
},
- }
+ },
+ 'lock_tab' : typeof xulG != 'undefined' ? (typeof xulG['lock_tab'] != 'undefined' ? xulG.lock_tab : undefined) : undefined,
+ 'unlock_tab' : typeof xulG != 'undefined' ? (typeof xulG['unlock_tab'] != 'undefined' ? xulG.unlock_tab : undefined) : undefined
};
}
this._savePl = function(values) {
- var self = this;
- var selected = this.getSelected( (values.which == 'all') );
- openils.Util.show('acq-lit-generic-progress');
+ this.getSelected(
+ (values.which == 'all'),
+ function(list) { self._savePlFromLineitems(values, list); }
+ );
+ };
+
+ this._savePlFromLineitems = function(values, selected) {
+ openils.Util.show("acq-lit-generic-progress");
if(values.new_name) {
openils.acq.Picklist.create(
- {name: values.new_name},
+ {name: values.new_name},
function(id) {
- self._updateLiList(id, selected, 0,
- function(){
- location.href = oilsBasePath + '/eg/acq/picklist/view/' + id;
- });
+ self._updateLiList(
+ id, selected, 0,
+ function() {
+ location.href =
+ oilsBasePath + "/acq/picklist/view/" + id;
+ }
+ );
}
);
} else if(values.existing_pl) {
// update lineitems to use an existing picklist
- self._updateLiList(values.existing_pl, selected, 0,
+ self._updateLiList(
+ values.existing_pl, selected, 0,
function(){
- location.href = oilsBasePath + '/eg/acq/picklist/view/' + values.existing_pl;
- });
+ location.href =
+ oilsBasePath + "/acq/picklist/view/" +
+ values.existing_pl;
+ }
+ );
}
- }
+ };
this._updateLiState = function(values, state) {
- var self = this;
- var selected = this.getSelected( (values.which == 'all') );
+ progressDialog.show(true);
+ this.getSelected(
+ (values.which == 'all'),
+ function(list) {
+ self._updateLiStateFromLineitems(values, state, list);
+ }
+ );
+ };
+
+ this._updateLiStateFromLineitems = function(values, state, selected) {
if(!selected.length) return;
dojo.forEach(selected, function(li) {li.state(state);});
- self._updateLiList(null, selected, 0,
+ self._updateLiList(null, selected, 0,
// TODO consider inline updates for efficiency
function() { location.href = location.href }
);
- }
+ };
this._updateLiList = function(pl, list, idx, oncomplete) {
if(idx >= list.length) return oncomplete();
);
}
- this._loadPLSelect = function() {
- if(this._plSelectLoaded) return;
- var plList = [];
- function handleResponse(r) {
- plList.push(r.recv().content());
- }
- var method = 'open-ils.acq.picklist.user.retrieve';
- fieldmapper.standardRequest(
- ['open-ils.acq', method],
- { async: true,
- params: [this.authtoken],
- onresponse: handleResponse,
- oncomplete: function() {
- self._plSelectLoaded = true;
- acqLitAddExistingSelect.store =
- new dojo.data.ItemFileReadStore({data:acqpl.toStoreData(plList)});
- acqLitAddExistingSelect.setValue();
+ this._loadPOSelect = function() {
+ if (!this.createPoProviderSelector) {
+ var widget = new openils.widget.AutoFieldWidget({
+ "fmField": "provider",
+ "fmClass": "acqpo",
+ "searchFilter": {"active": "t"},
+ "parentNode": dojo.byId("acq-lit-po-provider"),
+ "dijitArgs": {
+ "onChange": function() {
+ if (this.item) {
+ self._updateCreatePoPrepayCheckbox(
+ this.item.prepayment_required()
+ );
+ }
+ }
}
- }
- );
- }
+ });
+ widget.build(function(w) { self.createPoProviderSelector = w; });
+ }
- // grab the li-details for this lineitem, grab the linked copies and volumes, add them to the table
- this.showRealCopies = function(li) {
- while(this.realCopiesTbody.childNodes[0])
- this.realCopiesTbody.removeChild(this.realCopiesTbody.childNodes[0]);
- this.show('real-copies');
+ if (!this.createPoAgencySelector) {
+ var widget = new openils.widget.AutoFieldWidget({
+ "fmField": "ordering_agency",
+ "fmClass": "acqpo",
+ "parentNode": dojo.byId("acq-lit-po-agency"),
+ "orgLimitPerms": ["CREATE_PURCHASE_ORDER"],
+ });
+ widget.build(function(w) { self.createPoAgencySelector = w; });
+ }
+ };
- var pcrud = new openils.PermaCrud({authtoken : this.authtoken});
- this.realCopyList = [];
- this.volCache = {};
- var tabIndex = 1000;
+ this.showRealCopyEditUI = function(li) {
+ copyList = [];
var self = this;
-
- acqLitSaveRealCopies.onClick = function() {
- self.saveRealCopies();
- }
+ this.volCache = {};
this._fetchLineitem(li.id(),
function(fullLi) {
li = self.liCache[li.id()] = fullLi;
- pcrud.search(
+ self.pcrud.search(
'acp', {
id : li.lineitem_details().map(
function(item) { return item.eg_copy_id() }
)
}, {
async : true,
- streaming : true,
- onresponse : function(r) {
- var copy = openils.Util.readResponse(r);
- var volId = copy.call_number();
- var volume = self.volCache[volId];
- if(!volume) {
- volume = self.volCache[volId] = pcrud.retrieve('acn', volId);
+ oncomplete : function(r) {
+ try {
+ var r_list = openils.Util.readResponse( r );
+ for (var i = 0; i < r_list.length; i++) {
+ var copy = r_list[i];
+ var volId = copy.call_number();
+ var volume = self.volCache[volId];
+ if(!volume) {
+ volume = self.volCache[volId] = self.pcrud.retrieve('acn', volId);
+ }
+ copy.call_number(volume);
+ copyList.push(copy);
+ }
+ if (xulG) {
+ xulG.volume_item_creator( { 'existing_copies' : copyList } );
+ }
+ } catch(E) {
+ alert('error in oncomplete: ' + E);
}
- self.addRealCopy(volume, copy, tabIndex++);
}
}
);
}
);
- }
+ },
- this.addRealCopy = function(volume, copy, tabIndex) {
- var row = this.realCopiesRow.cloneNode(true);
- this.realCopyList.push(copy);
+ this.drawBibFinder = function(li) {
- var selectNode;
- dojo.forEach(
- ['owning_lib', 'location', 'circ_modifier', 'label', 'barcode'],
+ var query = '';
+ var liWrapper = new openils.acq.Lineitem({lineitem:li});
+ dojo.forEach(
+ ['isbn', 'upc', 'issn', 'title', 'author'],
function(field) {
- var isvol = (field == 'owning_lib' || field == 'label');
- var widget = new openils.widget.AutoFieldWidget({
- fmField : field,
- fmObject : isvol ? volume : copy,
- parentNode : nodeByName(field, row),
- readOnly : (field != 'barcode'),
- });
-
- var widgetDrawn = null;
-
- if(field == 'barcode') {
-
- widgetDrawn = function(w, ww) {
- var node = w.domNode;
- node.setAttribute('tabindex', ''+tabIndex);
-
- // on enter, select the next barcode input
- dojo.connect(w, 'onKeyDown',
- function(e) {
- if(e.keyCode == dojo.keys.ENTER) {
- var ti = node.getAttribute('tabindex');
- var nextNode = dojo.query('[tabindex=' + String(Number(ti) + 1) + ']', self.realCopiesTbody)[0];
- if(nextNode) nextNode.select();
- }
- }
- );
-
- dojo.connect(w, 'onChange',
- function(val) {
- if(!val || val == copy.barcode()) return;
- copy.ischanged(true);
- copy.barcode(val);
- }
- );
-
-
- if(self.realCopiesTbody.getElementsByTagName('TR').length == 0)
- selectNode = node;
+ var val = liWrapper.findAttr(field, 'lineitem_marc_attr_definition');
+ if(val) {
+ if(field == 'title' || field == 'author') {
+ query += field +':' + val + ' ';
+ } else {
+ query += 'identifier|' + field + ':' + val + ' ';
}
}
-
- widget.build(widgetDrawn);
}
);
- this.realCopiesTbody.appendChild(row);
- if(selectNode) selectNode.select();
- };
+ win = window.open(
+ oilsBasePath + '/acq/lineitem/findbib?query=' + escape(query),
+ '', 'resizable,scrollbars=1,chrome');
- this.saveRealCopies = function() {
- var pcrud = new openils.PermaCrud({authtoken : this.authtoken});
- progressDialog.show(true);
- var list = this.realCopyList.filter(function(copy) { return copy.ischanged(); });
- pcrud.update(list, {oncomplete: function() {
- progressDialog.hide();
- self.show('list');
- }});
+ win.window.recordFound = function(bibId) {
+ win.close();
+
+ var attrs = li.attributes();
+ li.attributes(null);
+ li.eg_bib_id(bibId);
+
+ fieldmapper.standardRequest(
+ ["open-ils.acq", "open-ils.acq.lineitem.update"],
+ {
+ "params": [openils.User.authtoken, li],
+ "async": true,
+ "oncomplete": function(r) {
+ if(openils.Util.readResponse(r)) {
+ location.href = location.href;
+ }
+ }
+ }
+ );
+ }
}
}
+