[open-ils-commits] r15448 - in trunk/Open-ILS/web: css/skin/default js/dojo/openils/acq/nls js/ui/default/acq/common js/ui/default/acq/po templates/default/acq/po (senator)
svn at svn.open-ils.org
svn at svn.open-ils.org
Thu Feb 4 12:21:40 EST 2010
Author: senator
Date: 2010-02-04 12:21:37 -0500 (Thu, 04 Feb 2010)
New Revision: 15448
Modified:
trunk/Open-ILS/web/css/skin/default/acq.css
trunk/Open-ILS/web/js/dojo/openils/acq/nls/acq.js
trunk/Open-ILS/web/js/ui/default/acq/common/li_table.js
trunk/Open-ILS/web/js/ui/default/acq/po/search.js
trunk/Open-ILS/web/templates/default/acq/po/search.tt2
Log:
Add an "virtual PO" view of PO search results in the Acquisitions module.
This extends the li_table primitive and uses it to display lineitems belonging
to many POs as if they were part of one large PO.
Modified: trunk/Open-ILS/web/css/skin/default/acq.css
===================================================================
--- trunk/Open-ILS/web/css/skin/default/acq.css 2010-02-04 14:23:54 UTC (rev 15447)
+++ trunk/Open-ILS/web/css/skin/default/acq.css 2010-02-04 17:21:37 UTC (rev 15448)
@@ -90,13 +90,32 @@
.oils-acq-lineitem-attr-name {}
.oils-acq-lineitem-attr-value {}
#oils-acq-lineitem-marc-block { margin-top: 10px; padding: 6px; }
+.oils-acq-po-heading-po { font-weight: bold; }
+#oils-acq-metapo-summary {
+ border: 1px inset #ccc;
+ width: 400px;
+ margin-bottom: 8px;
+ margin-left: 8px;
+}
+#oils-acq-metapo-summary th, #oils-acq-metapo-summary td { padding: 3px; }
+#oils-acq-metapo-summary tbody th { font-weight: bold; }
+#oils-acq-metapo-summary thead th {
+ font-size: 110%;
+ font-weight: bold;
+ text-align: center;
+}
+#oils-acq-metapo-summary td { text-align: right; }
#acq-lit-table {width:100%}
#acq-lit-table th {padding:5px; font-weight: bold; text-align:left;}
#acq-lit-table td {padding:2px;}
.acq-lit-row { border-bottom: 1px solid #AAA; }
.acq-lit-alt-row td { padding-left:30px; }
+.acq-lit-po-heading td { background-color: #ccc; border: 1px solid #000; }
+.acq-lit-po-heading td span { padding-left: 6px; padding-right: 6px; }
+.acq-lit-po-heading td span span { padding: 0; }
+.acq-lit-po-heading td span a[attr="name"] { font-weight: bold; }
#acq-lit-info-tbody td {padding:5px;}
#acq-lit-li-details-table {margin-top:20px;}
#acq-lit-li-details-table td {padding:0px 3px 1px 3px;}
@@ -111,4 +130,3 @@
.acq-lit-table-spacer { height:20px; }
.acq-lit-row td[name="selector"] { width:1.5em; font-weight:bold; color:blue; font-size:110%;}
#acq-lit-notes-tbody li { margin-bottom:10px; border:1px solid #aaa; -moz-border-radius: 5px 5px 5px 5px; }
-
Modified: trunk/Open-ILS/web/js/dojo/openils/acq/nls/acq.js
===================================================================
--- trunk/Open-ILS/web/js/dojo/openils/acq/nls/acq.js 2010-02-04 14:23:54 UTC (rev 15447)
+++ trunk/Open-ILS/web/js/dojo/openils/acq/nls/acq.js 2010-02-04 17:21:37 UTC (rev 15448)
@@ -2,5 +2,7 @@
'CREATE_PO_ASSETS_CONFIRM' : "This will create bibliographic, call number, and copy records for this purchase order in the ILS.\n\nContinue?",
'ROLLBACK_PO_RECEIVE_CONFIRM' : "This will rollback receipt of all copies for this purchase order.\n\nContinue?",
'XUL_RECORD_DETAIL_PAGE' : 'Record Details',
- 'DELETE_LI_COPIES_CONFIRM' : 'This will delete the last ${0} copies in the table. Proceed?'
+ 'DELETE_LI_COPIES_CONFIRM' : 'This will delete the last ${0} copies in the table. Proceed?',
+ 'NO_PO_RESULTS': "No results",
+ 'PO_HEADING_ERROR' : "Unexpected problem building virtual combined PO"
}
Modified: trunk/Open-ILS/web/js/ui/default/acq/common/li_table.js
===================================================================
--- trunk/Open-ILS/web/js/ui/default/acq/common/li_table.js 2010-02-04 14:23:54 UTC (rev 15447)
+++ trunk/Open-ILS/web/js/ui/default/acq/common/li_table.js 2010-02-04 17:21:37 UTC (rev 15448)
@@ -169,7 +169,7 @@
* Inserts a single lineitem into the growing table of lineitems
* @param {Object} li The lineitem object to insert
*/
- this.addLineitem = function(li) {
+ this.addLineitem = function(li, skip_final_placement) {
this.liCache[li.id()] = li;
// sort the lineitem notes on edit_time
@@ -200,8 +200,13 @@
this.poCache[li.purchase_order()] ||
fieldmapper.standardRequest(
['open-ils.acq', 'open-ils.acq.purchase_order.retrieve'],
- {params: [this.authtoken, li.purchase_order()]});
- if(po) {
+ {params: [
+ this.authtoken, li.purchase_order(), {
+ "flesh_price_summary": 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());
@@ -210,7 +215,7 @@
}
// show which picklist this lineitem is a member of
- if(li.picklist() && this.isPO) {
+ if(li.picklist() && (this.isPO || this.isMeta)) {
var pl =
this.plCache[li.picklist()] =
this.plCache[li.picklist()] ||
@@ -226,7 +231,11 @@
}
var countNode = nodeByName('count', row);
- countNode.innerHTML = li.item_count() || 0;
+ var count = li.item_count() || 0;
+ if (typeof(this._copy_count_cb) == "function") {
+ this._copy_count_cb(li.id(), count);
+ }
+ countNode.innerHTML = count;
countNode.id = 'acq-lit-copy-count-label-' + li.id();
// lineitem state
@@ -260,8 +269,12 @@
}
}
- self.tbody.appendChild(row);
- self.selectors.push(dojo.query('[name=selectbox]', row)[0]);
+ if (!skip_final_placement) {
+ self.tbody.appendChild(row);
+ self.selectors.push(dojo.query('[name=selectbox]', row)[0]);
+ } else {
+ return row;
+ }
};
/**
@@ -851,6 +864,10 @@
}
}
+ 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)
Modified: trunk/Open-ILS/web/js/ui/default/acq/po/search.js
===================================================================
--- trunk/Open-ILS/web/js/ui/default/acq/po/search.js 2010-02-04 14:23:54 UTC (rev 15447)
+++ trunk/Open-ILS/web/js/ui/default/acq/po/search.js 2010-02-04 17:21:37 UTC (rev 15448)
@@ -1,5 +1,6 @@
dojo.require('dijit.form.Form');
dojo.require('dijit.form.Button');
+dojo.require('dijit.form.CheckBox');
dojo.require('dijit.form.FilteringSelect');
dojo.require('dijit.form.NumberTextBox');
dojo.require('dojo.data.ItemFileWriteStore');
@@ -11,6 +12,9 @@
dojo.require('openils.widget.AutoFieldWidget');
dojo.require('openils.PermaCrud');
+var metaPO;
+var _last_fields;
+var general_po_search_opts = {"order_by": {"acqpo": "edit_time DESC"}};
function getPOOwner(rowIndex, item) {
if(!item) return '';
@@ -19,7 +23,15 @@
}
function doSearch(fields) {
-
+ _last_fields = dojo.clone(fields); /* Save for re-use */
+ var metapo_view = false;
+
+ /* Remove the metapo_view field from 'fields'... we'll use it later */
+ if (fields.metapo_view && fields.metapo_view[0]) {
+ metapo_view = true;
+ delete fields.metapo_view;
+ }
+
if(isNaN(fields.id)) {
delete fields.id;
for(var k in fields) {
@@ -36,8 +48,15 @@
for(var k in fields) some = true;
if(!some) fields.id = {'!=' : null};
- poGrid.resetStore();
- poGrid.loadAll({order_by:{acqpo : 'edit_time DESC'}}, fields);
+ if (metapo_view) {
+ openils.Util.hide("holds_po_grid");
+ loadMetaPO(fields);
+ } else {
+ if (metaPO) metaPO.myHide();
+ openils.Util.show("holds_po_grid");
+ poGrid.resetStore();
+ poGrid.loadAll(general_po_search_opts, fields);
+ }
}
function loadForm() {
@@ -61,4 +80,256 @@
doSearch({ordering_agency : openils.User.user.ws_ou()});
}
+function loadMetaPO(fields) {
+ var pcrud = new openils.PermaCrud();
+ var po_list = pcrud.search("acqpo", fields, general_po_search_opts);
+ if (!po_list || !po_list.length) {
+ alert(localeStrings.NO_PO_RESULTS);
+ } else {
+ if (!metaPO) {
+ metaPO = new AcqLiTable();
+
+ /* We need to know the width (in cells) of the template row for
+ * the LI table, and we don't want to hardcode it here. */
+ metaPO.n_cells = dojo.query("> td", metaPO.rowTemplate).length;
+
+ metaPO._copy_count_cb = function(liId, count) {
+ var poId = this.liCache[liId].purchase_order();
+
+ if (this.copy_counts[poId] == undefined)
+ this.copy_counts[poId] = {};
+ this.copy_counts[poId][liId] = count;
+
+ this.renderCopyCounts(poId);
+ this.renderSummary("copies");
+ };
+ metaPO.myHide = function() {
+ this.hide();
+ openils.Util.hide("oils-acq-holds-metapo-summary");
+ };
+ metaPO.renderSummary = function(part) {
+ var self = this;
+ /* The idea here will be that if "part" is defined, we'll
+ * just update that part of the metaPO summary, otherwise,
+ * the whole thing. */
+ if (part != undefined) {
+ var target = dojo.byId("oils-acq-metapo-summary-" + part);
+ switch (part) {
+ case "copies":
+ target.innerHTML = self.copiesTotal();
+ break;
+ case "po":
+ target.innerHTML = self.working_po_list.length;
+ break;
+ default:
+ /* assume a field on the acqpo's themselves */
+ target.innerHTML = self.anyFieldTotal(part);
+ break;
+ }
+ } else {
+ openils.Util.show("oils-acq-holds-metapo-summary");
+ self.totalable_fields.forEach(
+ function(f) { self.renderSummary(f); }
+ );
+ }
+ };
+ metaPO.anyFieldTotal = function(field) {
+ var self = this;
+ return self.working_po_list.reduce(
+ /* working_po_list contains unfleshed, acqpo's, so we must
+ * find the same PO in the poCache */
+ function(p, c) {
+ c = self.poCache[c.id()][field]();
+ return p + Number(c);
+ }, 0
+ );
+ };
+ metaPO.renderCopyCounts = function(poId) {
+ try {
+ dojo.query("td#oils-acq-po-heading-" + poId +
+ ' span span[attr="copies"]')[0].innerHTML =
+ this.copiesByPOId(poId);
+ } catch (E) {
+ ;
+ }
+ };
+ metaPO.sectionHeadingById = function(id) {
+ var headings = dojo.query("#po-heading-" + id, this.tbody);
+ if (headings.length != 1) {
+ alert(localeStrings.PO_HEADING_ERROR);
+ return undefined;
+ } else {
+ return headings[0];
+ }
+ };
+ metaPO.sectionHeadingByPOId = function(poId) {
+ return this.sectionHeadingById(this.sections_by_poid[poId]);
+ };
+ metaPO.addSection = function(po) {
+ var s = this.sections_by_poid[po.id()] = this.sections++;
+
+ this.tbody.appendChild(
+ dojo.create("tr", {
+ "class": "acq-lit-po-heading", "id": "po-heading-" + s
+ })
+ );
+
+ return s;
+ };
+ metaPO.addLineitemToSection = function(li, section) {
+ dojo.place(
+ this.addLineitem(li, true /* skip_final_placement */),
+ this.sectionHeadingById(section),
+ "after"
+ );
+ };
+ metaPO.generateActivator = function(id) {
+ return function() {
+ progressDialog.show(true);
+ try {
+ fieldmapper.standardRequest(
+ ["open-ils.acq",
+ "open-ils.acq.purchase_order.activate"], {
+ "async": true,
+ "params": [openils.User.authtoken, id],
+ "oncomplete": function() {
+ progressDialog.hide();
+ doSearch(_last_fields);
+ }
+ }
+ );
+ } catch (E) {
+ progressDialog.hide();
+ alert(E); /* XXX */
+ }
+ };
+ };
+ metaPO.renderHeading = function(poId) {
+ var self = this;
+ var td = dojo.create("td", {"colspan": self.n_cells});
+ td.id = "oils-acq-po-heading-" + poId;
+
+ /* Build our HTML structure from the template... */
+ dojo.query("> span", "oils-acq-po-heading-template").forEach(
+ function(s) { td.appendChild(s.cloneNode(true)); }
+ );
+
+ /* Some fields straight from the PO object... */
+ self.po_fields_for_display.forEach(
+ function(f) {
+ dojo.query('[attr="' + f + '"]', td)[0].innerHTML =
+ self.poCache[poId][f]();
+ }
+ );
+
+ /* The name field needs special treatment: it's a link */
+ dojo.attr(
+ dojo.query('a[attr="name"]', td)[0],
+ "href",
+ oilsBasePath + '/acq/po/view/' + poId
+ );
+
+ /* Show an "activate" link, or not, based on "state"... */
+ var a = dojo.query('a[attr="activator"]', td)[0];
+ if (self.poCache[poId].state() == "pending") {
+ a.onclick = self.generateActivator(poId);
+ openils.Util.show(a, "inline");
+ } else {
+ openils.Util.hide(a);
+ }
+
+ /* Put the new heading cell in place... */
+ dojo.place(td, self.sectionHeadingByPOId(poId), "only");
+
+ /* And finally, render copy info (must happen _after_ heading
+ * is attached to the DOM tree */
+ this.renderCopyCounts(poId);
+ };
+ metaPO.copiesByPOId = function(poId) {
+ if (!this.copy_counts[poId]) return undefined;
+ var total = 0;
+ for (var liId in this.copy_counts[poId]) {
+ total += this.copy_counts[poId][liId];
+ }
+ return total;
+ };
+ metaPO.copiesTotal = function() {
+ var total = 0;
+ for (var poId in this.copy_counts)
+ total += this.copiesByPOId(poId);
+ return total;
+ };
+ metaPO.myReset = function() {
+ this.isMeta = true;
+ this.sections = 0;
+ this.sections_by_poid = {};
+ this.copy_counts = {};
+ this.po_fields_for_display = [
+ "name", "lineitem_count", "amount_encumbered",
+ "amount_spent", "state"
+ ];
+ this.totalable_fields = [
+ "po", "lineitem_count", "copies",
+ "amount_encumbered", "amount_spent"
+ ];
+ openils.Util.hide("oils-acq-holds-metapo-summary");
+ };
+ metaPO.populate = function(list) {
+ var self = this;
+ var done = 0;
+
+ self.working_po_list = [];
+
+ progressDialog.show(true);
+ list.forEach(function(po) {
+ var sec = self.addSection(po);
+ fieldmapper.standardRequest(
+ ["open-ils.acq", "open-ils.acq.lineitem.search"], {
+ "async": true,
+ "params": [
+ openils.User.authtoken,
+ {"purchase_order": po.id()},
+ {"flesh_attrs": true, "flesh_notes": true}
+ ],
+ "onresponse": function(r) {
+ var li = openils.Util.readResponse(r);
+ if (li) /* sometimes empty string: disregard */
+ self.addLineitemToSection(li, sec);
+ },
+ "oncomplete": function(r) {
+ self.working_po_list.push(po);
+ self.renderHeading(po.id());
+ self.renderSummary();
+ /* This mechanism avoids calling .show() too
+ * often or before results are ready, and
+ * thus smooths out DOM rendering glitches. */
+ if (++done >= list.length) {
+ done = -1;
+ self.show("list");
+ progressDialog.hide();
+ }
+ }
+ }
+ );
+ });
+ /* This mechanism sees to it that we call .show() at least once
+ * even if the search result population seems to be timing
+ * out or failing. */
+ setTimeout(
+ function() {
+ if (done != -1) {
+ self.show("list");
+ progressDialog.hide();
+ }
+ }, 10000 /* 10 seconds: make this configurable? */
+ );
+ };
+ }
+
+ metaPO.reset();
+ metaPO.myReset();
+ metaPO.populate(po_list);
+ }
+}
+
openils.Util.addOnLoad(loadForm);
Modified: trunk/Open-ILS/web/templates/default/acq/po/search.tt2
===================================================================
--- trunk/Open-ILS/web/templates/default/acq/po/search.tt2 2010-02-04 14:23:54 UTC (rev 15447)
+++ trunk/Open-ILS/web/templates/default/acq/po/search.tt2 2010-02-04 17:21:37 UTC (rev 15448)
@@ -4,6 +4,15 @@
<div id='oils-acq-list-header-label'>PO Search</div>
</div>
+<div id="oils-acq-po-heading-template" class="hidden">
+ <span>Purchase Order: <a attr="name"></a></span>
+ <span>Total Lineitems: <span attr="lineitem_count"></span></span>
+ <span>Total Encumbered: $<span attr="amount_encumbered"></span></span>
+ <span>Total Spent: $<span attr="amount_spent"></span></span>
+ <span>Total Copies: <span attr="copies"></span></span>
+ <span>Status: <span attr="state"></span></span>
+ <span><a class="hidden" attr="activator" href="javascript:void(0);">Activate Order</a></span>
+</div>
<!-- load the page-specific JS -->
<script src='[% ctx.media_prefix %]/js/ui/default/acq/po/search.js'> </script>
@@ -36,8 +45,12 @@
identifier:"value",
label: "name",
items: [
+ /* FIXME This is probably not the correct final list of
+ possible states */
{name:"New", value:'new'},
- {name:"In Process", value:'in-process'}
+ {name:"In Process", value:'in-process'},
+ {name:"Pending", value:'pending'},
+ {name:"On order", value:'on-order'}
]
}
});
@@ -55,9 +68,14 @@
<span dojoType='dijit.form.Button' type='submit'>Search</span>
</div>
+ <div class="oils-acq-basic-form-div">
+ <input dojoType="dijit.form.CheckBox" value="1" name="metapo_view"
+ id="metapo_view" type="checkbox" />
+ <label for="metapo_view">Show results as a virtual combined PO</label>
+ </div>
</form>
<br/>
-<div dojoType="dijit.layout.ContentPane" layoutAlign="client">
+<div dojoType="dijit.layout.ContentPane" layoutAlign="client" id="holds_po_grid">
<table
id="po-grid"
autoHeight='true'
@@ -80,7 +98,38 @@
</tr>
</thead>
</table>
- <div comment='dojo-needs-me'/>
+ <div comment='dojo-needs-me'></div>
</div>
+<div id="oils-acq-holds-metapo-summary" class="hidden">
+ <table id="oils-acq-metapo-summary">
+ <thead>
+ <tr>
+ <th colspan="2">Results Summary</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>Total Purchase Orders:</th>
+ <td id="oils-acq-metapo-summary-po"></td>
+ </tr>
+ <tr>
+ <th>Total Lineitems:</th>
+ <td id="oils-acq-metapo-summary-lineitem_count"></td>
+ </tr>
+ <tr>
+ <th>Total Copies:</th>
+ <td id="oils-acq-metapo-summary-copies"></td>
+ </tr>
+ <tr>
+ <th>Total Encumbered:</th>
+ <td>$<span id="oils-acq-metapo-summary-amount_encumbered"></span></td>
+ </tr>
+ <tr>
+ <th>Total Spent:</th>
+ <td>$<span id="oils-acq-metapo-summary-amount_spent"></span></td>
+ </tr>
+ </tbody>
+ </table>
+</div>
+[% INCLUDE 'default/acq/common/li_table.tt2' %]
[% END %]
-
More information about the open-ils-commits
mailing list