Serials: dojo/autogrid-based scaffolding for building serials objects
authorsenator <senator@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Sun, 12 Sep 2010 19:03:01 +0000 (19:03 +0000)
committersenator <senator@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Sun, 12 Sep 2010 19:03:01 +0000 (19:03 +0000)
Accessible from the staff client OPAC browser's "Actions for this Record" menu
as "Alternate Serial Control", these minimalist interfaces should support a
workflow by which the user can create a subscription and its related parts
(distributions, streams, etc), and get things going in a quick and dirty way
while the existing Serial Control View continues to develop.

Some notable differences in orientation between this and the existing
interface work include:
    - The disuse of call numbers on distributions, instead favoring call number
    application to items by issuance at receive time (i.e., all copies of
    the Sep 2010 issue of Popular Mechanics share a call number rather than
    all copies of Popular Mechanics, any issue, at a given library sharing a
    call number).
    - Lack of attention to binding (although the batch receive interface will
    treat each item as a single bound unit, for barcoding, or will avoid
    creating units altogether if you don't want to barcode your serials).

If this doesn't sound like the way you would do serials, I'd definitely
recommend sticking with Serials Control View and ignoring these interfaces.
Dan Wells' interface work promises broader functionality in the long run.

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

21 files changed:
Open-ILS/examples/fm_IDL.xml
Open-ILS/web/css/skin/default.css
Open-ILS/web/css/skin/default/serial.css [new file with mode: 0644]
Open-ILS/web/js/dojo/openils/XUL.js
Open-ILS/web/js/ui/default/serial/list_stream.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/serial/list_subscription.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/serial/subscription.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/serial/subscription/caption_and_pattern.js [new file with mode: 0644]
Open-ILS/web/js/ui/default/serial/subscription/issuance.js [new file with mode: 0644]
Open-ILS/web/opac/locale/en-US/lang.dtd
Open-ILS/web/templates/default/serial/list_stream.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/serial/list_subscription.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/serial/subscription.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/serial/subscription/caption_and_pattern.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/serial/subscription/distribution.tt2 [new file with mode: 0644]
Open-ILS/web/templates/default/serial/subscription/issuance.tt2 [new file with mode: 0644]
Open-ILS/xul/staff_client/chrome/content/cat/opac.js
Open-ILS/xul/staff_client/chrome/content/cat/opac.xul
Open-ILS/xul/staff_client/chrome/locale/en-US/offline.properties
Open-ILS/xul/staff_client/server/serial/batch_receive.js
Open-ILS/xul/staff_client/server/serial/pattern_wizard_overlay.xul

index d15cda0..eca8ba3 100644 (file)
@@ -3170,12 +3170,24 @@ SELECT  usr,
                        <link field="subscription" reltype="has_a" key="id" map="" class="ssub"/>
                </links>
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+                       <actions>
+                               <create permission="ADMIN_SERIAL_CAPTION_PATTERN">
+                                       <context link="subscription" field="owning_lib" />
+                               </create>
+                               <retrieve />
+                               <update permission="ADMIN_SERIAL_CAPTION_PATTERN">
+                                       <context link="subscription" field="owning_lib" />
+                               </update>
+                               <delete permission="ADMIN_SERIAL_CAPTION_PATTERN">
+                                       <context link="subscription" field="owning_lib" />
+                               </delete>
+                       </actions>
                </permacrud>
        </class>
 
        <class id="ssub" controller="open-ils.cstore open-ils.pcrud" oils_obj:fieldmapper="serial::subscription" oils_persist:tablename="serial.subscription" reporter:label="Subscription">
                <fields oils_persist:primary="id" oils_persist:sequence="serial.subscription_id_seq">
-                       <field reporter:label="Id" name="id" reporter:datatype="id"/>
+                       <field reporter:label="ID" name="id" reporter:datatype="id"/>
                        <field reporter:label="Owning Library" name="owning_lib" reporter:datatype="org_unit"/>
                        <field reporter:label="Start Date" name="start_date" reporter:datatype="timestamp"/>
                        <field reporter:label="End Date" name="end_date" reporter:datatype="timestamp"/>
@@ -3197,7 +3209,7 @@ SELECT  usr,
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
                                <create permission="ADMIN_SERIAL_SUBSCRIPTION" context_field="owning_lib"/>
-                               <retrieve permission="VIEW_SERIAL_SUBSCRIPTION" context_field="owning_lib"/>
+                               <retrieve />
                                <update permission="ADMIN_SERIAL_SUBSCRIPTION" context_field="owning_lib"/>
                                <delete permission="ADMIN_SERIAL_SUBSCRIPTION" context_field="owning_lib"/>
                        </actions>
@@ -3227,7 +3239,7 @@ SELECT  usr,
                        <field reporter:label="ID" name="id" reporter:datatype="id"/>
                        <field reporter:label="Legacy Record Entry" name="record_entry" reporter:datatype="link"/>
                        <field reporter:label="Subscription" name="subscription" reporter:datatype="link"/>
-                       <field reporter:label="Holding Lib" name="holding_lib" reporter:datatype="link"/>
+                       <field reporter:label="Holding Lib" name="holding_lib" reporter:datatype="org_unit"/>
                        <field reporter:label="Label" name="label" reporter:datatype="text"/>
                        <field reporter:label="Receive Call Number" name="receive_call_number" reporter:datatype="link"/>
                        <field reporter:label="Receive Unit Template" name="receive_unit_template" reporter:datatype="link"/>
@@ -3257,10 +3269,10 @@ SELECT  usr,
                </links>
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
                        <actions>
-                               <create/>
-                               <retrieve/>
-                               <update/>
-                               <delete/>
+                               <create permission="ADMIN_SERIAL_DISTRIBUTION" context_field="holding_lib" />
+                               <retrieve />
+                               <update permission="ADMIN_SERIAL_DISTRIBUTION" context_field="holding_lib" />
+                               <delete permission="ADMIN_SERIAL_DISTRIBUTION" context_field="holding_lib" />
                        </actions>
                </permacrud>
        </class>
@@ -3299,6 +3311,18 @@ SELECT  usr,
                        <link field="distribution" reltype="has_a" key="id" map="" class="sdist"/>
                </links>
                <permacrud xmlns="http://open-ils.org/spec/opensrf/IDL/permacrud/v1">
+                       <actions>
+                               <create permission="ADMIN_SERIAL_STREAM">
+                                       <context link="distribution" field="holding_lib" />
+                               </create>
+                               <retrieve />
+                               <update permission="ADMIN_SERIAL_STREAM">
+                                       <context link="distribution" field="holding_lib" />
+                               </update>
+                               <delete permission="ADMIN_SERIAL_STREAM">
+                                       <context link="distribution" field="holding_lib" />
+                               </delete>
+                       </actions>
                </permacrud>
        </class>
 
index 5ea73e9..a7ab2d6 100644 (file)
@@ -1,6 +1,7 @@
 /* import the default css for the install applications */
 @import "default/acq.css";
 @import "default/admin.css";
+@import "default/serial.css";
 /* import the dojo CSS */
 @import "/js/dojo/dojo/resources/dojo.css";
 @import "/js/dojo/dijit/themes/tundra/tundra.css";
diff --git a/Open-ILS/web/css/skin/default/serial.css b/Open-ILS/web/css/skin/default/serial.css
new file mode 100644 (file)
index 0000000..8322252
--- /dev/null
@@ -0,0 +1,23 @@
+.oils-serial-header { margin-bottom: 20px; }
+.oils-serial-tab-container { height: 600px; }
+.lesser { margin-top: 2px !important }
+.lesser div:first-child { font-size: 110% !important; }
+.lesser div:last-child { margin-right: 16px; }
+#scap_editor th {
+    font-weight: bold;
+    background-color: #ccc;
+    padding: 2px 8px;
+}
+#scap_editor td { padding: 2px 8px; }
+#scap_editor tr[changed="true"] td { background-color: #fc9; }
+#scap_editor [name="remover"] button { color: red; font-weight: bold; }
+#scap_editor tfoot td { text-align: center; padding-top: 24px; }
+#scap_editor td[name] { text-align: center; }
+.serial-dialog-table tr > * { padding-bottom: 1em; }
+.serial-dialog-table th { text-align: left; padding-right: 1em; }
+.serial-dialog-table tr:last-child td { text-align: center; }
+.serial-additional-controls {
+    text-align: right;
+    margin-right: 16px;
+    padding: 8px 0;
+}
index 6c26acd..692097e 100644 (file)
@@ -33,6 +33,27 @@ if(!dojo._hasResource["openils.XUL"]) {
         xulG.new_tab(path, tabInfo, options);
     }
 
+    openils.XUL.newTabEasy = function(url, tab_name, extra_content_params) {
+        var content_params = {
+            "session": openils.User.authtoken,
+            "authtime": openils.User.authtime
+        };
+
+        ["url_prefix", "new_tab", "set_tab", "close_tab", "new_patron_tab",
+            "set_patron_tab", "volume_item_creator", "get_new_session",
+            "holdings_maintenance_tab", "set_tab_name", "open_chrome_window",
+            "url_prefix", "network_meter", "page_meter", "set_statusbar",
+            "set_help_context"
+        ].forEach(function(k) { content_params[k] = xulG[k]; });
+
+        if (extra_content_params)
+            dojo.mixin(content_params, extra_content_params);
+
+        xulG.new_tab(
+            xulG.url_prefix(url), {"tab_name": tab_name}, content_params
+        );
+    };
+
     /**
      * @return bool True if a new session was successfully created, false otherwise.
      */
diff --git a/Open-ILS/web/js/ui/default/serial/list_stream.js b/Open-ILS/web/js/ui/default/serial/list_stream.js
new file mode 100644 (file)
index 0000000..e61127a
--- /dev/null
@@ -0,0 +1,72 @@
+dojo.require("dijit.form.Button");
+dojo.require("dijit.form.NumberSpinner");
+dojo.require("dijit.form.TextBox");
+dojo.require("openils.widget.AutoGrid");
+dojo.require("openils.widget.ProgressDialog");
+dojo.require("openils.PermaCrud");
+
+var pcrud;
+
+function format_routing_label(routing_label) {
+    return routing_label ? routing_label : "[None]";
+}
+
+function load_sstr_grid() {
+    sstr_grid.overrideEditWidgets.distribution =
+        new dijit.form.TextBox({"disabled": true, "value": dist_id});
+
+    sstr_grid.resetStore();
+    sstr_grid.loadAll(
+        {"order_by": {"ssub": "start_date DESC"}},
+        {"distribution": dist_id}
+    );
+}
+
+function load_sdist_display() {
+    pcrud.retrieve(
+        "sdist", dist_id, {
+            "onresponse": function(r) {
+                if (r = openils.Util.readResponse(r)) {
+                    dojo.byId("sdist_label_here").innerHTML = r.label();
+                    load_sdist_org_unit_display(r);
+                }
+            }
+        }
+    );
+}
+
+function load_sdist_org_unit_display(dist) {
+    dojo.byId("sdist_org_unit_name_here").innerHTML =
+        aou.findOrgUnit(dist.holding_lib()).name();
+}
+
+function create_many_streams(fields) {
+    var streams = [];
+    for (var i = 0; i < fields.quantity; i++) {
+        var stream = new sstr();
+        stream.distribution(dist_id);
+        streams.push(stream);
+    }
+
+    progress_dialog.show(true);
+    this.pcrud.create(
+        streams, {
+            "oncomplete": function(r, list) {
+                progress_dialog.hide();
+                sstr_grid.refresh();
+            },
+            "onerror": function(r) {
+                progress_dialog.hide();
+                alert("Error creating streams!"); /* XXX i18n */
+            }
+        }
+    );
+}
+
+openils.Util.addOnLoad(
+    function() {
+        pcrud = new openils.PermaCrud();
+        load_sdist_display();
+        load_sstr_grid();
+    }
+);
diff --git a/Open-ILS/web/js/ui/default/serial/list_subscription.js b/Open-ILS/web/js/ui/default/serial/list_subscription.js
new file mode 100644 (file)
index 0000000..206b730
--- /dev/null
@@ -0,0 +1,46 @@
+dojo.require("dijit.form.Button");
+dojo.require("openils.widget.AutoGrid");
+dojo.require("openils.widget.OrgUnitFilteringSelect");
+dojo.require("openils.BibTemplate");
+
+function format_ssub_link(id) {
+    return "<a href='" + oilsBasePath + "/serial/subscription/" +
+        id + "'>" + id + "</a>";
+}
+
+function load_ssub_grid() {
+    ssub_grid.resetStore();
+    ssub_grid.loadAll({"order_by": {"ssub": "start_date DESC"}}, terms);
+}
+
+openils.Util.addOnLoad(
+    function() {
+        if (terms.record_entry)
+            new openils.BibTemplate({"record": terms.record_entry}).render();
+
+        /* This should be present even if terms.record_entry is undef */
+        ssub_grid.overrideEditWidgets.record_entry = new dijit.form.TextBox(
+            {"value": terms.record_entry, "disabled": true}
+        );
+
+        new openils.User().buildPermOrgSelector(
+            "ADMIN_SERIAL_SUBSCRIPTION",
+            ssub_owner_select,
+            null,
+            function() {
+                dojo.connect(
+                    ssub_owner_select,
+                    "onChange",
+                    function() {
+                        terms.owning_lib = aou.orgNodeTrail(
+                            aou.findOrgUnit(this.attr("value")),
+                            true /* asId */
+                        );
+                        load_ssub_grid();
+                    }
+                );
+                load_ssub_grid();
+            }
+        );
+    }
+);
diff --git a/Open-ILS/web/js/ui/default/serial/subscription.js b/Open-ILS/web/js/ui/default/serial/subscription.js
new file mode 100644 (file)
index 0000000..3f17749
--- /dev/null
@@ -0,0 +1,152 @@
+dojo.require("dijit.form.Button");
+dojo.require("dijit.form.RadioButton");
+dojo.require("dijit.form.FilteringSelect");
+dojo.require("dijit.form.DropDownButton");
+dojo.require("dijit.TooltipDialog");
+dojo.require("dijit.layout.TabContainer");
+dojo.require("dijit.layout.ContentPane");
+dojo.require("dojox.grid.DataGrid");
+dojo.require("openils.widget.AutoGrid");
+dojo.require("openils.widget.ProgressDialog");
+dojo.require("openils.PermaCrud");
+
+var pcrud;
+var sub;
+
+/* typing save: add {get,set}Value() to all HTML <select> elements */
+HTMLSelectElement.prototype.getValue = function() {
+    return this.options[this.selectedIndex].value;
+}
+HTMLSelectElement.prototype.setValue = function(s) {
+    for (var i = 0; i < this.options.length; i++) {
+        if (s == this.options[i].value) {
+            this.selectedIndex = i;
+            break;
+        }
+    }
+}
+
+function load_sub_grid(id) {
+    if (!pcrud) return; /* first run, onLoad hasn't fired yet */
+    if (!sub_grid._fresh) {
+        pcrud.retrieve(
+            "ssub", id, {
+                "onresponse": function(r) {
+                    if (r = openils.Util.readResponse(r)) {
+                        sub = r;
+                        sub_grid.setStore(
+                            new dojo.data.ItemFileReadStore(
+                                {"data": ssub.toStoreData([r])}
+                            )
+                        );
+                        sub_grid._fresh = true;
+                    }
+                }
+            }
+        );
+    }
+}
+
+/* TODO: make these formatters caching */
+function format_bib(bib_id) {
+    if (!bib_id) {
+        return "";
+    } else {
+        var result;
+        fieldmapper.standardRequest(
+            ["open-ils.search",
+                "open-ils.search.biblio.record.mods_slim.retrieve"], {
+                "async": false,
+                "params": [bib_id],
+                "oncomplete": function(r) {
+                    if (r = openils.Util.readResponse(r)) {
+                        var parts = [];
+                        if (r.title())
+                            parts.push(r.title());
+                        if (r.author())
+                            parts.push(r.author());
+                        if (r.author())
+                            parts.push(r.publisher());
+
+                        if (!parts.length)
+                            parts.push(r.tcn());
+
+                        result = parts.join(" / ");
+                    }
+                }
+            }
+        );
+        return "<a href='" + oilsBasePath + "/serial/list_subscription/" +
+            bib_id + "'>" + result + "</a>";
+    }
+}
+
+function format_date(s) {
+    return s ? openils.Util.timeStamp(s, {"selector": "date"}) : "";
+}
+
+function format_org_unit(aou_id) {
+    return aou_id ? aou.findOrgUnit(aou_id).shortname() : "";
+}
+
+function get_sdist(rowIndex, item) {
+    if (!item) return {"id": "", "label": ""};
+    return {
+        "id": this.grid.store.getValue(item, "id"),
+        "label": this.grid.store.getValue(item, "label")
+    };
+}
+
+function format_sdist_label(blob) {
+    if (!blob.id) return "";
+    var link = "<a href='" +
+        oilsBasePath + "/serial/list_stream/" + blob.id +
+        "'>" + (blob.label ? blob.label : "[None]") + "</a>" + /* XXX i18n */
+        "<span id='dist_link_" + blob.id + "'></span>";
+
+    /* XXX kludgy kludge kludge */
+    setTimeout(function() { append_stream_count(blob.id); }, 200);
+
+    return link;
+}
+
+function append_stream_count(dist_id) {
+    var span = dojo.byId("dist_link_" + dist_id);
+    if (span.childNodes.length) /* textNodes count as childnodes */
+        return;
+    pcrud.search(
+        "sstr", {"distribution": dist_id}, {
+            "id_list": true,
+            "oncomplete": function(r) {
+                var resp = openils.Util.readResponse(r);
+                var count = resp ? resp.length : 0;
+
+                /* XXX i18n */
+                span.innerHTML = "&nbsp;&nbsp; " + count + " stream(s)";
+            }
+        }
+    );
+}
+
+function open_batch_receive() {
+    if (!sub) {
+        alert("Let the interface load all the way first.");
+        return;
+    }
+
+    var url = "/xul/server/serial/batch_receive.xul?docid=" +
+        sub.record_entry() + "&subid=" + sub.id();
+
+    try {
+        openils.XUL.newTabEasy(url, "Batch Receive"); /* XXX i18n */
+    } catch (E) {
+        location.href = url;
+    }
+}
+
+openils.Util.addOnLoad(
+    function() {
+        pcrud = new openils.PermaCrud();
+        load_sub_grid(sub_id);
+    }
+);
diff --git a/Open-ILS/web/js/ui/default/serial/subscription/caption_and_pattern.js b/Open-ILS/web/js/ui/default/serial/subscription/caption_and_pattern.js
new file mode 100644 (file)
index 0000000..116cae2
--- /dev/null
@@ -0,0 +1,209 @@
+function SCAPRow() {
+    var self = this;
+    var _fields = ["id", "type", "pattern_code", "active", "create_date"];
+
+    this.init = function(id, manager, datum) {
+        this.id = id;
+        this.manager = manager;
+        this.element = dojo.clone(manager.template);
+
+        /* find the controls for each field */
+        this.controls = {};
+        _fields.forEach(
+            function(k) {
+                self.controls[k] = dojo.query(
+                    "[name='" + k + "'] [control]", self.element
+                )[0];
+            }
+        );
+
+        /* set up the remover button */
+        this.remover = dojo.query("[name='remover'] button", this.element)[0];
+        this.remover.onclick = function() { manager.remove_row(self); };
+
+        this.save_button = dojo.query("[name='save'] button", this.element)[0];
+        this.save_button.onclick = function() { manager.save_row(self); };
+
+        this.wizard_button = dojo.query(
+            "[name='pattern_code'] button", this.element
+        )[0];
+        this.wizard_button.onclick = function() {
+            try {
+                netscape.security.PrivilegeManager.enablePrivilege(
+                    "UniversalXPConnect"
+                );
+                window.openDialog(
+                    xulG.url_prefix("/xul/server/serial/pattern_wizard.xul"),
+                    "pattern_wizard",
+                    "scrollbars=yes", /* XXX doesn't work this way? */
+                    function(value) {
+                        self.controls.pattern_code.value = value;
+                        self.controls.pattern_code.onchange();
+                    }
+                );
+            } catch (E) {
+                alert(E); /* XXX */
+            }
+        };
+
+        /* set up onchange handlers for control fields */
+        this.controls.type.onchange = function() {
+            self.has_changed(true);
+            self.datum.type(this.getValue());
+        };
+        this.controls.pattern_code.onchange = function() {
+            self.has_changed(true);
+            self.datum.pattern_code(this.value);
+        };
+        this.controls.active.onchange = function() {
+            self.has_changed(true);
+            self.datum.active(this.checked ? "t" : "f");
+        };
+
+        this.load_fm_object(datum);
+    };
+
+    this.load_fm_object = function(datum) {
+        if (typeof datum != "undefined") {
+            this.datum = datum;
+
+            this.controls.type.setValue(datum.type());
+            this.controls.pattern_code.value = datum.pattern_code();
+            this.controls.active.checked = openils.Util.isTrue(datum.active());
+            this.controls.id.innerHTML = datum.id() || "";
+            this.controls.create_date.innerHTML =
+                openils.Util.timeStamp(datum.create_date());
+
+            this.has_changed(false);
+        } else {
+            this.datum = new scap();
+            this.datum.subscription(this.manager.sub_id);
+
+            _fields.forEach(
+                function(k) {
+                    try { self.controls[k].onchange(); } catch (E) { ; }
+                }
+            );
+        }
+    };
+
+    this.has_changed = function(has) {
+        if (typeof has != "undefined") {
+            this._has_changed = has;
+            this.save_button.disabled = !has;
+            dojo.attr(this.element, "changed", String(has));
+        }
+
+        return this._has_changed;
+    };
+
+    this.init.apply(this, arguments);
+}
+
+function SCAPEditor() {
+    var self = this;
+
+    this.init = function(sub_id, pcrud) {
+        this.sub_id = sub_id;
+        this.pcrud = pcrud || new openils.PermaCrud();
+
+        this.setup();
+        this.reset();
+        this.load_existing();
+    };
+
+    this.reset = function() {
+        this.virtRowCount = 0;
+        this.rows = {};
+
+        dojo.empty(this.body);
+    };
+
+    this.setup = function() {
+        var template = dojo.query("#scap_editor tbody tr")[0];
+        this.body = template.parentNode;
+        this.template = this.body.removeChild(template);
+
+        dojo.query("#scap_editor button[name='add']")[0].onclick =
+            function() { self.add_row(); };
+
+        openils.Util.show("scap_editor");
+    };
+
+    this.load_existing = function() {
+        this.pcrud.search("scap", {
+                "subscription": this.sub_id
+            }, {
+                "order_by": {"scap": "create_date"},
+                "onresponse": function(r) {
+                    if (r = openils.Util.readResponse(r)) {
+                        r.forEach(function(datum) { self.add_row(datum); });
+                    }
+                }
+            }
+        );
+    };
+
+    this.add_row = function(datum) {
+        var id;
+        if (typeof datum == "undefined") {
+            id = --(this.virtRowCount);
+            this.rows[id] = new SCAPRow(id, this);
+        } else {
+            id = datum.id();
+            this.rows[id] = new SCAPRow(id, this, datum);
+        }
+
+        dojo.place(this.rows[id].element, this.body, "last");
+    };
+
+    this.save_row = function(row) {
+        var old_id = row.id;
+        if (old_id < 0) {
+            this.pcrud.create(
+                row.datum, {
+                    "oncomplete": function(r, list) {
+                        openils.Util.readResponse(r);
+                        var new_id = list[0].id();
+                        row.id = new_id;
+                        delete self.rows[old_id];
+                        self.rows[new_id] = row;
+                        row.load_fm_object(list[0]);
+                        row.has_changed(false);
+                    }
+                }
+            );
+        } else {
+            this.pcrud.update(
+                row.datum, {
+                    "oncomplete": function(r, list) {
+                        openils.Util.readResponse(r);
+                        row.has_changed(false);
+                    }
+                }
+            );
+        }
+    };
+
+    this.remove_row = function(row) {
+        function _remove(row) {
+            dojo.destroy(self.rows[row.id].element);
+            delete self.rows[row.id];
+        }
+
+        if (row.id < 0) { /* virtual row */
+            _remove(row);
+        } else { /* real row */
+            this.pcrud.eliminate(
+                row.datum, {
+                    "oncomplete": function(r, list) {
+                        openils.Util.readResponse(r);
+                        _remove(row);
+                    }
+                }
+            );
+        }
+    };
+
+    this.init.apply(this, arguments);
+}
diff --git a/Open-ILS/web/js/ui/default/serial/subscription/issuance.js b/Open-ILS/web/js/ui/default/serial/subscription/issuance.js
new file mode 100644 (file)
index 0000000..55dba09
--- /dev/null
@@ -0,0 +1,76 @@
+function fresh_scap_selector(grid) {
+    pcrud.search(
+        "scap", {"subscription": sub_id, "active": "t"}, {
+            "oncomplete": function(r) {
+                var data = scap.toStoreData(openils.Util.readResponse(r));
+                var selector = new dijit.form.FilteringSelect(
+                    {
+                        "store": new dojo.data.ItemFileReadStore({"data":data}),
+                        "searchAttr": "id"
+                    },
+                    dojo.create("span")
+                );
+                selector.shove = {
+                    "create": data.items.length ? data.items[0].id : ""
+                };
+                dojo.connect(
+                    selector, "onChange", null, function() {
+                        if (this.item) {
+                            var widget =
+                                iss_grid.overrideEditWidgets.holding_type;
+                            widget.attr("value", this.item.type);
+                            widget.attr("disabled", true);
+                        }
+                    }
+                );
+
+                grid.overrideEditWidgets.caption_and_pattern = selector;
+            }
+        }
+    );
+}
+
+function prepare_prediction_dialog() {
+    if (sub.end_date()) {
+        prediction_dialog_end_date.attr("disabled", false);
+        prediction_dialog_end_date.attr("checked", true);
+    } else {
+        prediction_dialog_end_num.attr("checked", true);
+        prediction_dialog_end_date.attr("disabled", true);
+        prediction_dialog_num_to_predict.focus();
+    }
+    prediction_dialog_submit.attr("disabled", false);
+}
+
+function generate_predictions(fields) {
+    var args = {"ssub_id": sub.id(), "all_dists": true};
+
+    if (fields.end_how == "date") {
+        args.end_date = sub.end_date();
+    } else if ((num = Number(fields.num_to_predict)) > 0)  {
+        args.num_to_predict = num;
+    } else {
+        alert("Go with a whole, positive number."); /* XXX i18n */
+        return;
+    }
+
+    progress_dialog.show(true);
+    try {
+        fieldmapper.standardRequest(
+            ["open-ils.serial", "open-ils.serial.make_predictions"], {
+                "params": [openils.User.authtoken, args],
+                "async": true,
+                "onresponse": function(r) {
+                    openils.Util.readResponse(r); /* tests for events */
+                },
+                "oncomplete": function() {
+                    progress_dialog.hide();
+                    iss_grid.refresh();
+                }
+            }
+        );
+    } catch (E) {
+        alert(E);
+        progess_dialog.hide();
+    }
+}
index b30d250..ce08625 100644 (file)
 <!ENTITY staff.cat.opac.view_holds.label "View Holds">
 <!ENTITY staff.cat.opac.view_orders.accesskey "r">
 <!ENTITY staff.cat.opac.view_orders.label "View/Place Orders">
+<!ENTITY staff.cat.opac.alt_serial.accesskey "a">
+<!ENTITY staff.cat.opac.alt_serial.label "Alternate Serial Control">
 <!ENTITY staff.cat.opac.batch_receive.accesskey "i">
 <!ENTITY staff.cat.opac.batch_receive.label "Serials Batch Receive">
 <!ENTITY staff.cat.popup.add_to_bucket "Add to Bucket">
diff --git a/Open-ILS/web/templates/default/serial/list_stream.tt2 b/Open-ILS/web/templates/default/serial/list_stream.tt2
new file mode 100644 (file)
index 0000000..ea3f659
--- /dev/null
@@ -0,0 +1,73 @@
+[% WRAPPER default/base.tt2 %]
+[% ctx.page_title = "Streams" %]
+<script
+    type="text/javascript"
+    src="[% ctx.media_prefix %]/js/ui/default/serial/list_stream.js">
+</script>
+<script type="text/javascript">
+    var dist_id = "[% ctx.page_args.0 %]";
+</script>
+<div dojoType="dijit.layout.ContentPane" layoutAlign="client">
+    <div dojoType="dijit.layout.ContentPane"
+        layoutAlign="top" class="oils-header-panel">
+        <div>Streams</div>
+        <div>
+            <button dojoType="dijit.form.Button"
+                onClick="sstr_grid.showCreateDialog()">New Stream</button>
+            <button dojoType="dijit.form.Button"
+                onClick="multi_stream_dialog.show()">
+                Create Many Streams
+            </button>
+            <button dojoType="dijit.form.Button"
+                onClick="sstr_grid.refresh()">Refresh Grid</button>
+            <button dojoType="dijit.form.Button"
+                onClick="sstr_grid.deleteSelected()">Delete Selected</button>
+        </div>
+    </div>
+    <div>
+        Showing streams attached to the distribution,
+        <em id="sdist_label_here"></em>
+        (<span id="sdist_org_unit_name_here"></span>).
+    </div>
+    <table jsId="sstr_grid"
+        dojoType="openils.widget.AutoGrid"
+        query="{id: '*'}"
+        suppressFields="['distribution']"
+        fmClass="sstr"
+        defaultCellWidth="'auto'"
+        showPaginator="true"
+        editOnEnter="true">
+        <thead>
+            <tr>
+                <th field="routing_label" formatter="format_routing_label">
+                </th>
+            </tr>
+        </thead>
+    </table>
+</div>
+<div class="hidden">
+    <div dojoType="dijit.Dialog"
+        execute="create_many_streams(arguments[0]);"
+        title="Create Streams"
+        jsId="multi_stream_dialog">
+        <table class="serial-dialog-table">
+            <tr>
+                <th>How many?</th>
+                <td>
+                    <input dojoType="dijit.form.NumberSpinner"
+                        value="1" smallDelta="1" name="quantity"
+                        constraints="{'min': 1, 'max': 1000}" />
+                </td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <button dojoType="dijit.form.Button" type="submit">
+                        Create
+                    </button>
+                </td>
+            </tr>
+        </table>
+    </div>
+    <div dojoType="openils.widget.ProgressDialog" jsId="progress_dialog"></div>
+</div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/serial/list_subscription.tt2 b/Open-ILS/web/templates/default/serial/list_subscription.tt2
new file mode 100644 (file)
index 0000000..7881779
--- /dev/null
@@ -0,0 +1,59 @@
+[% WRAPPER default/base.tt2 %]
+[% ctx.page_title = "Subscriptions" %]
+<script
+    type="text/javascript"
+    src="[% ctx.media_prefix %]/js/ui/default/serial/list_subscription.js">
+</script>
+<script type="text/javascript">
+    var terms = {
+        "owning_lib": aou.orgNodeTrail(
+            aou.findOrgUnit(openils.User.user.ws_ou()),
+            true /* asId */
+        )
+    };
+
+    if (docid = "[% ctx.page_args.0 %]") /* assignment intentional */
+        terms.record_entry = docid;
+</script>
+<div dojoType="dijit.layout.ContentPane" layoutAlign="client">
+    <div dojoType="dijit.layout.ContentPane"
+        layoutAlign="top" class="oils-header-panel">
+        <div>Subscriptions</div>
+        <div>
+            <button
+                dojoType="dijit.form.Button"
+                onClick="ssub_grid.showCreateDialog()">New Subscription</button>
+            <button
+                dojoType="dijit.form.Button"
+                onClick="ssub_grid.deleteSelected()">Delete Selected</button>
+        </div>
+    </div>
+    <div>
+        <span>
+            Show subscriptions related to
+            <em type="opac/slot-data" datatype="marcxml"
+                query="datafield[tag=245]" limit="1"></em>
+            owned at or above:
+        </span>
+        <select dojoType="openils.widget.OrgUnitFilteringSelect"
+            jsId="ssub_owner_select"
+            searchAttr="shortname" labelAttr="shortname">
+        </select>
+    </div>
+    <table jsId="ssub_grid"
+        dojoType="openils.widget.AutoGrid"
+        query="{id: '*'}"
+        fieldOrder="['id','owning_lib','start_date','end_date']"
+        suppressFields="['record_entry']"
+        fmClass="ssub"
+        showPaginator="true"
+        showSequenceFields="true"
+        editOnEnter="true">
+        <thead>
+            <tr>
+                <th field="id" formatter="format_ssub_link"></th>
+            </tr>
+        </thead>
+    </table>
+</div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/serial/subscription.tt2 b/Open-ILS/web/templates/default/serial/subscription.tt2
new file mode 100644 (file)
index 0000000..24970ad
--- /dev/null
@@ -0,0 +1,130 @@
+[% WRAPPER "default/base.tt2" %]
+<script>
+    var cap_editor;
+    var sub_id = "[% ctx.page_args.0 %]";
+</script>
+<script src="[% ctx.media_prefix %]/js/ui/default/serial/subscription.js">
+</script>
+<script src="[% ctx.media_prefix %]/js/ui/default/serial/subscription/caption_and_pattern.js">
+</script>
+<script src="[% ctx.media_prefix %]/js/ui/default/serial/subscription/issuance.js">
+</script>
+
+<div dojoType="dijit.layout.ContentPane" layout="top" class="oils-header-panel">
+    <div>Subscription Details</div>
+    <div>
+        <span dojoType="dijit.form.Button" onClick="open_batch_receive();">
+            Batch Item Receive
+        </span>
+    </div>
+</div>
+
+<div dojoType="dijit.layout.TabContainer" class="oils-serial-tab-container">
+
+    <!-- Subscription Summary -->
+    <div dojoType="dijit.layout.ContentPane" title="Summary" selected="true">
+        <script type="dojo/connect" event="onShow">
+            load_sub_grid(sub_id);
+        </script>
+        <table jsId="sub_grid"
+            dojoType="dojox.grid.DataGrid" query="{id: '*'}" rowSelector="20px">
+            <thead>
+                <tr>
+                    <th field="id">ID</th>
+                    <th field="owning_lib" formatter="format_org_unit">
+                        Owning Library
+                    </th>
+                    <th field="start_date" formatter="format_date">
+                        Start Date
+                    </th>
+                    <th field="end_date" formatter="format_date">
+                        End Date
+                    </th>
+                    <th field="record_entry" width="20em"
+                        formatter="format_bib">
+                        Bibliographic Record
+                    </th>
+                    <th field="expected_date_offset">Expected Date Offset</th>
+                </tr>
+            </thead>
+        </table>
+    </div>
+
+    <!-- Distributions -->
+    <div dojoType="dijit.layout.ContentPane"
+        title="Distributions" layoutAlign="client">
+        <script type="dojo/connect" event="onShow">
+            if (!dist_grid._fresh) {
+                dist_grid.resetStore();
+                dist_grid.loadAll(
+                    {"order_by": {"sdist": "holding_lib"}},
+                    {"subscription": sub_id}
+                );
+                dist_grid._fresh = true;
+            }
+
+            if (!dist_grid.overrideEditWidgets.subscription) {
+                dist_grid.overrideEditWidgets.subscription =
+                    new dijit.form.TextBox({
+                        "disabled": true, "value": sub_id
+                    });
+            }
+        </script>
+        [% INCLUDE "default/serial/subscription/distribution.tt2" %]
+    </div>
+
+    <!-- Caption/Pattern -->
+    <div dojoType="dijit.layout.ContentPane"
+        title="Captions and Patterns" layoutAlign="client">
+        <script type="dojo/connect" event="onShow">
+            if (!cap_editor) cap_editor = new SCAPEditor(sub_id);
+        </script>
+        [% INCLUDE "default/serial/subscription/caption_and_pattern.tt2" %]
+    </div>
+
+    <!-- Issuances -->
+    <div dojoType="dijit.layout.ContentPane"
+        title="Issuances" layoutAlign="client">
+        <script type="dojo/connect" event="onShow">
+            if (!iss_grid._fresh) {
+                iss_grid.resetStore();
+                iss_grid.loadAll(
+                    {"order_by": {"siss": "date_published"}},
+                    {"subscription": sub_id}
+                );
+                iss_grid._fresh = true;
+            }
+
+            if (!iss_grid.overrideEditWidgets.subscription) {
+                iss_grid.overrideEditWidgets.subscription =
+                    new dijit.form.TextBox({
+                        "disabled": true, "value": sub_id
+                    });
+
+                iss_grid.overrideEditWidgets.creator =
+                    new dijit.form.TextBox({"disabled": true});
+                iss_grid.overrideEditWidgets.creator.shove = {
+                    "create": openils.User.user.id()
+                };
+
+                iss_grid.overrideEditWidgets.editor =
+                    new dijit.form.TextBox({
+                        "disabled": true, "value": openils.User.user.id()
+                    });
+
+                iss_grid.overrideEditWidgets.holding_type =
+                    new dijit.form.TextBox({"disabled": true});
+                iss_grid.overrideEditWidgets.holding_type.shove = {"create":""};
+
+                iss_grid.overrideEditWidgets.holding_type =
+                    new dijit.form.TextBox;
+            }
+            fresh_scap_selector(iss_grid);
+        </script>
+        [% INCLUDE "default/serial/subscription/issuance.tt2" %]
+    </div>
+</div>
+<div class="hidden">
+    <div dojoType="openils.widget.ProgressDialog" jsId="progress_dialog"></div>
+</div>
+[% END %]
diff --git a/Open-ILS/web/templates/default/serial/subscription/caption_and_pattern.tt2 b/Open-ILS/web/templates/default/serial/subscription/caption_and_pattern.tt2
new file mode 100644 (file)
index 0000000..5510cdf
--- /dev/null
@@ -0,0 +1,52 @@
+<div dojoType="dijit.layout.ContentPane" layout="top">
+    <table id="scap_editor" class="hidden">
+        <thead>
+            <tr>
+                <th>ID</th>
+                <th>Type</th>
+                <th>Pattern Code</th>
+                <th>Create Date</th>
+                <th>Active</th>
+                <th>Remove</th>
+                <th>Save Changes</th>
+            </tr>
+        </thead>
+        <tbody>
+            <tr>
+                <td name="id">
+                    <span control="true"></span>
+                </td>
+                <td name="type">
+                    <select control="true">
+                        <option value="basic">(853) Basic</option>
+                        <option value="supplement">(854) Supplement</option>
+                        <option value="index">(855) Index</option>
+                    </select>
+                </td>
+                <td name="pattern_code">
+                    <input type="text" size="16" control="true" />
+                    <button>Wizard ...</button>
+                </td>
+                <td name="create_date">
+                    <span control="true"></span>
+                </td>
+                <td name="active">
+                    <input type="checkbox" control="true" />
+                </td>
+                <td name="remover">
+                    <button>X</button>
+                </td>
+                <td name="save">
+                    <button>Save Changes</button>
+                </td>
+            </tr>
+        </tbody>
+        <tfoot>
+            <tr>
+                <td colspan="7">
+                    <button name="add">Add Caption and Pattern</button>
+                </td>
+            </tr>
+        </tfoot>
+    </table>
+</div>
diff --git a/Open-ILS/web/templates/default/serial/subscription/distribution.tt2 b/Open-ILS/web/templates/default/serial/subscription/distribution.tt2
new file mode 100644 (file)
index 0000000..8ad3a61
--- /dev/null
@@ -0,0 +1,33 @@
+<div dojoType="dijit.layout.ContentPane" layout="top"
+    class="oils-header-panel lesser">
+    <div>Distributions</div>
+    <div style="margin-right: 16px;">
+        <span dojoType="dijit.form.Button"
+            onClick="dist_grid.refresh();">Refresh Grid</span>
+        <span dojoType="dijit.form.Button"
+            onClick="dist_grid.showCreateDialog();">New Distribution</span>
+        <span dojoType="dijit.form.Button"
+            onClick="dist_grid.deleteSelected();">Delete Selected</span>
+    </div>
+</div>
+<div dojoType="dijit.layout.ContentPane" layout="top">
+    <table
+        jsId="dist_grid"
+        dojoType="openils.widget.AutoGrid"
+        autoHeight="true"
+        fieldOrder="['subscription','label','holding_lib']"
+        suppressFields="['record_entry','subscription','receive_call_number','bind_call_number','bind_unit_template']"
+        suppressEditFields="['record_entry','receive_call_number','bind_call_number','bind_unit_template']"
+        defaultCellWidth="'auto'"
+        fmClass="sdist"
+        query="{id: '*'}"
+        editOnEnter="true"
+        showPaginator="true">
+        <thead>
+            <tr>
+                <th field="label"
+                    get="get_sdist" formatter="format_sdist_label"></th>
+            </tr>
+        </thead>
+    </table>
+</div>
diff --git a/Open-ILS/web/templates/default/serial/subscription/issuance.tt2 b/Open-ILS/web/templates/default/serial/subscription/issuance.tt2
new file mode 100644 (file)
index 0000000..55cf751
--- /dev/null
@@ -0,0 +1,78 @@
+<div dojoType="dijit.layout.ContentPane" layout="top"
+    class="oils-header-panel lesser">
+    <div>Issuances</div>
+    <div style="margin-right: 16px;">
+        <span dojoType="dijit.form.Button"
+            onclick="iss_grid.refresh();">Refresh Grid</span>
+        <span dojoType="dijit.form.Button"
+            onclick="iss_grid.showCreateDialog();">New Issuance</span>
+        <span dojoType="dijit.form.Button"
+            onclick="iss_grid.deleteSelected();">Delete Selected</span>
+    </div>
+</div>
+<div class="serial-additional-controls">
+    <span dojoType="dijit.form.Button"
+        onclick="prediction_dialog.show();">Generate Predictions</span>
+</div>
+<div dojoType="dijit.layout.ContentPane" layout="top">
+    <table jsId="iss_grid"
+        dojoType="openils.widget.AutoGrid"
+        autoHeight="true"
+        fieldOrder="['subscription','creator','editor','label','date_published','caption_and_pattern','holding_type']"
+        suppressFields="['subscription','holding_link_id','create_date','edit_date','creator','editor']"
+        suppressEditFields="['id','holding_link_id','create_date','edit_date']"
+        defaultCellWidth="'auto'"
+        fmClass="siss"
+        query="{id: '*'}"
+        editOnEnter="true"
+        showPaginator="true">
+    </table>
+</div>
+<div class="hidden">
+    <div dojoType="dijit.Dialog"
+        title="Generate Issuance and Item Predictions"
+        execute="generate_predictions(arguments[0]);"
+        jsId="prediction_dialog">
+        <script type="dojo/connect" event="onShow">
+            prepare_prediction_dialog();
+        </script>
+        <table class="serial-dialog-table">
+            <tr>
+                <th>
+                    <input dojoType="dijit.form.RadioButton"
+                        id="end_date" name="end_how" value="date"
+                        checked="false" disabled="true"
+                        jsId="prediction_dialog_end_date" />
+                    <label for="end_date">
+                        Predict until end of subscription
+                    </label>
+                </th>
+                <td></td>
+            </tr>
+            <tr>
+                <th>
+                    <input dojoType="dijit.form.RadioButton"
+                        id="end_num" name="end_how" value="number"
+                        checked="true" jsId="prediction_dialog_end_num"
+                        onChange="if (this.attr('checked')) setTimeout(function(){prediction_dialog_num_to_predict.focus();},200);" />
+                    <label for="end_num">
+                        Predict a certain number of issuances:
+                    </label>
+                </th>
+                <td>
+                    <input dojoType="dijit.form.TextBox"
+                        style="width: 5em;"
+                        jsId="prediction_dialog_num_to_predict"
+                        name="num_to_predict" />
+                </td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <button dojoType="dijit.form.Button"
+                        jsId="prediction_dialog_submit"
+                        type="submit" disabled="true">Generate</button>
+                </td>
+            </tr>
+        </table>
+    </div>
+</div>
index a23727d..b496f39 100644 (file)
@@ -303,6 +303,39 @@ function open_acq_orders() {
     }
 }
 
+function open_alt_serial_mgmt() {
+    try {
+        var content_params = {
+            "session": ses(),
+            "authtime": ses("authtime"),
+            "show_nav_buttons": true,
+            "no_xulG": false,
+            "show_print_button": false
+        };
+
+        ["url_prefix", "new_tab", "set_tab", "close_tab", "new_patron_tab",
+            "set_patron_tab", "volume_item_creator", "get_new_session",
+            "holdings_maintenance_tab", "set_tab_name", "open_chrome_window",
+            "url_prefix", "network_meter", "page_meter", "set_statusbar",
+            "set_help_context"
+        ].forEach(function(k) { content_params[k] = xulG[k]; });
+
+        var loc = urls.XUL_BROWSER + "?url=" + window.escape(
+            xulG.url_prefix("/eg/serial/list_subscription/") + docid
+        );
+        xulG.new_tab(
+            loc, {
+                "tab_name": $("offlineStrings").getString(
+                    "staff.cat.opac.serial_alt_mgmt"
+                ),
+                "browser": false
+            }, content_params
+        );
+    } catch (E) {
+        g.error.sdump("D_ERROR", E);
+    }
+}
+
 function set_opac() {
     g.view = 'opac';
     try {
@@ -539,28 +572,6 @@ function open_marc_editor(rec, label) {
     };
 }
 
-function serials_mgmt_new_tab() {
-    try {
-        /* XXX should the following be put into a function somewhere? the gist
-         * of this setting up of content_params seems to be duplicated all
-         * over the place.
-         */
-        var content_params = {"session": ses(), "authtime": ses("authtime")};
-        ["url_prefix", "new_tab", "set_tab", "close_tab", "new_patron_tab",
-            "set_patron_tab", "volume_item_creator", "get_new_session",
-            "holdings_maintenance_tab", "set_tab_name", "open_chrome_window",
-            "url_prefix", "network_meter", "page_meter", "set_statusbar",
-            "set_help_context"
-        ].forEach(function(k) { content_params[k] = xulG[k]; });
-
-        xulG.new_tab(
-            xulG.url_prefix(urls.XUL_SERIAL_RECORD_ENTRY), {}, content_params
-        );
-    } catch (E) {
-        g.error.sdump('D_ERROR', E);
-    }
-}
-
 function bib_in_new_tab() {
     try {
         var url = browser_frame.contentWindow.g.browser.controller.view.browser_browser.contentWindow.wrappedJSObject.location.href;
index 0c9396f..5197d89 100644 (file)
@@ -73,7 +73,8 @@
                         <menu id="mfhd_delete" label="&staff.serial.mfhd_menu.delete.label;"/>
                     </menupopup>
                 </menu>
-                <menuitem id="serctrl_view" label="&staff.serial.serctrl_view.label;" oncommand="set_serctrl_view();"/>
+                <menuitem id="serctrl_view" label="&staff.serial.serctrl_view.label;" oncommand="set_serctrl_view();" />
+                <menuitem label="&staff.cat.opac.alt_serial.label;" accesskey="&staff.cat.opac.alt_serial.accesskey;" id="alt_serial" oncommand="open_alt_serial_mgmt();" />
                 <menuitem label="&staff.cat.opac.batch_receive.label;" accesskey="&staff.cat.opac.batch_receive.accesskey;" id="batch_receive" oncommand="batch_receive_in_new_tab();"/>
                 </menupopup>
                 </menu>
index e7d0425..7fec403 100644 (file)
@@ -261,6 +261,7 @@ staff.cat.opac.title_for_hold_transfer.destination_needed.label=Need to mark a r
 staff.cat.opac.title_for_hold_transfer.success.label=Holds transferred.
 staff.cat.opac.title_for_hold_transfer.failure.label=Holds not transferred.
 staff.cat.opac.related_items=Related Lineitems
+staff.cat.opac.serial_alt_mgmt=Subscriptions
 staff.cat.create_or_rebarcode_items=Create or Re-barcode Items
 printing.nothing_to_reprint=Nothing to re-print
 printing.prompt_for_external_print_cmd=Enter external print command and parameters (use %receipt.txt% or %receipt.html% as the file containing the print data. Those values will be substituted with the proper path.):
index b549683..3fbf350 100644 (file)
@@ -21,7 +21,7 @@ function F(k, args) {
 function BatchReceiver() {
     var self = this;
 
-    this.init = function(authtoken, bib_id) {
+    this.init = function(authtoken, bib_id, sub_id) {
         if (authtoken) {
             this.user = new openils.User({"authtoken": authtoken});
             this.pcrud = new openils.PermaCrud({"authtoken": authtoken});
@@ -73,7 +73,7 @@ function BatchReceiver() {
         this.item_cache = {};
 
         if (bib_id)
-            this.bib_lookup(bib_id, null, true);
+            this.bib_lookup(bib_id, null, true, sub_id);
 
         busy(false);
     };
@@ -453,7 +453,7 @@ function BatchReceiver() {
         }
     };
 
-    this.bib_lookup = function(bib_search_term, evt, is_actual_id) {
+    this.bib_lookup = function(bib_search_term, evt, is_actual_id, sub_id) {
         if (evt && evt.keyCode != 13) return;
 
         if (!bib_search_term) {
@@ -497,7 +497,7 @@ function BatchReceiver() {
                         } else {
                             self.bibdata = list[0];
                             self._show_bibdata_bits();
-                            self.choose_subscription();
+                            self.choose_subscription(sub_id);
                         }
                     } else {
                         alert(S("bib_lookup.not_found"));
@@ -513,7 +513,7 @@ function BatchReceiver() {
         );
     };
 
-    this.choose_subscription = function() {
+    this.choose_subscription = function(sub_id) {
         hide("batch_receive_bib");
         hide("batch_receive_entry");
         hide("batch_receive_sub_bits");
@@ -521,7 +521,11 @@ function BatchReceiver() {
 
         var subs = this.bibdata.bre.subscriptions();
 
-        if (subs.length > 1) {
+        if (sub_id) {
+            this.choose_issuance(
+                subs.filter(function(o) { return o.id() == sub_id; })[0]
+            );
+        } else if (subs.length > 1) {
             var menulist = dojo.create("menulist", {"id": "sub_chooser"});
             var menupopup = dojo.create("menupopup", {}, menulist, "only");
 
@@ -912,6 +916,6 @@ function my_init() {
     batch_receiver = new BatchReceiver(
         (typeof ses == "function" ? ses() : 0) ||
             cgi.param("ses") || dojo.cookie("ses"),
-        cgi.param("docid") || null
+        cgi.param("docid") || null, cgi.param("subid") || null
     );
 }
index 47a8605..141bbb3 100644 (file)
                     label="Use chronology captions?" />
                 <vbox id="chron_editor_here" class="hideme">
                     <description class="step">
-                        Generally, each caption should be a smaller unit of
-                        time than the preceding caption.
+                        Each caption must be a smaller unit of
+                        time than the preceding caption.<!-- XXX TODO enforce -->
                     </description>
                     <grid>
                         <columns>