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._location_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]);
89 hard_empty(this.entry_tbody);
91 /* XXX incredibly, running hard_empty() more than once seems to be
92 * good and necessary. There's a bug under the covers somewhere,
93 * but this keeps it out of sight for the moment. */
94 hard_empty(this.entry_tbody);
96 hard_empty(this.entry_tbody);
102 this.bib_lookup(bib_id, null, true);
107 this._clear_entry_batch_row = function() {
109 dojo.byId("entry_batch_row").childNodes,
111 if (node.nodeType == 1 &&
112 node.getAttribute("name") != "barcode")
118 this._show_bibdata_bits = function() {
119 hard_empty("title_here");
120 dojo.byId("title_here").appendChild(T(this.bibdata.mvr.title()));
121 hard_empty("author_here");
123 if (this.bibdata.mvr.author()) {
124 dojo.byId("author_here").appendChild(T(this.bibdata.mvr.author()));
125 show("author_here_holder");
127 hide("author_here_holder");
130 show("batch_receive_bibdata_bits");
133 this._sub_label = function(sub) {
134 /* XXX use a formatting string from serial.properties */
135 return sub.id() + ": (" + sub.owning_lib().shortname() + ") " +
136 D(sub.start_date()) + " - " + D(sub.end_date());
139 this._show_sub_bits = function() {
140 hard_empty("sublabel_here");
142 T(this._sub_label(this.sub)),
146 hide("batch_receive_sub");
147 show("batch_receive_sub_bits");
150 this._show_issuance_bits = function() {
151 hide("batch_receive_issuance");
152 hard_empty("issuance_label_here");
154 T(this.issuance.label()),
155 "issuance_label_here",
158 show("batch_receive_issuance_bits");
161 this._get_receivable_issuances = function() {
166 fieldmapper.standardRequest(
167 ["open-ils.serial", "open-ils.serial.issuances.receivable"], {
168 "params": [authtoken, this.sub.id()],
170 "onresponse": function(r) {
171 if (r = openils.Util.readResponse(r))
184 this._build_circ_modifier_dropdown = function() {
185 if (!this._built_circ_modifier_dropdown) {
186 var menulist = dojo.create("menulist");
187 var menupopup = dojo.create("menupopup", null, menulist, "only");
189 "menuitem", {"value": 0, "label": S("none")},
194 fieldmapper.standardRequest(
195 ["open-ils.circ", "open-ils.circ.circ_modifier.retrieve.all"],{
196 "params": [{"full": true}],
198 "onresponse": function(r) {
199 if (mods = openils.Util.readResponse(r)) {
202 return a.code() > b.code() ? 1 :
203 b.code() > a.code() ? -1 :
211 /* XXX use format string */
212 "label": mod.code()+" "+mod.name()
222 /* in this case, discard menulist and menupopup */
223 this._built_circ_modifier_dropdown =
224 dojo.create("description", {"value": "-"});
226 this._built_circ_modifier_dropdown = menulist;
230 return dojo.clone(this._built_circ_modifier_dropdown);
233 this._extend_circ_modifier_for_batch = function(control) {
235 "menuitem", {"value": -1, "label": "---"},
236 dojo.query("menupopup", control)[0],
242 this._build_location_dropdown = function(locs, add_unset_value) {
243 var menulist = dojo.create("menulist");
244 var menupopup = dojo.create("menupopup", null, menulist, "only");
246 if (add_unset_value) {
248 "menuitem", {"value": -1, "label": "---"}, menupopup, "first"
257 "label": "(" + loc.owning_lib().shortname() + ") " +
258 loc.name() /* XXX i18n */
267 this._get_locations_for_lib = function(lib) {
268 if (!this._location_by_lib[lib]) {
269 fieldmapper.standardRequest(
270 ["open-ils.circ", "open-ils.circ.copy_location.retrieve.all"],{
271 "params": [lib, false, true],
273 "onresponse": function(r) {
274 if (locs = openils.Util.readResponse(r))
275 self._location_by_lib[lib] = locs;
281 return this._location_by_lib[lib];
284 this._build_receive_toggle = function(item) {
287 "oncommand": function(ev) {
288 self._disable_row(item.id(), !ev.target.checked);
295 this._disable_row = function(item_id, disabled) {
296 var row = this.rows[item_id];
297 dojo.query("textbox,menulist", row).forEach(
298 function(element) { element.disabled = disabled; }
302 this._row_disabled = function(row) {
303 if (typeof(row) == "string") row = this.rows[row];
304 return !dojo.query("checkbox", row)[0].checked;
307 this._row_field_value = function(row, field, value) {
308 if (typeof(row) == "string") row = this.rows[row];
310 var node = dojo.query("*", node_by_name(field, row))[0];
312 if (typeof(value) == "undefined")
318 this._user_wants_autogen = function() {
319 return dojo.byId("autogen_barcodes").checked;
322 this._get_autogen_potentials = function(item_id) {
323 var hit_a_wall = false;
325 return [openils.Util.objectProperties(this.rows).sort(num_sort).filter(
329 } else if (id <= item_id || self._row_disabled(id)) {
331 } else if (self._row_field_value(id, "barcode")) {
341 this._prepare_autogen_control = function() {
342 dojo.attr("autogen_barcodes",
343 "command", function(ev) {
344 if (!ev.target.checked) {
345 var list = self._have_autogen_barcodes();
346 if (list.length && confirm(S("autogen_barcodes.remove"))) {
349 self._row_field_value(id, "barcode", "");
350 self.rows[id]._has_autogen_barcode = false;
359 this._have_autogen_barcodes = function() {
361 for (var id in this.rows)
362 if (this.rows[id]._has_autogen_barcode) list.push(id);
366 this._set_all_enabled_rows = function(key, value) {
367 /* do NOT do trimming here, set whitespace as is. */
368 for (var id in this.rows) {
369 if (!this._row_disabled(id))
370 this._row_field_value(id, key, value);
374 this.bib_lookup = function(bib_search_term, evt, is_actual_id) {
375 if (evt && evt.keyCode != 13) return;
377 if (!bib_search_term) {
378 var bib_search_term = dojo.byId("bib_search_term").value.trim();
379 if (!bib_search_term.length) {
380 alert(S("bib_lookup.empty"));
385 hide("batch_receive_sub");
386 hide("batch_receive_entry");
389 dojo.byId("bib_lookup_submit").disabled = true;
390 fieldmapper.standardRequest(
392 "open-ils.serial.biblio.record_entry.by_identifier.atomic"], {
395 "require_subscriptions": true,
397 "is_actual_id": is_actual_id
401 "oncomplete": function(r) {
402 /* These two things better come before readResponse(),
403 * which can throw exceptions. */
405 dojo.byId("bib_lookup_submit").disabled = false;
407 var list = openils.Util.readResponse(r, false, true);
408 if (list && list.length) {
409 if (list.length > 1) {
410 /* XXX TODO just let the user pick one from a list,
411 * although this circumstance seems really
412 * unlikely. It just can't happen for TCN, and
413 * wouldn't be likely for ISxN or UPC... ? */
414 alert(S("bib_lookup.multiple"));
416 self.bibdata = list[0];
417 self._show_bibdata_bits();
418 self.choose_subscription();
421 alert(S("bib_lookup.not_found"));
425 dojo.byId("bib_search_term").reset();
426 dojo.byId("bib_search_term").focus();
434 this.choose_subscription = function() {
435 hide("batch_receive_bib");
436 hide("batch_receive_entry");
437 hide("batch_receive_sub_bits");
438 hide("batch_receive_issuance");
440 var subs = this.bibdata.bre.subscriptions();
442 if (subs.length > 1) {
443 var menulist = dojo.create("menulist", {"id": "sub_chooser"});
444 var menupopup = dojo.create("menupopup", {}, menulist, "only");
446 this.bibdata.bre.subscriptions().forEach(
450 "label": self._sub_label(sub),
457 hard_empty(dojo.byId("sub_chooser_here"));
459 dojo.place(menulist, dojo.byId("sub_chooser_here"), "only");
460 show("batch_receive_sub");
462 this.choose_issuance(subs[0]);
466 this.choose_issuance = function(sub) {
467 hide("batch_receive_bib");
468 hide("batch_receive_entry");
469 hide("batch_receive_sub");
471 if (typeof(sub) == "undefined") { /* sub chosen from menu */
472 var sub_id = dojo.byId("sub_chooser").value;
473 this.sub = this.bibdata.bre.subscriptions().filter(
474 function(o) { return o.id() == sub_id; }
476 } else { /* only one sub possible, passed in directly */
480 this._show_sub_bits();
482 this.issuances = this._get_receivable_issuances(); /* sync */
484 if (this.issuances.length > 1) {
485 var menulist = dojo.create("menulist", {"id": "issuance_chooser"});
486 var menupopup = dojo.create("menupopup", {}, menulist, "only");
490 if (a.date_published()>b.date_published()) return 1;
491 else if (b.date_published()>a.date_published()) return -1;
498 "label": issuance.label(),
499 "value": issuance.id()
505 hard_empty("issuance_chooser_here");
506 dojo.place(menulist, dojo.byId("issuance_chooser_here"), "only");
508 show("batch_receive_issuance");
509 } else if (this.issuances.length) {
510 this.load_entry_form(this.issuances[0]);
512 alert(S("issuance_lookup.none"));
518 this.load_entry_form = function(issuance) {
519 if (typeof(issuance) == "undefined") {
520 var issuance_id = dojo.byId("issuance_chooser").value;
521 this.issuance = this.issuances.filter(
522 function(o) { return o.id() == issuance_id; }
525 this.issuance = issuance;
528 this._show_issuance_bits();
529 this._prepare_autogen_control();
533 fieldmapper.standardRequest(
535 "open-ils.serial.items.receivable.by_issuance.atomic"], {
536 "params": [authtoken, this.issuance.id()],
538 "onresponse": function(r) {
541 if (list = openils.Util.readResponse(r, false, true)) {
547 list.forEach(function(o) {self.add_entry_row(o);});
548 if (list.length > 1) {
549 self.build_batch_entry_row();
550 show("batch_receive_entry");
555 alert(S("item_lookup.none"));
556 if (self.issuances.length) self.choose_issuance();
566 this.build_batch_entry_row = function() {
567 var row = dojo.byId("entry_batch_row");
569 this.batch_controls = {};
571 node_by_name("note", row).appendChild(
572 this.batch_controls.note = dojo.create("textbox", {"size": 20})
575 node_by_name("location", row).appendChild(
576 this.batch_controls.location = this._build_location_dropdown(
577 /* XXX TODO build a smarter list. rather than all copy locs
578 * under OU #1, try building a list of copy locs available to
579 * all OUs represented in actual items */
580 this._get_locations_for_lib(1),
581 true /* add_unset_value */
585 node_by_name("circ_modifier", row).appendChild(
586 this.batch_controls.circ_modifier =
587 this._extend_circ_modifier_for_batch(
588 this._build_circ_modifier_dropdown()
592 node_by_name("price", row).appendChild(
593 this.batch_controls.price = dojo.create("textbox", {"size": 9})
596 node_by_name("apply", row).appendChild(
597 dojo.create("button", {
599 "oncommand": function() { self.apply_batch_values(); }
604 this.apply_batch_values = function() {
605 var row = dojo.byId("entry_batch_row");
607 for (var key in this.batch_controls) {
608 var value = this.batch_controls[key].value;
609 if (value != "" && value != -1)
610 this._set_all_enabled_rows(key, value);
614 this.add_entry_row = function(item) {
615 this.item_cache[item.id()] = item;
616 var row = this.rows[item.id()] = dojo.clone(this.template);
618 function n(s) { return node_by_name(s, row); } /* typing saver */
620 n("holding_lib").appendChild(
621 T(item.stream().distribution().holding_lib().shortname())
624 n("barcode").appendChild(
628 "tabindex": 10000 + Number(item.id()), /* is this right? */
629 "onchange": function() {
630 self.autogen_if_appropriate(this, item.id());
636 n("location").appendChild(
637 this._build_location_dropdown(
638 this._get_locations_for_lib(
639 item.stream().distribution().holding_lib().id()
644 n("note").appendChild(dojo.create("textbox", {"size": 20}));
645 n("circ_modifier").appendChild(this._build_circ_modifier_dropdown());
646 n("price").appendChild(dojo.create("textbox", {"size": 9}));
647 n("receive").appendChild(this._build_receive_toggle(item));
649 this.entry_tbody.appendChild(row);
652 this.receive = function() {
654 for (var id in this.rows) {
655 if (this._row_disabled(id))
658 var item = this.item_cache[id];
660 var barcode = this._row_field_value(id, "barcode");
662 var unit = new sunit();
663 unit.barcode(barcode);
665 ["price", "location", "circ_modifier"].forEach(
667 var value = self._row_field_value(id, field).trim();
668 if (value) unit[field](value);
676 var note_value = this._row_field_value(id, "note").trim();
678 var note = new sin();
681 note.title(S("receive_time_note"));
682 note.value(note_value);
691 fieldmapper.standardRequest(
692 ["open-ils.serial", "open-ils.serial.receive_items.one_unit_per"],{
693 "params": [authtoken, items],
695 "oncomplete": function(r) {
697 while (item_id = openils.Util.readResponse(r))
698 self.finish_receipt(item_id);
708 this.finish_receipt = function(item_id) {
709 hard_empty(this.rows[item_id]);
710 dojo.destroy(this.rows[item_id]);
711 delete this.rows[item_id];
712 delete this.item_cache[item_id];
715 this.autogen_if_appropriate = function(textbox, item_id) {
716 if (this._user_wants_autogen() && textbox.value) {
717 var [list, question] = this._get_autogen_potentials(item_id);
719 if (question && !confirm(S("autogen_barcodes.questionable")))
724 fieldmapper.standardRequest(
725 ["open-ils.cat", "open-ils.cat.item.barcode.autogen"], {
726 "params": [authtoken, textbox.value, list.length],
728 "onresponse": function(r) {
729 r = openils.Util.readResponse(r, false, true);
731 for (var i = 0; i < r.length; i++) {
732 var row = self.rows[list[i]];
733 self._row_field_value(
736 row._has_autogen_barcode = true;
746 } /* do nothing for empty list */
750 this._init.apply(this, arguments);
754 var cgi = new openils.CGI();
756 authtoken = (typeof ses == "function" ? ses() : 0) ||
757 cgi.param("ses") || dojo.cookie("ses");
759 batch_receiver = new BatchReceiver(cgi.param("docid") || null);