From 98028342870b2d5721e9043d42393c588d828604 Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Wed, 30 Jul 2014 15:02:22 -0400 Subject: [PATCH] LP#1350371 PO name on create w/ dupe detect Adds support for entering a PO name at PO creation time, both from the picklist page and from the PO create page. If a name is entered which matches the name of an existing PO at or below the ordering agency, a link to the matching PO is shown and the user is prevented from creating the PO until the name is changed or cleared. Signed-off-by: Bill Erickson Signed-off-by: Kathy Lussier Signed-off-by: Mike Rylander --- .../lib/OpenILS/Application/Acq/Order.pm | 1 + .../src/templates/acq/common/li_table.tt2 | 13 +- Open-ILS/web/js/dojo/openils/acq/nls/acq.js | 5 +- .../web/js/dojo/openils/widget/EditPane.js | 2 +- .../openils/widget/FilteringTreeSelect.js | 6 + .../web/js/ui/default/acq/common/li_table.js | 84 ++++++++++- Open-ILS/web/js/ui/default/acq/po/create.js | 131 +++++++++++++++++- 7 files changed, 234 insertions(+), 8 deletions(-) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm index 4dc88af993..12b8def750 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Acq/Order.pm @@ -1803,6 +1803,7 @@ sub create_purchase_order_api { $pargs{provider} = $po->provider if $po->provider; $pargs{ordering_agency} = $po->ordering_agency if $po->ordering_agency; $pargs{prepayment_required} = $po->prepayment_required if $po->prepayment_required; + $pargs{name} = $po->name if $po->name; my $vandelay = $args->{vandelay}; $po = create_purchase_order($mgr, %pargs) or return $e->die_event; diff --git a/Open-ILS/src/templates/acq/common/li_table.tt2 b/Open-ILS/src/templates/acq/common/li_table.tt2 index 533a2ca369..2239689739 100644 --- a/Open-ILS/src/templates/acq/common/li_table.tt2 +++ b/Open-ILS/src/templates/acq/common/li_table.tt2 @@ -460,6 +460,14 @@ [% l('Ordering Agency') %]
+ + [% l('Name (optional)') %] +
+ + + [% l('This name is used by another PO') %] + [% l('View PO') %] + [% l('Provider') %]
@@ -481,9 +489,12 @@ - +
[% l('Submit') %]
+ +
[% l('Cancel') %]
+ diff --git a/Open-ILS/web/js/dojo/openils/acq/nls/acq.js b/Open-ILS/web/js/dojo/openils/acq/nls/acq.js index 674840c9c7..990260a8e4 100644 --- a/Open-ILS/web/js/dojo/openils/acq/nls/acq.js +++ b/Open-ILS/web/js/dojo/openils/acq/nls/acq.js @@ -99,5 +99,8 @@ "ACQ_SEARCH_CLASS_ABBR_acqinv": "I", "ACQ_SEARCH_CLASS_ABBR_acqlid": "LID", "ACQ_SEARCH_CLASS_ABBR_acqlia": "LIA", - "NO_LI_GENERAL" : "You have not selected any (suitable) line items." + "NO_LI_GENERAL" : "You have not selected any (suitable) line items.", + "DUPE_PO_NAME_MSG" : "This name is already in use by another PO", + "DUPE_PO_NAME_LINK" : "View PO", + "PO_NAME_OPTIONAL" : "${0} (optional)" } diff --git a/Open-ILS/web/js/dojo/openils/widget/EditPane.js b/Open-ILS/web/js/dojo/openils/widget/EditPane.js index a3d36c0df2..0e14144f8e 100644 --- a/Open-ILS/web/js/dojo/openils/widget/EditPane.js +++ b/Open-ILS/web/js/dojo/openils/widget/EditPane.js @@ -199,7 +199,7 @@ if(!dojo._hasResource['openils.widget.EditPane']) { if(this.hideSaveButton) return; - new dijit.form.Button({ + this.saveButton = new dijit.form.Button({ label:this.nls.SAVE, onClick: function() {self.performAutoEditAction();} }, applySpan); diff --git a/Open-ILS/web/js/dojo/openils/widget/FilteringTreeSelect.js b/Open-ILS/web/js/dojo/openils/widget/FilteringTreeSelect.js index 7791369020..649578120e 100644 --- a/Open-ILS/web/js/dojo/openils/widget/FilteringTreeSelect.js +++ b/Open-ILS/web/js/dojo/openils/widget/FilteringTreeSelect.js @@ -28,6 +28,12 @@ if(!dojo._hasResource["openils.widget.FilteringTreeSelect"]){ disableQuery : null, tree : null, + construct : function(args) { + if (args && args.dijitArgs && args.dijitArgs.onChange) { + dojo.connect(this, 'onChange', args.dijitArgs.onChange); + } + }, + startup : function() { this.tree = (typeof this.tree == 'string') ? dojox.jsonPath.query(window, '$.' + this.tree, {evalType:"RESULT"}) : this.tree; diff --git a/Open-ILS/web/js/ui/default/acq/common/li_table.js b/Open-ILS/web/js/ui/default/acq/common/li_table.js index af9e29ad42..2a2a2ff329 100644 --- a/Open-ILS/web/js/ui/default/acq/common/li_table.js +++ b/Open-ILS/web/js/ui/default/acq/common/li_table.js @@ -122,6 +122,9 @@ function AcqLiTable() { this.selectedIndex = 0; }; + acqLitCreatePoCancel.onClick = function() { + acqLitPoCreateDialog.hide(); + } acqLitCreatePoSubmit.onClick = function() { if (!self.createPoProviderSelector.attr("value") || !self.createPoAgencySelector.attr("value")) { @@ -3270,6 +3273,8 @@ function AcqLiTable() { po.provider(this.createPoProviderSelector.attr("value")); po.ordering_agency(this.createPoAgencySelector.attr("value")); po.prepayment_required(fields.prepayment_required[0] ? true : false); + var name = this.createPoNameInput.attr('value'); + if (name) po.name(name); // avoid name="" // if we're creating assets, delay the asset creation // until after the PO is created. This will allow us to @@ -3522,6 +3527,67 @@ function AcqLiTable() { widget.build(function(w) { self.createPoProviderSelector = w; }); } + this.createPoCheckDupes = function() { + var org = self.createPoAgencySelector.attr('value'); + var name = self.createPoNameInput.attr('value'); + openils.Util.hide('acq-dupe-po-name'); + + if (!name) { + acqLitCreatePoSubmit.attr('disabled', false); + return; + } + + acqLitCreatePoSubmit.attr('disabled', true); + var orgs = fieldmapper.aou.descendantNodeList(org, true); + new openils.PermaCrud().search('acqpo', + {name : name, ordering_agency : orgs}, + {async : true, oncomplete : function(r) { + var po = openils.Util.readResponse(r); + + if (po && (po = po[0])) { + + var link = dojo.byId('acq-dupe-po-link'); + openils.Util.show('acq-dupe-po-name', 'table-row'); + var dupe_path = '/acq/po/view/' + po.id(); + + if (window.xulG) { + + if (window.IAMBROWSER) { + // TODO: integration + + } else { + // XUL client + link.onclick = function() { + + var loc = xulG.url_prefix('XUL_BROWSER?url=') + + window.encodeURIComponent( + xulG.url_prefix('EG_WEB_BASE' + dupe_path) + ); + + xulG.new_tab(loc, + {tab_name: '', browser:false}, + { + no_xulG : false, + show_nav_buttons : true, + show_print_button : true, + } + ); + } + } + + } else { + link.onclick = function() { + window.open(oilsBasePath + dupe_path, '_blank').focus(); + } + } + + } else { + acqLitCreatePoSubmit.attr('disabled', false); + } + }} + ); + } + if (!this.createPoAgencySelector) { var widget = new openils.widget.AutoFieldWidget({ "fmField": "ordering_agency", @@ -3529,7 +3595,23 @@ function AcqLiTable() { "parentNode": dojo.byId("acq-lit-po-agency"), "orgLimitPerms": ["CREATE_PURCHASE_ORDER"], }); - widget.build(function(w) { self.createPoAgencySelector = w; }); + widget.build(function(w) { + self.createPoAgencySelector = w; + dojo.connect(w, 'onChange', self.createPoCheckDupes); + }); + } + + if (!this.createPoNameInput) { + var widget = new openils.widget.AutoFieldWidget({ + "fmField": "name", + "fmClass": "acqpo", + "parentNode": dojo.byId("acq-lit-po-name"), + "orgLimitPerms": ["CREATE_PURCHASE_ORDER"], + }); + widget.build(function(w) { + self.createPoNameInput = w; + dojo.connect(w, 'onChange', self.createPoCheckDupes); + }); } }; diff --git a/Open-ILS/web/js/ui/default/acq/po/create.js b/Open-ILS/web/js/ui/default/acq/po/create.js index 181fc11da7..723603ef75 100644 --- a/Open-ILS/web/js/ui/default/acq/po/create.js +++ b/Open-ILS/web/js/ui/default/acq/po/create.js @@ -1,7 +1,13 @@ dojo.require("openils.widget.EditDialog"); dojo.require("openils.widget.EditPane"); +dojo.require("openils.PermaCrud"); +dojo.require("openils.User"); +dojo.require("fieldmapper.OrgUtils"); -var editDialog; +dojo.requireLocalization('openils.acq', 'acq'); +var localeStrings = dojo.i18n.getLocalization('openils.acq', 'acq'); + +var editDialog, selectedAgency, currentName; function toPoListing() { location.href = oilsBasePath + "/acq/search/unified?ca=po"; @@ -13,6 +19,111 @@ function toOnePo(id) { openils.Util.addOnLoad( function() { + + // apply here in case the selector never changes + // (i.e. no onchange fires). + selectedAgency = openils.User.user.ws_ou(); + + // called each time the PO name changes + function name_changed(new_name) { + currentName = new_name; + + console.debug('checking for PO name collision + "' + + currentName + '" at ' + selectedAgency); + + if (!new_name) { // name cleared + editDialog.editPane.saveButton.attr('disabled', false); + return; + } + + // disable Save option pending confirmation of uniqueness + editDialog.editPane.saveButton.attr('disabled', true); + + var orgs = fieldmapper.aou.descendantNodeList(selectedAgency, true); + new openils.PermaCrud().search('acqpo', + {name : new_name, ordering_agency : orgs}, + {async : true, oncomplete : function(r) { + var po = openils.Util.readResponse(r); + var tbody = editDialog.editPane.table.getElementsByTagName('tbody')[0]; + + // remove any previous dupe warning row + dojo.forEach(tbody.getElementsByTagName('tr'), function(row) { + if (row) { // sometimes row is undefined?? + if (row.getAttribute('dupe-po-row')) + tbody.removeChild(row); + } + }); + + if (po && (po = po[0])) { + // duplicate found. add info row to create dialog + + var parent_row; + dojo.forEach(tbody.getElementsByTagName('tr'), function(row) { + if (row.getAttribute('fmfield') == 'name') + parent_row = row; + }); + + var new_tr = dojo.create('tr', {'dupe-po-row' : 1}); + var link = dojo.create('a', { + href : 'javascript:;', + innerHTML : localeStrings.DUPE_PO_NAME_LINK + }); + + var dupe_path = '/acq/po/view/' + po.id(); + + if (window.xulG) { + + if (window.IAMBROWSER) { + // TODO: integration + + } else { + // XUL client + link.onclick = function() { + + var loc = xulG.url_prefix('XUL_BROWSER?url=') + + window.encodeURIComponent( + xulG.url_prefix('EG_WEB_BASE' + dupe_path) + ); + + xulG.new_tab(loc, + {tab_name: '', browser:false}, + { + no_xulG : false, + show_nav_buttons : true, + show_print_button : true, + } + ); + } + } + + } else { + link.onclick = function() { + window.open(oilsBasePath + dupe_path, '_blank').focus(); + } + } + + new_tr.appendChild(dojo.create('td', + {innerHTML : localeStrings.DUPE_PO_NAME_MSG})); + var link_td = dojo.create('td'); + link_td.appendChild(link); + new_tr.appendChild(link_td); + tbody.insertBefore(new_tr, parent_row.nextSibling); + + } else { + editDialog.editPane.saveButton.attr('disabled', false); + } + }} + ); + } + + function agency_changed(val) { + selectedAgency = val; + if (currentName) { + // if the ordering agency changes, re-run the dupe name check. + name_changed(currentName); + } + } + editDialog = new openils.widget.EditDialog({ "editPane": new openils.widget.EditPane({ "fmObject": new acqpo(), @@ -22,13 +133,17 @@ openils.Util.addOnLoad( * much advantage over a hardcoded interface. */ "suppressFields": [ "create_time", "edit_time", "editor", "order_date", - "owner", "cancel_reason", "creator", "state", "name" + "owner", "cancel_reason", "creator", "state" ], - "fieldOrder": ["ordering_agency", "provider"], + "fieldOrder": ["ordering_agency", "name", "provider"], "mode": "create", overrideWidgetArgs : { provider : { dijitArgs : { store_options : { base_filter : { active :"t" } } } }, - ordering_agency : { orgDefaultsToWs : true } + ordering_agency : { + orgDefaultsToWs : true, + dijitArgs : {onChange : agency_changed} + }, + name : {dijitArgs : {onChange : name_changed}} }, "onSubmit": function(po) { fieldmapper.standardRequest( @@ -54,5 +169,13 @@ openils.Util.addOnLoad( }); editDialog.startup(); editDialog.show(); + + // modify the label of the 'name' field to make it more clear it's optional + var row = dojo.query('[fmfield=name]', editDialog.editPane.table)[0]; + var name_td = row.getElementsByTagName('td')[0]; + name_td.innerHTML = dojo.string.substitute( + localeStrings.PO_NAME_OPTIONAL, + [name_td.innerHTML] + ); } ); -- 2.43.2