1 dojo.require("dojo.cookie");
2 dojo.require("dojo.date.locale");
3 dojo.require("dojo.date.stamp");
4 dojo.require("openils.Util");
5 dojo.require("openils.CGI");
10 String.prototype.trim = function() {return this.replace(/^\s*(.+)\s*$/,"$1");}
13 * hard_empty() is needed because dojo.empty() doesn't seem to work on
14 * XUL nodes. This also means that dojo.place() with a position argument of
15 * "only" doesn't do what it should, but calling hard_empty() on the refnode
16 * first will do the trick.
18 function hard_empty(node) {
19 if (typeof(node) == "string")
20 node = dojo.byId(node);
22 dojo.forEach(node.childNodes, dojo.destroy);
26 if (typeof(e) == "string") e = dojo.byId(e);
27 openils.Util.addCSSClass(e, "hideme");
31 if (typeof(e) == "string") e = dojo.byId(e);
32 openils.Util.removeCSSClass(e, "hideme");
36 if (typeof(busy._window) == "undefined")
37 busy._window = dojo.query("window")[0];
38 busy._window.style.cursor = on ? "wait" : "auto";
42 return dojo.byId("serialStrings").getString("batch_receive." + k).
46 function T(s) { return document.createTextNode(s); }
47 function D(s) {return s ? openils.Util.timeStamp(s, {"selector":"date"}) : "";}
48 function node_by_name(s, ctx) {return dojo.query("[name='" + s + "']", ctx)[0];}
50 function num_sort(a, b) {
51 [a, b] = [Number(a), Number(b)];
52 return a > b ? 1 : (a < b ? -1 : 0);
55 function BatchReceiver() {
58 this._init = function(bib_id) {
59 hide("batch_receive_sub");
60 hide("batch_receive_entry");
61 hide("batch_receive_bibdata_bits");
62 hide("batch_receive_sub_bits");
63 hide("batch_receive_issuance_bits");
64 hide("batch_receive_issuance");
66 dojo.byId("bib_lookup_submit").disabled = false;
67 dojo.byId("bib_search_term").value = "";
70 show("batch_receive_bib");
71 dojo.byId("bib_search_term").focus();
74 if (!this.entry_tbody) {
75 this.entry_tbody = dojo.byId("entry_tbody");
76 this.template = this.entry_tbody.removeChild(
77 dojo.byId("entry_template")
81 this._clear_entry_batch_row();
83 this._copy_loc_by_lib = {};
85 /* empty the entry receiving table if we're starting over */
86 if (this.item_cache) {
87 for (var id in this.item_cache)
88 this.finish_receipt(this.item_cache[id]);
95 this.bib_lookup(bib_id, null, true);
100 this._clear_entry_batch_row = function() {
102 dojo.byId("entry_batch_row").childNodes,
104 if (node.nodeType == 1 &&
105 node.getAttribute("name") != "barcode")
111 this._show_bibdata_bits = function() {
112 hard_empty("title_here");
113 dojo.byId("title_here").appendChild(T(this.bibdata.mvr.title()));
114 hard_empty("author_here");
116 if (this.bibdata.mvr.author()) {
117 dojo.byId("author_here").appendChild(T(this.bibdata.mvr.author()));
118 show("author_here_holder");
120 hide("author_here_holder");
123 show("batch_receive_bibdata_bits");
126 this._sub_label = function(sub) {
127 /* XXX use a formatting string from serial.properties */
128 return sub.id() + ": (" + sub.owning_lib().shortname() + ") " +
129 D(sub.start_date()) + " - " + D(sub.end_date());
132 this._show_sub_bits = function() {
133 hard_empty("sublabel_here");
135 T(this._sub_label(this.sub)),
139 hide("batch_receive_sub");
140 show("batch_receive_sub_bits");
143 this._show_issuance_bits = function() {
144 hide("batch_receive_issuance");
145 hard_empty("issuance_label_here");
147 T(this.issuance.label()),
148 "issuance_label_here",
151 show("batch_receive_issuance_bits");
154 this._get_receivable_issuances = function() {
159 fieldmapper.standardRequest(
160 ["open-ils.serial", "open-ils.serial.issuances.receivable"], {
161 "params": [authtoken, this.sub.id()],
163 "onresponse": function(r) {
164 if (r = openils.Util.readResponse(r))
177 this._build_circ_mod_dropdown = function() {
178 if (!this._built_circ_mod_dropdown) {
179 var menulist = dojo.create("menulist");
180 var menupopup = dojo.create("menupopup", null, menulist, "only");
182 "menuitem", {"value": 0, "label": S("none")},
187 fieldmapper.standardRequest(
188 ["open-ils.circ", "open-ils.circ.circ_modifier.retrieve.all"], {
191 "onresponse": function(r) {
192 if (mods = openils.Util.readResponse(r)) {
197 "value": mod, "label": mod
207 /* in this case, discard menulist and menupopup */
208 this._built_circ_mod_dropdown =
209 dojo.create("description", {"value": "-"});
211 this._built_circ_mod_dropdown = menulist;
215 return dojo.clone(this._built_circ_mod_dropdown);
218 this._extend_circ_mod_for_batch = function(control) {
220 "menuitem", {"value": -1, "label": "---"},
221 dojo.query("menupopup", control)[0],
227 this._build_copy_loc_dropdown = function(locs, add_unset_value) {
228 var menulist = dojo.create("menulist");
229 var menupopup = dojo.create("menupopup", null, menulist, "only");
231 if (add_unset_value) {
233 "menuitem", {"value": -1, "label": "---"}, menupopup, "first"
242 "label": "(" + loc.owning_lib().shortname() + ") " +
243 loc.name() /* XXX i18n */
252 this._get_copy_locs_for_lib = function(lib) {
253 if (!this._copy_loc_by_lib[lib]) {
254 fieldmapper.standardRequest(
255 ["open-ils.circ", "open-ils.circ.copy_location.retrieve.all"], {
256 "params": [lib, false, true],
258 "onresponse": function(r) {
259 if (locs = openils.Util.readResponse(r))
260 self._copy_loc_by_lib[lib] = locs;
266 return this._copy_loc_by_lib[lib];
269 this._build_receive_toggle = function(item) {
272 "oncommand": function(ev) {
273 self._disable_row(item.id(), !ev.target.checked);
280 this._disable_row = function(item_id, disabled) {
281 var row = this.rows[item_id];
282 dojo.query("textbox,menulist", row).forEach(
283 function(element) { element.disabled = disabled; }
287 this._row_disabled = function(row) {
288 if (typeof(row) == "string") row = this.rows[row];
289 return !dojo.query("checkbox", row)[0].checked;
292 this._row_field_value = function(row, field, value) {
293 if (typeof(row) == "string") row = this.rows[row];
295 var node = dojo.query("*", node_by_name(field, row))[0];
297 if (typeof(value) == "undefined")
303 this._user_wants_autogen = function() {
304 return dojo.byId("autogen_barcodes").checked;
307 this._get_autogen_potentials = function(item_id) {
308 var hit_a_wall = false;
310 return [openils.Util.objectProperties(this.rows).sort(num_sort).filter(
314 } else if (id <= item_id || self._row_disabled(id)) {
316 } else if (self._row_field_value(id, "barcode")) {
326 this._prepare_autogen_control = function() {
327 dojo.attr("autogen_barcodes",
328 "command", function(ev) {
329 if (!ev.target.checked) {
330 var list = self._have_autogen_barcodes();
331 if (list.length && confirm(S("autogen_barcodes.remove"))) {
334 self._row_field_value(id, "barcode", "");
335 self.rows[id]._has_autogen_barcode = false;
344 this._have_autogen_barcodes = function() {
346 for (var id in this.rows)
347 if (this.rows[id]._has_autogen_barcode) list.push(id);
351 this._set_all_enabled_rows = function(key, value) {
352 /* do NOT do trimming here, set whitespace as is. */
353 for (var id in this.rows) {
354 if (!this._row_disabled(id))
355 this._row_field_value(id, key, value);
359 this.bib_lookup = function(bib_search_term, evt, is_actual_id) {
360 if (evt && evt.keyCode != 13) return;
362 if (!bib_search_term) {
363 var bib_search_term = dojo.byId("bib_search_term").value.trim();
364 if (!bib_search_term.length) {
365 alert(S("bib_lookup.empty"));
370 hide("batch_receive_sub");
371 hide("batch_receive_entry");
374 dojo.byId("bib_lookup_submit").disabled = true;
375 fieldmapper.standardRequest(
377 "open-ils.serial.biblio.record_entry.by_identifier.atomic"], {
380 "require_subscriptions": true,
382 "is_actual_id": is_actual_id
386 "oncomplete": function(r) {
387 /* These two things better come before readResponse(), which
388 * can throw exceptions. */
390 dojo.byId("bib_lookup_submit").disabled = false;
392 var list = openils.Util.readResponse(r, false, true);
393 if (list && list.length) {
394 if (list.length > 1) {
395 /* XXX TODO just let the user pick one from a list,
396 * although this circumstance seems really
397 * unlikely. It just can't happen for TCN, and
398 * wouldn't be likely for ISxN or UPC... ? */
399 alert(S("bib_lookup.multiple"));
401 self.bibdata = list[0];
402 self._show_bibdata_bits();
403 self.choose_subscription();
406 alert(S("bib_lookup.not_found"));
410 dojo.byId("bib_search_term").reset();
411 dojo.byId("bib_search_term").focus();
419 this.choose_subscription = function() {
420 hide("batch_receive_bib");
421 hide("batch_receive_entry");
422 hide("batch_receive_sub_bits");
423 hide("batch_receive_issuance");
425 var subs = this.bibdata.bre.subscriptions();
427 if (subs.length > 1) {
428 var menulist = dojo.create("menulist", {"id": "sub_chooser"});
429 var menupopup = dojo.create("menupopup", {}, menulist, "only");
431 this.bibdata.bre.subscriptions().forEach(
435 "label": self._sub_label(sub),
442 hard_empty(dojo.byId("sub_chooser_here"));
444 dojo.place(menulist, dojo.byId("sub_chooser_here"), "only");
445 show("batch_receive_sub");
447 this.choose_issuance(subs[0]);
451 this.choose_issuance = function(sub) {
452 hide("batch_receive_bib");
453 hide("batch_receive_entry");
454 hide("batch_receive_sub");
456 if (typeof(sub) == "undefined") { /* sub chosen from menu */
457 var sub_id = dojo.byId("sub_chooser").value;
458 this.sub = this.bibdata.bre.subscriptions().filter(
459 function(o) { return o.id() == sub_id; }
461 } else { /* only one sub possible, passed in directly */
465 this._show_sub_bits();
467 this.issuances = this._get_receivable_issuances(); /* sync */
469 if (this.issuances.length > 1) {
470 var menulist = dojo.create("menulist", {"id": "issuance_chooser"});
471 var menupopup = dojo.create("menupopup", {}, menulist, "only");
475 if (a.date_published() > b.date_published()) return 1;
476 else if (b.date_published() > a.date_published()) return -1;
483 "label": issuance.label(),
484 "value": issuance.id()
490 hard_empty("issuance_chooser_here");
491 dojo.place(menulist, dojo.byId("issuance_chooser_here"), "only");
493 show("batch_receive_issuance");
494 } else if (this.issuances.length) {
495 this.load_entry_form(this.issuances[0]);
497 alert(S("issuance_lookup.none"));
503 this.load_entry_form = function(issuance) {
504 if (typeof(issuance) == "undefined") {
505 var issuance_id = dojo.byId("issuance_chooser").value;
506 this.issuance = this.issuances.filter(
507 function(o) { return o.id() == issuance_id; }
510 this.issuance = issuance;
513 this._show_issuance_bits();
514 this._prepare_autogen_control();
518 fieldmapper.standardRequest(
520 "open-ils.serial.items.receivable.by_issuance.atomic"], {
521 "params": [authtoken, this.issuance.id()],
523 "onresponse": function(r) {
526 if (list = openils.Util.readResponse(r, false, true)) {
532 list.forEach(function(o) {self.add_entry_row(o);});
533 if (list.length > 1) {
534 self.build_batch_entry_row();
535 show("batch_receive_entry");
540 alert(S("item_lookup.none"));
541 if (self.issuances.length) self.choose_issuance();
551 this.build_batch_entry_row = function() {
552 var row = dojo.byId("entry_batch_row");
554 this.batch_controls = {};
556 node_by_name("note", row).appendChild(
557 this.batch_controls.note = dojo.create("textbox", {"size": 20})
560 node_by_name("copy_loc", row).appendChild(
561 this.batch_controls.copy_loc = this._build_copy_loc_dropdown(
562 /* XXX is 1 really the right value below? */
563 this._get_copy_locs_for_lib(1),
564 true /* add_unset_value */
568 node_by_name("circ_mod", row).appendChild(
569 this.batch_controls.circ_mod = this._extend_circ_mod_for_batch(
570 this._build_circ_mod_dropdown()
574 node_by_name("price", row).appendChild(
575 this.batch_controls.price = dojo.create("textbox", {"size": 9})
578 node_by_name("apply", row).appendChild(
579 dojo.create("button", {
581 "oncommand": function() { self.apply_batch_values(); }
586 this.apply_batch_values = function() {
587 var row = dojo.byId("entry_batch_row");
589 for (var key in this.batch_controls) {
590 var value = this.batch_controls[key].value;
591 if (value != "" && value != -1)
592 this._set_all_enabled_rows(key, value);
596 this.add_entry_row = function(item) {
597 this.item_cache[item.id()] = item;
598 var row = this.rows[item.id()] = dojo.clone(this.template);
600 function n(s) { return node_by_name(s, row); } /* typing saver */
602 n("holding_lib").appendChild(
603 T(item.stream().distribution().holding_lib().shortname())
606 n("barcode").appendChild(
610 "tabindex": 10000 + Number(item.id()), /* is this right? */
611 "onchange": function() {
612 self.autogen_if_appropriate(this, item.id());
618 n("copy_loc").appendChild(
619 this._build_copy_loc_dropdown(
620 this._get_copy_locs_for_lib(
621 item.stream().distribution().holding_lib().id()
626 n("note").appendChild(dojo.create("textbox", {"size": 20}));
627 n("circ_mod").appendChild(this._build_circ_mod_dropdown());
628 n("price").appendChild(dojo.create("textbox", {"size": 9}));
629 n("receive").appendChild(this._build_receive_toggle(item));
631 this.entry_tbody.appendChild(row);
634 this.receive = function() {
636 for (var id in this.rows) {
637 /* XXX TODO: get field values, send to ML,
638 * and yes do trimming here. */
639 if (!this._row_disabled(id)) recv_ids.push(id);
643 fieldmapper.standardRequest(
644 ["open-ils.serial", "open-ils.serial.items.receive_by_id"], {
645 "params": [authtoken, recv_ids],
647 "oncomplete": function(r) {
649 while (item = openils.Util.readResponse(r))
650 self.finish_receipt(item);
660 this.finish_receipt = function(item) {
661 dojo.destroy(this.rows[item.id()]);
662 delete this.rows[item.id()];
663 delete this.item_cache[item.id()];
666 this.autogen_if_appropriate = function(textbox, item_id) {
667 if (this._user_wants_autogen() && textbox.value) {
668 var [list, question] = this._get_autogen_potentials(item_id);
670 if (question && !confirm(S("autogen_barcodes.questionable")))
675 fieldmapper.standardRequest(
676 ["open-ils.cat", "open-ils.cat.item.barcode.autogen"], {
677 "params": [authtoken, textbox.value, list.length],
679 "onresponse": function(r) {
680 r = openils.Util.readResponse(r, false, true);
682 for (var i = 0; i < r.length; i++) {
683 var row = self.rows[list[i]];
684 self._row_field_value(
687 row._has_autogen_barcode = true;
697 } /* do nothing for empty list */
701 this._init.apply(this, arguments);
705 var cgi = new openils.CGI();
707 authtoken = (typeof ses == "function" ? ses() : 0) ||
708 cgi.param("ses") || dojo.cookie("ses");
710 batch_receiver = new BatchReceiver(cgi.param("docid") || null);