Acq: Added a working LI search interface.
authorsenator <senator@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 12 Feb 2010 16:22:47 +0000 (16:22 +0000)
committersenator <senator@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Fri, 12 Feb 2010 16:22:47 +0000 (16:22 +0000)
There's more to come on this, but for now you can search LIs by state,
by related PO ordering agency, by any one attached attribute value, and even
by providing a file of search terms to match some attributes (ISBN in
particular).

This doesn't have paging yet, and will also need tweaked to enable
searching by more than one attribute at a time.

git-svn-id: svn://svn.open-ils.org/ILS/trunk@15518 dcc99617-32d9-48b4-a31d-7c20da2025e4

14 files changed:
Open-ILS/examples/fm_IDL.xml
Open-ILS/src/perlmods/OpenILS/Application/Acq/Lineitem.pm
Open-ILS/web/css/skin/default/acq.css
Open-ILS/web/js/dojo/openils/XUL.js
Open-ILS/web/js/dojo/openils/acq/nls/acq.js
Open-ILS/web/js/ui/default/acq/lineitem/search.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/acq/po/li_search.js [deleted file]
Open-ILS/web/opac/locale/en-US/lang.dtd
Open-ILS/web/templates/default/acq/lineitem/search.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/acq/po/li_search.tt2 [deleted file]
Open-ILS/web/templates/default/menu.tt2
Open-ILS/xul/staff_client/chrome/content/main/menu.js
Open-ILS/xul/staff_client/chrome/content/main/menu_frame_menus.xul
Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties

index b76e3b4..e718794 100644 (file)
@@ -5093,7 +5093,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                </links>
        </class>
 
-       <class id="acqliad" controller="open-ils.cstore open-ils.reporter-store" oils_obj:fieldmapper="acq::lineitem_attr_definition" oils_persist:tablename="acq.lineitem_attr_definition" reporter:label="Line Item Attribute Definition">
+       <class id="acqliad" controller="open-ils.cstore open-ils.reporter-store open-ils.pcrud" oils_obj:fieldmapper="acq::lineitem_attr_definition" oils_persist:tablename="acq.lineitem_attr_definition" reporter:label="Line Item Attribute Definition">
                <fields oils_persist:primary="id" oils_persist:sequence="acq.lineitem_attr_definition_id_seq">
                        <field reporter:label="Definition ID" name="id" reporter:datatype="id" />
                        <field reporter:label="Code" name="code" reporter:datatype="text" />
@@ -5101,6 +5101,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
                        <field reporter:label="Is Identifier?" name="ident" reporter:datatype="bool"/>
                </fields>
                <links/>
+               <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+                       <actions>
+                               <retrieve />
+                       </actions>
+               </permacrud>
        </class>
 
        <class id="acqlimad" controller="open-ils.cstore open-ils.reporter-store" oils_obj:fieldmapper="acq::lineitem_marc_attr_definition" oils_persist:tablename="acq.lineitem_marc_attr_definition" reporter:label="Line Item MARC Attribute Definition">
index 611ec83..4dc8cc7 100644 (file)
@@ -257,6 +257,131 @@ sub lineitem_search {
 
 
 __PACKAGE__->register_method(
+    method => "lineitem_search_by_attributes",
+    api_name => "open-ils.acq.lineitem.search.by_attributes",
+    stream => 1,
+    signature => {
+        desc => "Performs a search against lineitem_attrs",
+        params => [
+            {desc => "Authentication token", type => "string"},
+            {   desc => q/
+Search definition:
+    attr_value_pairs : list of pairs of (attr definition ID, attr value) where value can be scalar (fuzzy match) or array (exact match)
+    li_states        : list of lineitem states
+    po_agencies      : list of purchase order ordering agencies (org) ids
+
+At least one of these search terms is required.
+                /,
+                type => "object"},
+            {   desc => q/
+Options hash:
+    idlist      : if set, only return lineitem IDs
+    clear_marc  : if set, strip the MARC xml from the lineitem before delivery
+    flesh_attrs : flesh lineitem attributes;
+                /,
+                type => "object"}
+        ]
+    }
+);
+
+__PACKAGE__->register_method(
+    method => "lineitem_search_by_attributes",
+    api_name => "open-ils.acq.lineitem.search.by_attributes.ident",
+    stream => 1,
+    signature => {
+        desc => "Performs a search against lineitem_attrs where ident is true.".
+            "See open-ils.acq.lineitem.search.by_attributes for params."
+    }
+);
+
+sub lineitem_search_by_attributes {
+    my ($self, $conn, $auth, $search, $options) = @_;
+
+    my $e = new_editor(authtoken => $auth, xact => 1);
+    return $e->die_event unless $e->checkauth;
+    # XXX needs permissions consideration
+
+    return [] unless $search;
+    my $attr_value_pairs = $search->{attr_value_pairs};
+    my $li_states = $search->{li_states};
+    my $po_agencies = $search->{po_agencies}; # XXX if none, base it on perms
+
+    my $query = {
+        "select" => {"acqlia" => ["lineitem"]},
+        "from" => {
+            "acqlia" => {
+                "acqliad" => {"field" => "id", "fkey" => "definition"},
+                "jub" => {
+                    "field" => "id",
+                    "fkey" => "lineitem",
+                    "join" => {
+                        "acqpo" => {"field" => "id", "fkey" => "purchase_order"}
+                    }
+                }
+            }
+        }
+    };
+
+    my $where = {};
+    $where->{"+acqliad"} = {"ident" => "t"}
+        if $self->api_name =~ /\.ident/;
+
+    my $searched_for_something = 0;
+
+    if (ref $attr_value_pairs eq "ARRAY") {
+        $where->{"-or"} = [];
+        foreach (@$attr_value_pairs) {
+            next if @$_ != 2;
+            my ($def, $value) = @$_;
+            push @{$where->{"-or"}}, {
+                "-and" => {
+                    "attr_value" => (ref $value) ?
+                        $value : {"ilike" => "%" . $value . "%"},
+                    "definition" => $def
+                }
+            };
+        }
+        $searched_for_something = 1;
+    }
+
+    if ($li_states and @$li_states) {
+        $where->{"+jub"} = {"state" => $li_states};
+        $searched_for_something = 1;
+    }
+
+    if ($po_agencies and @$po_agencies) {
+        $where->{"+acqpo"} = {"ordering_agency" => $po_agencies};
+        $searched_for_something = 1;
+    }
+
+    if (not $searched_for_something) {
+        $e->rollback;
+        return new OpenILS::Event(
+            "BAD_PARAMS", note => "You have provided no search terms."
+        );
+    }
+
+    $query->{"where"} = $where;
+    use Data::Dumper;
+    $Data::Dumper::Indent = 0;
+    $logger->info("XXX LFW " . Dumper($query));
+    my $lis = $e->json_query($query);
+
+    for my $li_id_obj (@$lis) {
+        my $li_id = $li_id_obj->{"lineitem"};
+        if($options->{"idlist"}) {
+            $conn->respond($li_id);
+        } else {
+            $conn->respond(
+                retrieve_lineitem($self, $conn, $auth, $li_id, $options)
+            );
+        }
+    }
+    undef;
+}
+
+
+__PACKAGE__->register_method(
        method => 'lineitem_search_ident',
        api_name => 'open-ils.acq.lineitem.search.ident',
     stream => 1,
index 8926980..9c1c250 100644 (file)
 }
 #oils-acq-metapo-summary td { text-align: right; }
 
+/* li search page */
+h1.oils-acq-li-search { font-size: 150%;font-weight: bold;margin-bottom: 12px; }
+h2.oils-acq-li-search { font-size: 138%;font-weight: bold;margin-bottom: 11px; }
+h3.oils-acq-li-search { font-size: 125%;font-weight: bold;margin-bottom: 10px; }
+h4.oils-acq-li-search { font-size: 112%;font-weight: bold;margin-bottom: 9px; }
+#oils-acq-li-search-form-holder {border-bottom: 2px #666 inset; margin: 6px 0;}
+.oils-acq-li-search-form-row { margin: 6px 0; }
+input.oils-acq-li-search { margin: 0 12px; }
+label.oils-acq-li-search { margin: 0 12px; }
+span.oils-acq-li-search { margin: 0 12px; }
+span#records-up { font-weight: bold; }
+
 #acq-lit-table {width:100%}
 #acq-lit-table th {padding:5px; font-weight: bold; text-align:left;}
 #acq-lit-table td {padding:2px;}
index c9cde52..6a39d19 100644 (file)
@@ -49,6 +49,59 @@ if(!dojo._hasResource["openils.XUL"]) {
         }
         return true;
     }
-}
 
+    /* This class cuts down on the obscenely long incantations needed to
+     * use XPCOM components. */
+    openils.XUL.SimpleXPCOM = function() {};
+    openils.XUL.SimpleXPCOM.prototype = {
+        "FP": {
+            "iface": Components.interfaces.nsIFilePicker,
+            "cls": "@mozilla.org/filepicker;1"
+        },
+        "FIS": {
+            "iface": Components.interfaces.nsIFileInputStream,
+            "cls": "@mozilla.org/network/file-input-stream;1"
+        },
+        "SIS": {
+            "iface": Components.interfaces.nsIScriptableInputStream,
+            "cls": "@mozilla.org/scriptableinputstream;1"
+        },
+        "create": function(key) {
+            return Components.classes[this[key].cls].
+                createInstance(this[key].iface);
+        },
+        "getPrivilegeManager": function() {
+            return netscape.security.PrivilegeManager;
+        }
+    };
+
+    openils.XUL.contentFromFileOpenDialog = function(windowTitle) {
+        try {
+            var api = new openils.XUL.SimpleXPCOM();
+
+            /* The following enablePrivilege() call must happen at this exact
+             * level of scope -- not wrapped in another function -- otherwise
+             * it doesn't work. */
+            api.getPrivilegeManager().enablePrivilege("UniversalXPConnect");
 
+            var picker = api.create("FP");
+            picker.init(
+                window, windowTitle || "Upload File", api.FP.iface.modeOpen
+            );
+            if (picker.show() == api.FP.iface.returnOK && picker.file) {
+                var fis = api.create("FIS");
+                var sis = api.create("SIS");
+
+                fis.init(picker.file, 1 /* MODE_RDONLY */, 0, 0);
+                sis.init(fis);
+
+                return sis.read(-1);
+            } else {
+                return null;
+            }
+        } catch(E) {
+            alert(E);
+            return null;
+        }
+    };
+}
index 86c93a1..9077dfa 100644 (file)
@@ -9,5 +9,10 @@
     'DFA_NOT_ALL': "Could not record all of your applications of distribution forumulas.",
     'APPLY': "Apply",
     'RESET_FORMULAE': "Reset Formulas",
-    'OUT_OF_COPIES': "You have applied distribution formulas to every copy."
+    'OUT_OF_COPIES': "You have applied distribution formulas to every copy.",
+    'ONE_LI_ATTR_SEARCH_AT_A_TIME': "You cannot both type in an attribute value search and search for an uploaded file of terms at the same time.",
+    'LI_ATTR_SEARCH_CHOOSE_FILE': "Select file with search terms",
+    'LI_ATTR_SEARCH_TOO_LARGE': "That file is too large for this operation.",
+    'SELECT_AN_LI_ATTRIBUTE': "You must select an LI attribute.",
+    'NO_RESULTS': "No results."
 }
diff --git a/Open-ILS/web/js/ui/default/acq/lineitem/search.js b/Open-ILS/web/js/ui/default/acq/lineitem/search.js
new file mode 100644 (file)
index 0000000..00f4ba4
--- /dev/null
@@ -0,0 +1,190 @@
+dojo.require("dijit.form.Form");
+dojo.require("dijit.form.Button");
+dojo.require("dijit.form.RadioButton");
+dojo.require("dijit.form.TextBox");
+dojo.require("dijit.form.FilteringSelect");
+dojo.require("dojo.data.ItemFileReadStore");
+dojo.require("openils.User");
+dojo.require("openils.Util");
+dojo.require("openils.PermaCrud");
+dojo.require("openils.XUL");
+dojo.require("openils.widget.AutoFieldWidget");
+
+var _searchable_by_array = ["issn", "isbn", "upc"];
+var combinedAttrValueArray = [];
+var liTable;
+
+function prepareStateStore(pcrud) {
+    stateSelector.store = new dojo.data.ItemFileReadStore({
+        "data": {
+            "label": "description",
+            "identifier": "code",
+            "items": [
+                /* XXX i18n; Also, this list shouldn't be hardcoded here. */
+                {"code": "new", "description": "New"},
+                {"code": "on-order", "description": "On Order"},
+                {"code": "pending-order", "description": "Pending Order"}
+            ]
+        }
+    });
+}
+
+function prepareScalarSearchStore(pcrud) {
+    attrScalarDefSelector.store = new dojo.data.ItemFileReadStore({
+        "data": acqliad.toStoreData(
+            pcrud.search("acqliad", {"id": {"!=": null}})
+        )
+    });
+}
+
+function prepareArraySearchStore(pcrud) {
+    attrArrayDefSelector.store = new dojo.data.ItemFileReadStore({
+        "data": acqliad.toStoreData(
+            pcrud.search("acqliad", {"code": _searchable_by_array})
+        )
+    });
+}
+
+function prepareAgencySelector() {
+    new openils.widget.AutoFieldWidget({
+        "fmClass": "acqpo",
+        "fmField": "ordering_agency",
+        "parentNode": dojo.byId("agency_selector"),
+        "orgLimitPerms": ["VIEW_PURCHASE_ORDER"],
+        "dijitArgs": {"name": "agency", "required": false}
+    }).build();
+}
+
+function load() {
+    var pcrud = new openils.PermaCrud();
+
+    prepareStateStore(pcrud);
+    prepareScalarSearchStore(pcrud);
+    prepareArraySearchStore(pcrud);
+
+    prepareAgencySelector();
+
+    liTable = new AcqLiTable();
+    openils.Util.show("oils-acq-li-search-form-holder");
+}
+
+function toggleAttrSearchType(which, checked) {
+    /* This would be cooler with a slick dispatch table instead of branchy
+     * logic, but whatever... */
+    if (checked) {
+        if (which == "scalar") {
+            openils.Util.show("oils-acq-li-search-attr-scalar", "inline");
+            openils.Util.hide("oils-acq-li-search-attr-array");
+        } else if (which == "array") {
+            openils.Util.hide("oils-acq-li-search-attr-scalar");
+            openils.Util.show("oils-acq-li-search-attr-array", "inline");
+        } else {
+            openils.Util.hide("oils-acq-li-search-attr-scalar");
+            openils.Util.hide("oils-acq-li-search-attr-array");
+        }
+    }
+}
+
+var buildAttrSearchClause = {
+    "array": function(v) {
+        if (!v.array_def) {
+            throw new Error(localeStrings.SELECT_AN_LI_ATTRIBUTE);
+        }
+        return {
+            "attr_value_pairs":
+                [[Number(v.array_def), combinedAttrValueArray]] /* [[sic]] */
+        };
+    },
+    "scalar": function(v) {
+        if (!v.scalar_def) {
+            throw new Error(localeStrings.SELECT_AN_LI_ATTRIBUTE);
+        }
+        return {
+            "attr_value_pairs":
+                [[Number(v.scalar_def), v.scalar_value]] /* [[sic]] */
+        };
+    },
+    "none": function(v) {
+        //return {"attr_value_pairs": [[1, ""]]};
+        return {};
+    }
+};
+
+function naivelyParse(data) {
+    return data.split(/[\n, ]/).filter(function(o) {return o.length > 0; });
+}
+
+function clearTerms() {
+    combinedAttrValueArray = [];
+    dojo.byId("records-up").innerHTML = 0;
+}
+
+function loadTermsFromFile() {
+    var rawdata = openils.XUL.contentFromFileOpenDialog(
+        localeStrings.LI_ATTR_SEARCH_CHOOSE_FILE
+    );
+    if (!rawdata) {
+        return;
+    } else if (rawdata.length > 1024 * 128) {
+        /* FIXME 128k is completely arbitrary; needs researched for
+         * a sane limit and should also be made configurable. Further, if
+         * there's going to be a size limit, it'd be much better to apply
+         * it before reading in the file at all, not now. */
+        alert(localeStrings.LI_ATTR_SEARCH_TOO_LARGE);
+    } else {
+        try {
+            combinedAttrValueArray =
+                combinedAttrValueArray.concat(naivelyParse(rawdata));
+            dojo.byId("records-up").innerHTML = combinedAttrValueArray.length;
+        } catch (E) {
+            alert(E);
+        }
+    }
+}
+
+function buildSearchClause(values) {
+    var o = {};
+    if (values.state) o.li_states = [values.state];
+    if (values.agency) o.po_agencies = [Number(values.agency)];
+    return o;
+}
+
+function doSearch(values) {
+    var results_this_time = 0;
+    liTable.reset();
+    try {
+        fieldmapper.standardRequest(
+            ["open-ils.acq", "open-ils.acq.lineitem.search.by_attributes"], {
+                "params": [
+                    openils.User.authtoken,
+                    dojo.mixin(
+                        buildAttrSearchClause[values.attr_search_type](values),
+                        buildSearchClause(values)
+                    ),
+                    {
+                        "clear_marc": true, "flesh_attrs": true,
+                        "flesh_notes": true
+                    }
+                ],
+                "async": true,
+                "onresponse": function(r) {
+                    var li = openils.Util.readResponse(r);
+                    if (li) {
+                        results_this_time++;
+                        liTable.addLineitem(li);
+                        liTable.show("list");
+                    }
+                },
+                "oncomplete": function() {
+                    if (results_this_time < 1) {
+                        alert(localeStrings.NO_RESULTS);
+                    }
+                }
+            }
+        );
+    } catch (E) {
+        alert(E); // XXX
+    }
+}
+
+openils.Util.addOnLoad(load);
diff --git a/Open-ILS/web/js/ui/default/acq/po/li_search.js b/Open-ILS/web/js/ui/default/acq/po/li_search.js
deleted file mode 100644 (file)
index d099ed0..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-dojo.require('fieldmapper.Fieldmapper');
-dojo.require('dijit.ProgressBar');
-dojo.require('dijit.form.Form');
-dojo.require('dijit.form.TextBox');
-dojo.require('dijit.form.CheckBox');
-dojo.require('dijit.form.FilteringSelect');
-dojo.require('dijit.form.Button');
-dojo.require("dijit.Dialog");
-dojo.require('openils.Event');
-dojo.require('openils.Util');
-dojo.require('openils.acq.Lineitem');
-dojo.require('openils.acq.Provider');
-dojo.require('openils.acq.PO');
-dojo.require('openils.widget.OrgUnitFilteringSelect');
-
-var recvCount = 0;
-var createAssetsSelected = false;
-var createDebitsSelected = false;
-
-var lineitems = [];
-
-function drawForm() {
-    buildProviderSelect(providerSelector);
-}
-
-function buildProviderSelect(sel, oncomplete) {
-    openils.acq.Provider.createStore(
-        function(store) {
-            sel.store = new dojo.data.ItemFileReadStore({data:store});
-            if(oncomplete)
-                oncomplete();
-        },
-        'MANAGE_PROVIDER'
-    );
-}
-
-var liReceived;
-function doSearch(values) {
-    var search = {};
-    for(var v in values) {
-        var val = values[v];
-        if(val != null && val != '')
-            search[v] = val;
-    }
-
-    if(values.state == 'approved')
-        dojo.style('oils-acq-li-search-po-create', 'visibility', 'visible');
-    else
-        dojo.style('oils-acq-li-search-po-create', 'visibility', 'hidden');
-
-    //search = [search, {limit:searchLimit, offset:searchOffset}];
-    search = [search, {}];
-    options = {clear_marc:1, flesh_attrs:1};
-
-    liReceived = 0;
-    lineitems = [];
-    dojo.style('searchProgress', 'visibility', 'visible');
-    fieldmapper.standardRequest(
-        ['open-ils.acq', 'open-ils.acq.lineitem.search'],
-        {   async: true,
-            params: [openils.User.authtoken, search, options],
-            onresponse: handleResult,
-            oncomplete: viewList
-        }
-    );
-}
-
-function handleResult(r) {
-    var result = r.recv().content();
-    searchProgress.update({maximum: searchLimit, progress: ++liReceived});
-    lineitems.push(result);
-}
-
-function viewList() {
-    dojo.style('searchProgress', 'visibility', 'hidden');
-    dojo.style('oils-acq-li-search-result-grid', 'visibility', 'visible');
-    var store = new dojo.data.ItemFileWriteStore(
-        {data:jub.toStoreData(lineitems, null, 
-            {virtualFields:['estimated_price', 'actual_price']})});
-    var model = new dojox.grid.data.DojoData(
-        null, store, {rowsPerPage: 20, clientSort: true, query:{id:'*'}});
-    JUBGrid.populate(liGrid, model, lineitems);
-}
-
-function createPOFromLineitems(fields) {
-    var po = new acqpo();
-    po.provider(newPOProviderSelector.getValue());
-    createAssetsSelected = fields.create_assets;
-    createDebitsSelected = fields.create_debits;
-
-    if(fields.which == 'selected') {
-        // find the selected lineitems
-        var selected = liGrid.selection.getSelected();
-        var selList = [];
-        for(var idx = 0; idx < selected.length; idx++) {
-            var rowIdx = selected[idx];
-            var id = liGrid.model.getRow(rowIdx).id;
-            for(var i = 0; i < lineitems.length; i++) {
-                var li = lineitems[i];
-                if(li.id() == id && !li.purchase_order() && li.state() == 'approved')
-                    selList.push(lineitems[i]);
-            }
-        }
-    } else {
-        selList = lineitems;
-    }
-
-    if(selList.length == 0) return;
-
-    openils.acq.PO.create(po, 
-        function(poId) {
-            if(e = openils.Event.parse(poId)) 
-                return alert(e);
-            updateLiList(poId, selList);
-        }
-    );
-}
-
-function updateLiList(poId, selList) {
-    _updateLiList(poId, selList, 0);
-}
-
-function checkCreateDebits(poId) {
-    if(!createDebitsSelected)
-        return viewPO(poId);
-    fieldmapper.standardRequest(
-        ['open-ils.acq', 'open-ils.acq.purchase_order.debits.create'],
-        {   async: true,
-            params: [openils.User.authtoken, poId, {encumbrance:1}],
-            oncomplete : function(r) {
-                var total = r.recv().content();
-                if(e = openils.Event.parse(total))
-                    return alert(e);
-                viewPO(poId);
-            }
-        }
-    );
-}
-
-function viewPO(poId) {
-    location.href = 'view/' + poId;
-}
-
-function _updateLiList(poId, selList, idx) {
-    if(idx >= selList.length) {
-        if(createAssetsSelected)
-            return createAssets(poId);
-        else
-            return checkCreateDebits(poId);
-    }
-    var li = selList[idx];
-    li.purchase_order(poId);
-    li.state('in-process');
-    new openils.acq.Lineitem({lineitem:li}).update(
-        function(stat) {
-            _updateLiList(poId, selList, ++idx);
-        }
-    );
-}
-
-function createAssets(poId) {
-    searchProgress.update({progress: 0});
-    dojo.style('searchProgress', 'visibility', 'visible');
-
-    function onresponse(r) {
-        var stat = r.recv().content();
-        if(e = openils.Event.parse(stat))
-            return alert(e);
-        searchProgress.update({maximum: stat.total, progress: stat.progress});
-    }
-
-    function oncomplete(r) {
-        dojo.style('searchProgress', 'visibility', 'hidden');
-        checkCreateDebits(poId);
-    }
-
-    fieldmapper.standardRequest(
-        ['open-ils.acq','open-ils.acq.purchase_order.assets.create'],
-        {   async: true,
-            params: [openils.User.authtoken, poId],
-            onresponse : onresponse,
-            oncomplete : oncomplete
-        }
-    );
-}
-    
-
-openils.Util.addOnLoad(drawForm);
-
index 64df98f..68c0c8b 100644 (file)
 <!ENTITY staff.main.menu.acq.picklist.accesskey "L">
 <!ENTITY staff.main.menu.acq.bib_search.label "Title Search">
 <!ENTITY staff.main.menu.acq.bib_search.accesskey "T">
+<!ENTITY staff.main.menu.acq.li_search.label "Lineitem Search">
+<!ENTITY staff.main.menu.acq.li_search.accesskey "I">
 <!ENTITY staff.main.menu.acq.brief_record.label "New Brief Record">
 <!ENTITY staff.main.menu.acq.brief_record.accesskey "B">
 <!ENTITY staff.main.menu.acq.upload.label "Load Order Record">
diff --git a/Open-ILS/web/templates/default/acq/lineitem/search.tt2 b/Open-ILS/web/templates/default/acq/lineitem/search.tt2
new file mode 100644 (file)
index 0000000..1c2739b
--- /dev/null
@@ -0,0 +1,83 @@
+[% WRAPPER 'default/base.tt2' %]
+[% ctx.page_title = 'Lineitem Search' %]
+<script src="[% ctx.media_prefix %]/js/ui/default/acq/lineitem/search.js"></script>
+<!-- later: "[% ctx.page_args.0 %]" -->
+<div id="oils-acq-li-search-form-holder" class="hidden">
+    <h1 class="oils-acq-li-search">Lineitem Search</h1>
+    <form dojoType="dijit.form.Form" action="" method=""
+        id="oils-acq-li-search-form" jsId="searchForm">
+        <script type="dojo/method" event="onSubmit">
+            doSearch(this.getValues());
+            return false; /* no redirect */
+        </script>
+
+        <div class="oils-acq-li-search-form-row">
+            <label class="oils-acq-li-search" for="state_selector">
+                Lineitem state
+            </label>
+            <input class="oils-acq-li-search" name="state"
+                dojoType="dijit.form.FilteringSelect" required="false"
+                id="state_selector" jsId="stateSelector"
+                labelAttr="description" searchAttr="description"
+                />
+            <label class="oils-acq-li-search" for="agency_selector">
+                PO ordering agency
+            </label>
+            <input class="oils-acq-li-search" id="agency_selector" />
+        </div>
+        <div class="oils-acq-li-search-form-row">
+            <input class="oils-acq-li-search" dojoType="dijit.form.RadioButton"
+                name="attr_search_type" jsId="attrSearchTypeNone"
+                id="attr_search_type_none" value="none" checked="checked"
+                onChange="toggleAttrSearchType(this.value, this.checked);" />
+            <label for="attr_search_type_none" class="oils-acq-li-search">
+                No further attributes to search by
+            </label>
+        </div>
+        <div class="oils-acq-li-search-form-row">
+            <input class="oils-acq-li-search" dojoType="dijit.form.RadioButton"
+                name="attr_search_type" jsId="attrSearchTypeScalar"
+                id="attr_search_type_scalar" value="scalar"
+                onChange="toggleAttrSearchType(this.value, this.checked);" />
+            <label for="attr_search_type_scalar" class="oils-acq-li-search">
+                Search by one attribute value
+            </label>
+            <div id="oils-acq-li-search-attr-scalar" class="hidden">
+                <input class="oils-acq-li-search"
+                    name="scalar_def" dojoType="dijit.form.FilteringSelect"
+                    jsId="attrScalarDefSelector"
+                    labelAttr="description" searchAttr="description" />
+                <input class="oils-acq-li-search" name="scalar_value"
+                    dojoType="dijit.form.TextBox"/>
+            </div>
+        </div>
+        <div class="oils-acq-li-search-form-row">
+            <input class="oils-acq-li-search" dojoType="dijit.form.RadioButton"
+                name="attr_search_type" jsId="attrSearchTypeArray"
+                id="attr_search_type_array" value="array"
+                onChange="toggleAttrSearchType(this.value, this.checked);" />
+            <label for="attr_search_type_array" class="oils-acq-li-search">
+                Provide a file of search terms
+            </label>
+            <div id="oils-acq-li-search-attr-array" class="hidden">
+                <input class="oils-acq-li-search"
+                    name="array_def" dojoType="dijit.form.FilteringSelect"
+                    jsId="attrArrayDefSelector"
+                    labelAttr="description" searchAttr="description" />
+                <span class="oils-acq-li-search">
+                    <span id="records-up">0</span> term(s) prepared for search
+                </span>
+                <span class="oils-acq-li-search" dojoType="dijit.form.Button"
+                    onClick="loadTermsFromFile();">Add file</span>
+                <span class="oils-acq-li-search" dojoType="dijit.form.Button"
+                    onClick="clearTerms();">Clear loaded search terms</span>
+            </div>
+        </div>
+        <div class="oils-acq-li-search-form-row"
+            id="oils-acq-li-search-attr-submit">
+            <span dojoType="dijit.form.Button" type="submit">Search</span>
+        </div>
+    </form>
+</div>
+[% INCLUDE 'default/acq/common/li_table.tt2' %]
+[% END %]
diff --git a/Open-ILS/web/templates/default/acq/po/li_search.tt2 b/Open-ILS/web/templates/default/acq/po/li_search.tt2
deleted file mode 100644 (file)
index 58af3d3..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-[% WRAPPER default/base.tt2 %]
-    <script src='[% ctx.media_prefix %]/js/ui/default/acq/po/li_search.js'> </script>
-    <script>
-        var searchLimit = 20;
-        var searchOffset = 0;
-    </script>
-
-    <div id='oils-acq-li-search-block' class='container'>
-        <form dojoType='dijit.form.Form' action='' method=''>
-            <script type="dojo/method" event="onSubmit">
-                doSearch(this.getValues());
-                return false; /* don't redirect */
-            </script>
-            <table class='oils-acq-basic-form-table'>
-                <tr>
-                    <td><label for='state'>State</label></td>
-                    <td>
-                        <select dojoType='dijit.form.FilteringSelect' name='state'>
-                            <option value='new'>New</option>
-                            <option value='approved'>Approved</option>
-                            <option value='in-process'>In Process</option>
-                            <option value='received'>Received</option>
-                        </select>
-                    </td>
-                </tr>
-                <tr>
-                    <td><label for='provider'>Provider</label></td>
-                    <td>
-                        <select dojoType='dijit.form.FilteringSelect' name='provider' 
-                            labalAttr='code' searchAttr='code' jsId='providerSelector'>
-                        </select>
-                    </td>
-                </tr>
-                <tr>
-                    <td colspan='2'><div dojoType='dijit.form.Button' type='submit'>Search</div></td>
-                </tr>
-            </table>
-        </form>
-    </div>
-
-    <div id='oils-acq-li-search-progress'>
-        <div dojoType="dijit.ProgressBar" style="width:300px" jsId="searchProgress" id="searchProgress"></div>
-    </div>
-    <script>dojo.style('searchProgress', 'visibility', 'hidden');</script>
-
-    <div dojoType="dijit.form.DropDownButton" id='oils-acq-li-search-po-create'>
-        <span>Create PO</span>
-        <div dojoType="dijit.TooltipDialog" execute="createPOFromLineitems(arguments[0]);">
-            <script type='dojo/connect' event='onOpen'>
-                buildProviderSelect(newPOProviderSelector, 
-                    function() {
-                        newPOProviderSelector.setValue(providerSelector.getValue());
-                    }
-                );
-                new openils.User().buildPermOrgSelector('CREATE_PURCHASE_ORDER', orderingAgencySelect);
-            </script>
-            <table class='dijitTooltipTable'>
-                <tr>
-                    <td colspan='2'>
-                        <input dojoType="dijit.form.RadioButton" name="which" type='radio' checked='checked' value='selected'/>
-                        <label for="name">For selected items</label>
-                        <input dojoType="dijit.form.RadioButton" name="which" type='radio' value='all'/>
-                        <label for="name">For all items</label>
-                    </td>
-                </tr>
-                <tr>
-                    <td><label for="name">Provider: </label></td>
-                    <td>
-                        <input jsId='newPOProviderSelector' name="provider" 
-                            dojoType="dijit.form.FilteringSelect" searchAttr='code' labelAttr='code'/>
-                    </td>
-                </tr>
-                <tr>
-                    <td><label for="name">Ordering Agency:</label></td>
-                    <td>
-                        <input dojoType="openils.widget.OrgUnitFilteringSelect" jsId='orderingAgencySelect'
-                            searchAttr="shortname" name="ordering_agency" autocomplete="true" labelAttr='shortname'> </input>
-                    </td>
-                </tr>
-                <tr>
-                    <td><label for="create_assets">Generate Bib/Copy Data</label></td>
-                    <td>
-                        <input name='create_assets' dojoType='dijit.form.CheckBox' checked='checked'> </input>
-                    </td>
-                </tr>
-                <tr>
-                    <td><label for="create_debits">Encumber funds</label></td>
-                    <td>
-                        <input name='create_debits' dojoType='dijit.form.CheckBox' checked='checked'> </input>
-                    </td>
-                </tr>
-                <tr>
-                    <td colspan='2' align='center'>
-                        <button dojoType='dijit.form.Button' type="submit">Create</button>
-                    </td>
-                </tr>
-            </table>
-        </div>
-    </div> 
-    <script>dojo.style('oils-acq-li-search-po-create', 'visibility', 'hidden');</script>
-    <div id='oils-acq-li-search-result-grid' style='height:100%'>
-        [% grid_jsid = 'liGrid'; domprefix = 'oils-acq-li-search' %]
-        [% INCLUDE 'default/acq/common/jubgrid.tt2' %]
-    </div>
-    <script>dojo.style('oils-acq-li-search-result-grid', 'visibility', 'hidden');</script>
-[% END %]
-
-
index 66ca1f2..7f21b4c 100644 (file)
@@ -50,7 +50,7 @@
                             PO Search
                         </div>
                         <div dojoType="dijit.MenuItem" iconClass="dijitEditorIcon dijitEditorIconCopy"
-                            onClick="location.href = '[% ctx.base_path %]/acq/po/li_search';">
+                            onClick="location.href = '[% ctx.base_path %]/acq/lineitem/search';">
                             Lineitem Search
                         </div>
                         <!-- XXX 
index 9085913..4ca01dd 100644 (file)
@@ -671,6 +671,10 @@ main.menu.prototype = {
                 ['oncommand'],
                 function() { open_eg_web_page('acq/picklist/bib_search', 'menu.cmd_acq_bib_search.tab'); }
             ],
+            'cmd_acq_li_search' : [
+                ['oncommand'],
+                function() { open_eg_web_page('acq/lineitem/search', 'menu.cmd_acq_li_search.tab'); }
+            ],
             'cmd_acq_new_brief_record' : [
                 ['oncommand'],
                 function() { open_eg_web_page('acq/picklist/brief_record', 'menu.cmd_acq_new_brief_record.tab'); }
index 49ad231..54bdf79 100644 (file)
@@ -80,6 +80,7 @@
     <command id="cmd_acq_upload" />
     <command id="cmd_acq_view_po" />
     <command id="cmd_acq_bib_search" />
+    <command id="cmd_acq_li_search" />
     <command id="cmd_acq_new_brief_record" />
     <command id="cmd_acq_view_fund" />
     <command id="cmd_acq_view_funding_source" />
     <menupopup id="main.menu.acq.popup">
         <menuitem label="&staff.main.menu.acq.picklist.label;" accesskey="&staff.main.menu.acq.picklist.accesskey;" command="cmd_acq_view_picklist"/>
         <menuitem label="&staff.main.menu.acq.bib_search.label;" accesskey="&staff.main.menu.acq.bib_search.accesskey;" command="cmd_acq_bib_search"/>
+        <menuitem label="&staff.main.menu.acq.li_search.label;" accesskey="&staff.main.menu.acq.li_search.accesskey;" command="cmd_acq_li_search"/>
         <menuitem label="&staff.main.menu.acq.upload.label;" accesskey="&staff.main.menu.acq.upload.accesskey;" command="cmd_acq_upload"/>
         <menuitem label="&staff.main.menu.acq.brief_record.label;" accesskey="&staff.main.menu.acq.brief_record.accesskey;" command="cmd_acq_new_brief_record"/>
         <menuseparator />
index 42df113..4a573e1 100644 (file)
@@ -222,6 +222,7 @@ menu.cmd_local_admin_cash_reports.tab=Cash Reports
 menu.cmd_local_admin_transit_list.tab=Transits
 menu.cmd_acq_view_picklist.tab=Selection Lists
 menu.cmd_acq_bib_search.tab=Title Search
+menu.cmd_acq_li_search.tab=Lineitem Search
 menu.cmd_acq_upload.tab=Load Order Record
 menu.cmd_acq_new_brief_record.tab=New Brief Record
 menu.cmd_acq_view_po.tab=Purchase Orders