</class>
<class id="acqdf" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="acq::distribution_formula" oils_persist:tablename="acq.distribution_formula" reporter:label="Distribution Formula">
<fields oils_persist:primary="id" oils_persist:sequence="acq.distribution_formula_id_seq">
- <field reporter:label="Formula ID" name="id" reporter:datatype="id"/>
+ <field reporter:label="Formula ID" name="id" reporter:datatype="id" reporter:selector="name" />
<field reporter:label="Formula Owner" name="owner" reporter:datatype="org_unit"/>
<field reporter:label="Formula Name" name="name" reporter:datatype="text"/>
<field reporter:label="Skip Count" name="skip_count" reporter:datatype="int"/>
<div id='acq-lit-table-div' class='hidden'>
<!-- Line Item (bib record) list -->
- <table id='acq-lit-table' class='oils-generic-table'>
- <thead>
- <tr>
- <th colspan='0'>
- <table style='width:100%;'>
- <tr>
- <td>
- <span>
- <select id="acq-lit-li-actions-selector">
- <!-- mask meanings:
- pl: selection list
- po: pending purchase order
- ao: activated purchase order
- gs: general search
- vp: view/place orders
- fs: MARC federated search
+ <div style="float: left;">
+ <span>
+ <select id="acq-lit-li-actions-selector">
+ <!-- mask meanings:
+ pl: selection list
+ po: pending purchase order
+ ao: activated purchase order
+ gs: general search
+ vp: view/place orders
+ fs: MARC federated search
- * for all, otherwise combine with |
- -->
- <option mask='*' value='_'>[% l('--Actions--') %]</option>
- <option mask='pl|gs|vp|fs' value='save_picklist'>[% l('Save Items To Selection List') %]</option>
- <option mask='pl|gs|vp' value='selector_ready'>[% l('Mark Ready for Selector') %]</option>
- <option mask='pl|gs|vp' value='order_ready'>[% l('Mark Ready for Order') %]</option>
- <option mask='pl|po|gs|vp' value='delete_selected'>[% l('Delete Selected Items') %]</option>
- <option mask='pl|po' value='add_brief_record'>[% l('Add Brief Record') %]</option>
- <option mask='pl|po|ao|gs' value='export_attr_list'>[% l('Export Single Attribute List') %]</option>
- <option mask='*' value='' disabled='disabled'>[% l('----PO----') %]</option>
- <option mask='pl|gs|vp|fs' value='create_order'>[% l('Create Purchase Order') %]</option>
- <option mask='pl|gs|vp|fs' value='add_to_order'>[% l('Add to Purchase Order') %]</option>
- <option mask='po|ao' value='print_po'>[% l('Print Purchase Order') %]</option>
- <option mask='po|ao' value='po_history'>[% l('View PO History') %]</option>
- <option mask='po' value='create_assets'>[% l('Load Bibs and Items') %]</option>
- <!-- <option mask='' value='batch_apply_funds'>[% l('Apply Funds to Selected Items') %]</option> XXX moving to batch updater -->
- <option mask='ao|gs|vp' value='cancel_lineitems'>[% l('Cancel Selected Line Items') %]</option>
- <option mask='po|ao|gs|vp' value='apply_claim_policy'>[% l('Apply Claim Policy to Selected Line Items') %]</option><!-- can the functionality desired here be covered by the next thing? -->
- <option mask='ao|gs|vp' value='receive_lineitems' id='receive_lineitems' disabled='disabled'>[% l('Mark Selected Line Items as Received') %]</option>
- <option mask='ao|gs|vp' value='rollback_receive_lineitems' id='rollback_receive_lineitems' disabled='disabled'>[% l('Un-Receive Selected Line Items') %]</option>
- <option mask='ao|gs|vp' value='batch_create_invoice'>[% l('Create Invoice From Selected Line Items') %]</option>
- <option mask='ao|gs|vp' value='batch_link_invoice'>[% l('Link Selected Line Items to Invoice') %]</option>
- </select>
- <span id="acq-lit-export-attr-holder" class="hidden">
- <input dojoType="dijit.form.FilteringSelect" id="acq-lit-export-attr" jsId="acqLitExportAttrSelector" labelAttr="description" searchAttr="description" />
- <span dojoType="dijit.form.Button" jsId="acqLitExportAttrButton">[% l('Export List') %]</span>
- </span>
- <span id="acq-lit-cancel-reason" class="hidden">
- <span id="acq-lit-cancel-reason-selector"></span>
- <span dojoType="dijit.form.Button" jsId="acqLitCancelLineitemsButton">[% l('Cancel Line Items') %]</span>
- </span>
- </span>
- <span id='acq-lit-generic-progress' class='hidden'>
- <span dojoType="dijit.ProgressBar" style="width:300px" jsId="litGenericProgress"></span>
- </span>
- </td>
- <td>
- <div style='width:100%;text-align:right;'>
- <span style='padding-right:15px;'>
- <a href='javascript:void(0);' id='acq-lit-prev' style='visibility:hidden'>[% l('« Previous') %]</a>
- <a href='javascript:void(0);' id='acq-lit-next' style='visibility:hidden'>[% l('Next »') %]</a>
- </span>
- </div>
- </td>
- </tr>
- </table>
- </th>
- </tr>
- </thead>
- <tbody><tr><td colspan='0' style='height:20px;'/></tr></tbody>
+ * for all, otherwise combine with |
+ -->
+ <option mask='*' value='_'>[% l('--Actions--') %]</option>
+ <option mask='pl|gs|vp|fs' value='save_picklist'>[% l('Save Items To Selection List') %]</option>
+ <option mask='pl|gs|vp' value='selector_ready'>[% l('Mark Ready for Selector') %]</option>
+ <option mask='pl|gs|vp' value='order_ready'>[% l('Mark Ready for Order') %]</option>
+ <option mask='pl|po|gs|vp' value='delete_selected'>[% l('Delete Selected Items') %]</option>
+ <option mask='pl|po' value='add_brief_record'>[% l('Add Brief Record') %]</option>
+ <option mask='pl|po|ao|gs' value='export_attr_list'>[% l('Export Single Attribute List') %]</option>
+ <option mask='*' value='' disabled='disabled'>[% l('----PO----') %]</option>
+ <option mask='pl|gs|vp|fs' value='create_order'>[% l('Create Purchase Order') %]</option>
+ <option mask='pl|gs|vp|fs' value='add_to_order'>[% l('Add to Purchase Order') %]</option>
+ <option mask='po|ao' value='print_po'>[% l('Print Purchase Order') %]</option>
+ <option mask='po|ao' value='po_history'>[% l('View PO History') %]</option>
+ <option mask='po' value='create_assets'>[% l('Load Bibs and Items') %]</option>
+ <option mask='ao|gs|vp' value='cancel_lineitems'>[% l('Cancel Selected Line Items') %]</option>
+ <option mask='po|ao|gs|vp' value='apply_claim_policy'>[% l('Apply Claim Policy to Selected Line Items') %]</option><!-- can the functionality desired here be covered by the next thing? -->
+ <option mask='ao|gs|vp' value='receive_lineitems' id='receive_lineitems' disabled='disabled'>[% l('Mark Selected Line Items as Received') %]</option>
+ <option mask='ao|gs|vp' value='rollback_receive_lineitems' id='rollback_receive_lineitems' disabled='disabled'>[% l('Un-Receive Selected Line Items') %]</option>
+ <option mask='ao|gs|vp' value='batch_create_invoice'>[% l('Create Invoice From Selected Line Items') %]</option>
+ <option mask='ao|gs|vp' value='batch_link_invoice'>[% l('Link Selected Line Items to Invoice') %]</option>
+ </select>
+ <span id="acq-lit-export-attr-holder" class="hidden">
+ <input dojoType="dijit.form.FilteringSelect" id="acq-lit-export-attr" jsId="acqLitExportAttrSelector" labelAttr="description" searchAttr="description" />
+ <span dojoType="dijit.form.Button" jsId="acqLitExportAttrButton">[% l('Export List') %]</span>
+ </span>
+ <span id="acq-lit-cancel-reason" class="hidden">
+ <span id="acq-lit-cancel-reason-selector"></span>
+ <span dojoType="dijit.form.Button" jsId="acqLitCancelLineitemsButton">[% l('Cancel Line Items') %]</span>
+ </span>
+ </span>
+ <span id='acq-lit-generic-progress' class='hidden'>
+ <span dojoType="dijit.ProgressBar" style="width:300px" jsId="litGenericProgress"></span>
+ </span>
+ </div>
+ <div style="float: right;">
+ <div style='width:100%;text-align:right;'>
+ <span style='padding-right:15px;'>
+ <a href='javascript:void(0);' id='acq-lit-prev' style='visibility:hidden'>[% l('« Previous') %]</a>
+ <a href='javascript:void(0);' id='acq-lit-next' style='visibility:hidden'>[% l('Next »') %]</a>
+ </span>
+ </div>
+ </div>
+ <div style="clear: both;"> </div><!-- XXX better way to end effects of float: left/right ? -->
+
+ <table id="acq-batch-update" class="hidden"><!-- XXX freeze in place w/ CSS? -->
+ <tr>
+ <th>
+ <label for="acq-bu-item_count">[% l("Copies") %]</label>
+ </th>
+ <th>
+ <label for="acq-bu-owning_lib">[% l("Owning Branch") %]</label>
+ </th>
+ <th>
+ <label for="acq-bu-location">[% l("Copy Location") %]</label>
+ </th>
+ <th>
+ <label for="acq-bu-collection_code">[% l("Collection Code") %]</label>
+ </th>
+ <th>
+ <label for="acq-bu-fund">[% l("Fund") %]</label>
+ </th>
+ <th>
+ <label for="acq-bu-circ_modifier">[% l("Circ Modifier") %]</label>
+ </th>
+ <th>
+ <label for="acq-bu-distribution_formula">[% l("Distribution Formula") %]</label>
+ </th>
+ </tr>
+ <tr>
+ <td>
+ <span id="acq-bu-item_count"></span>
+ </td>
+ <td>
+ <span id="acq-bu-owning_lib"></span>
+ </td>
+ <td>
+ <span id="acq-bu-location"></span>
+ </td>
+ <td>
+ <span id="acq-bu-collection_code"></span>
+ </td>
+ <td>
+ <span id="acq-bu-fund"></span>
+ </td>
+ <td>
+ <span id="acq-bu-circ_modifier"></span> OR
+ </td>
+ <td>
+ <span id="acq-bu-distribution_formula"></span>
+ <span dojoType="dijit.form.Button" jsId="acqBatchUpdateApply">[% l("Apply to Selected") %]</span>
+ </td>
+ </tr>
+ </table>
+ <table id='acq-lit-table' class='oils-generic-table'>
+ <tbody><tr><td colspan='0' style='height:20px;'></td></tr></tbody>
<tbody style='font-weight:bold;border:1px solid #aaa;'>
<tr>
<td><span><a id='acq-lit-select-toggle' href='javascript:void(0);'>✓</a></span></td>
span[name="worksheet"] { padding: 0 6px; }
#acq-lit-li-claim-dia-lid-list-init { margin-left: 8px; }
+#acq-batch-update { padding: 20px 0; }
+#acq-batch-update th { font-weight: bold; }
+#acq-batch-update td { white-space: nowrap; padding-right: 0.5em; }
+
#acq-worksheet-contents thead th { font-weight: bold; background-color: #ccc; text-align: center; border-bottom: 1px #000 solid; border-right: 1px #000 solid; padding: 0 6px; }
#acq-worksheet-contents tbody td { text-align: left; vertical-align: top; border: 1px #999 inset; padding: 0 2px; }
"INVOICE_ITEM_PO_DETAILS" : "<b>${0}</b><br/><a href='${1}/acq/po/view/${2}'>PO #${3} ${4}</a><br/>Total Estimated Cost: $${5}",
"UNNAMED" : "Unnamed",
"NO_FIND_INVOICE" : "Could not find that invoice.\nNote that the Invoice # field is case-sensitive.",
- "NO_LI_TO_CLAIM" : "You have not selected any lineitems to claim.",
- "NO_LID_TO_CLAIM" : "You have not selected any lineitem details to claim.",
+ "LI_BATCH_UPDATE": "Line item batch update",
+ "NO_LI_TO_UPDATE" : "You have not selected any line items to update.",
+ "NO_LI_TO_CLAIM" : "You have not selected any line items to claim.",
+ "NO_LID_TO_CLAIM" : "You have not selected any line item details to claim.",
"CHANGE_CLAIM_POLICY" : "Change claim policy",
"CANCELED" : "Canceled",
"RECVD" : "Recv'd",
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.afwCopyFieldArgs = function(field, perms) {
+ return {
+ "fmField" : field,
+ "fmClass": 'acqlid',
+ "labelFormat": (field == 'fund') ? fundLabelFormat : null,
+ "searchFormat": (field == 'fund') ? fundSearchFormat : null,
+ "searchFilter": (field == 'fund') ? {"active": "t"} : null,
+ "orgLimitPerms": [perms],
+ "dijitArgs": {
+ "required": false,
+ "labelType": (field == "fund") ? "html" : null
+ },
+ "noCache": (field == "fund"),
+ "forceSync": true
+ };
+ };
+
+ /* This is the "new" batch updater that sits atop all lineitems. It does
+ * use this.afwCopyFieldArgs() to borrow a little common code from the
+ * "old" batch updater atop the copy details view. */
+ this.initBatchUpdater = function(disabled_fields) {
+ openils.Util.show("acq-batch-update", "table");
+
+ if (!dojo.isArray(disabled_fields)) disabled_fields = [];
+
+ /* Note that this will directly contain dijits, not the AutoWidget
+ * wrapper object. */
+ this.batchUpdateWidgets = {};
+
+ this.batchUpdateWidgets.item_count = new dijit.form.TextBox(
+ {
+ "style": {"width": "3em"},
+ "disabled": Boolean(
+ dojo.indexOf(disabled_fields, "item_count") != -1
+ )
+ },
+ "acq-bu-item_count"
+ );
+
+ (new openils.widget.AutoFieldWidget({
+ "fmClass": "acqdf",
+ "selfReference": true,
+ "dijitArgs": { "required": false },
+ "forceSync": true,
+ "parentNode": "acq-bu-distribution_formula"
+ })).build(
+ function(w) {
+ dojo.style(w.domNode, {"width": "12em"});
+ /* dijitArgs to AutoFieldWidget won't work for 'disabled' */
+ w.attr(
+ "disabled",
+ dojo.indexOf(disabled_fields, "distribution_formula") != -1
+ );
+ self.batchUpdateWidgets.distribution_formula = w;
+ }
+ );
+
+ dojo.forEach(
+ ["owning_lib","location","collection_code","circ_modifier","fund"],
+ function(field) {
+ var args = self.afwCopyFieldArgs(field,"CREATE_PURCHASE_ORDER");
+ args.parentNode = dojo.byId("acq-bu-" + field);
+
+ (new openils.widget.AutoFieldWidget(args)).build(
+ function(w, aw) {
+ if (field == "fund") {
+ dojo.connect(
+ w, "onChange", function(val) {
+ self._updateFundSelectorStyle(aw, val);
+ }
+ );
+ if (w.store)
+ self._ensureCSSFundClasses(w.store);
+ }
+
+ dojo.style(w.domNode, {"width": "10em"});
+ w.attr(
+ "disabled",
+ dojo.indexOf(disabled_fields, field) != -1
+ );
+ self.batchUpdateWidgets[field] = w;
+ }
+ );
+ }
+ );
+
+ acqBatchUpdateApply.onClick = function() {
+ var li_id_list = self.getSelected(false, null, true /* id list */);
+ if (!li_id_list.length) {
+ alert(localeStrings.NO_LI_TO_UPDATE);
+ return;
+ }
+
+ progressDialog.show(true);
+ progressDialog.attr("title", localeStrings.LI_BATCH_UPDATE);
+ progressDialog.update({"maximum": li_id_list.length,"progress": 0});
+
+ var count = 0;
+
+ var params = [ self.authtoken, {"lineitems": li_id_list},
+ self.batchUpdateChanges(), self.batchUpdateFormula() ];
+ console.log("batch update params: " + dojo.toJson(params));
+
+ fieldmapper.standardRequest(
+ ["open-ils.acq", "open-ils.acq.lineitem.batch_update"], {
+ "async": true,
+ "params": params,
+ "onresponse": function(r) {
+ if ((r = openils.Util.readResponse(r))) { // assignment
+ progressDialog.update({"progress": ++count});
+ } else {
+ progressDialog.hide();
+ progressDialog.attr("title", "");
+ }
+ },
+ "oncomplete": function() {
+ /* XXX Is the last call to onresponse guaranteed to
+ * finish before oncomplete is fired? */
+ if (count != li_id_list.length) {
+ console.error("lineitem batch update operation failed");
+ progressDialog.hide();
+ progressDialog.attr("title", "");
+ } else {
+ location.href = location.href;
+ }
+ }
+ }
+ );
+ };
+ };
+
+ this.batchUpdateChanges = function() {
+ var o = {};
+
+ dojo.forEach(
+ openils.Util.objectProperties(this.batchUpdateWidgets),
+ function(k) {
+ if (k == "distribution_formula") return; /* handled elsewhere */
+ if (self.batchUpdateWidgets[k].attr("disabled")) return;
+
+ /* It's important that a value of "" should mean that a field
+ * doesn't get used in the arguments to the batch updater API,
+ * but 0 should mean an actual 0. */
+ var value = self.batchUpdateWidgets[k].attr("value");
+ if (value !== "")
+ o[k] = value;
+ }
+ );
+
+ return o;
+ };
+
+ this.batchUpdateFormula = function() {
+ if (this.batchUpdateWidgets.distribution_formula.attr("disabled")) {
+ return null;
+ } else {
+ return (
+ this.batchUpdateWidgets.distribution_formula.attr("value") ||
+ null
+ );
+ }
+ };
+
this.reset = function(keep_selectors) {
while(self.tbody.childNodes[0])
self.tbody.removeChild(self.tbody.childNodes[0]);
};
this.enableActionsDropdownOptions = function(mask) {
- /* 'mask' is probably a minomer the way I'm using it, but it needs to
+ /* 'mask' is probably a misnomer the way I'm using it, but it needs to
* be one of pl,po,ao,gs,vp, or fs. */
dojo.query("option", "acq-lit-li-actions-selector").forEach(
function(option) {
if(self.copyBatchRowDrawn) {
self.copyBatchWidgets[field].attr('value', null);
} else {
- 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,
- "labelType": (field == "fund") ? "html" : null
- },
- noCache: (field == "fund"),
- forceSync : true
- });
+ var args = self.afwCopyFieldArgs(field, "CREATE_PICKLIST");
+ args.parentNode = dojo.query('[name='+field+']', row)[0];
+
+ var widget = new openils.widget.AutoFieldWidget(args);
widget.build(
function(w, ww) {
if (field == "fund" && w.store)
if(PO.order_date()) {
openils.Util.show('acq-po-activated-on', 'inline');
liTable.enableActionsDropdownOptions("ao"); /* activated */
+ liTable.initBatchUpdater(["item_count", "distribution_formula"]);
dojo.byId('acq-po-activated-on').innerHTML =
dojo.string.substitute(
} else {
/* These things only make sense for not-ordered-yet POs */
+ liTable.initBatchUpdater();
liTable.enableActionsDropdownOptions("po");
openils.Util.show("acq-po-zero-activate-label", "table-cell");
--- /dev/null
+Acquisitions Purchase Order and other Interface Improvements
+============================================================
+
+Feature Summary
+---------------
+
+The following features, which primarily affect the user interface layer,
+improve Acquisitions work flows.
+
+ * Avoid double-activation of POs
+ * Disable invoice and cancel options for pending POs
+ * Disable zero-copy checkbox for activated POs
+ * Disable new charges for activated POs
+ * Replace "Shelving Location" with Copy Location
+
+ * Rearranging "actions" drop-down
+ ** More consitency in actions applying to selected lineitems specifically
+ ** Things moved from the per-lineitem dropdown to the main one when
+ sensible.
+ ** Add to PO dialog added
+ ** You can no longer add lineitems to a PO if they're already on one.
+ ** Actions in dropdown now enabled/disabled differently depending on
+ the interface where it appears (PO vs Selection List vs Acq Search etc.)
+
+ * Batch update for line items
+ ** Apply updates to all copies of all selected line items at once
+ ** Relies on a middle layer method that streams back information that
+ would suit a more asynchronous display in the future (rather than
+ simply reloading the page upon success, which it does now)
+ ** For failure cases, specific information about which line item cannot
+ be updated, and why, is available to the client, although taking
+ best advantage of this information for user-friendly display is left
+ to the future.
+++ /dev/null
-Acquisitions Purchase Order Improvements
-========================================
-
-Feature Summary
----------------
-
-The following features, which primarily affect the user interface layer,
-improve Acquisitions work flows.
-
- * Avoid double-activation of POs
- * Disable invoice and cancel options for pending POs
- * Disable zero-copy checkbox for activated POs
- * Disable new charges for activated POs
- * Replace "Shelving Location" with Copy Location
-
- * Rearranging "actions" drop-down
- ** More consitency in actions applying to selected lineitems specifically
- ** Things moved from the per-lineitem dropdown to the main one when
- sensible.
- ** Add to PO dialog added
- ** You can no longer add lineitems to a PO if they're already on one.
- ** Actions in dropdown now enabled/disabled differently depending on
- the interface where it appears (PO vs Selection List vs Acq Search etc.)