1 /* This module depends on common.js being loaded, as well as the
2 * localization (Dojo/nls) for pickup and return . */
4 dojo.require("dojo.data.ItemFileReadStore");
5 dojo.require("dojo.date.locale");
6 dojo.require("openils.PermaCrud");
8 function Populator(widgets, primary_input) {
9 this.widgets = widgets;
12 for (var k in widgets) this.all.push(k);
14 if (primary_input) this.primary_input = primary_input;
17 this.prepare_empty_stores();
20 Populator.prototype.prepare_cache = function(data) {
22 for (var k in this.all) this.cache[this.all[k]] = {};
24 Populator.prototype.prepare_empty_stores = function(data) {
25 this.empty_stores = {};
27 for (var i in this.all) {
28 var name = this.all[i];
30 if (this.widgets[name] && this["flatten_" + name]) {
31 this.empty_stores[name] =
32 new dojo.data.ItemFileReadStore({
33 "data": this["flatten_" + name]([])
35 this.widgets[name].setStore(this.empty_stores[name]);
39 Populator.prototype.flatten_ready = function(data) {
43 "items": data.map(function(o) {
46 "type": o.target_resource_type().name(),
47 "resource": o.current_resource().barcode(),
48 "start_time": humanize_timestamp_string(o.start_time()),
49 "end_time": humanize_timestamp_string(o.end_time())
54 Populator.prototype.flatten_out = function(data) {
58 "items": data.map(function(o) {
61 "type": o.target_resource_type().name(),
62 "resource": o.current_resource().barcode(),
63 "pickup_time": humanize_timestamp_string(o.pickup_time()),
64 "end_time": humanize_timestamp_string(o.end_time())
69 Populator.prototype.flatten_in = function(data) {
73 "items": data.map(function(o) {
76 "type": o.target_resource_type().name(),
77 "resource": o.current_resource().barcode(),
78 "due_time": humanize_timestamp_string(o.end_time()),
79 "return_time": humanize_timestamp_string(o.return_time())
84 Populator.prototype.reveal_container = function(widget) {
85 var el = document.getElementById("contains_" + widget.id);
86 if (el) reveal_dom_element(el);
88 Populator.prototype.hide_container = function(widget) {
89 var el = document.getElementById("contains_" + widget.id);
90 if (el) hide_dom_element(el);
92 Populator.prototype.populate_ready = function(data) {
93 return this._populate_any_resv_grid(data, "ready");
95 Populator.prototype.populate_out = function(data) {
96 return this._populate_any_resv_grid(data, "out");
98 Populator.prototype.populate_in = function(data) {
99 return this._populate_any_resv_grid(data, "in");
101 Populator.prototype._populate_any_resv_grid = function(data, which) {
102 var flattener = this["flatten_" + which];
103 var widget = this.widgets[which];
104 var cache = this.cache[which];
105 var empty_store = this.empty_stores[which];
107 this.reveal_container(widget);
109 if (!data || !data.length) {
110 widget.setStore(empty_store);
111 this.toggle_anyness(false, which);
113 for (var i in data) cache[data[i].id()] = data[i];
116 new dojo.data.ItemFileReadStore({"data": flattener(data)})
119 this.toggle_anyness(true, which);
121 /* Arrrgh! Horrid but necessary: */
122 setTimeout(function() { widget.sort(); }, 100);
125 Populator.prototype.populate_patron = function(data) {
126 var h2 = document.createElement("h2");
127 h2.setAttribute("class", "booking");
128 h2.appendChild(document.createTextNode(formal_name(data)));
130 this.widgets.patron.innerHTML = "";
131 this.widgets.patron.appendChild(h2);
133 this.reveal_container(this.widgets.patron);
134 /* Maybe add patron's home OU or something here later... */
136 Populator.prototype.return_by_resource = function(barcode) {
137 /* XXX instead of talking to the server every time we do this, we could
138 * also check the "out" cache, iff we have one. */
139 var r = fieldmapper.standardRequest(
141 "open-ils.booking.reservations.by_returnable_resource_barcode"],
142 [openils.User.authtoken, barcode]
144 if (!r || r.length < 1) {
145 alert(localeStrings.NO_SUCH_RETURNABLE_RESOURCE);
146 } else if (is_ils_event(r)) {
147 alert(my_ils_error(localeStrings.RETURNABLE_RESOURCE_ERROR, r));
150 var new_barcode = r.usr().card().barcode();
152 alert(localeStrings.RETURN_ERROR + "\nr: " + js2JSON(r) + "\n" + E);
155 if (this.patron_barcode && this.patron_barcode != new_barcode) {
156 /* XXX make this more subtle, i.e. flash something in background */
157 alert(localeStrings.NOTICE_CHANGE_OF_PATRON);
159 this.patron_barcode = new_barcode;
160 var ret = this.return(r);
162 alert(localeStrings.RETURN_NO_RESPONSE);
163 } else if (is_ils_event(ret) && ret.textcode != "SUCCESS") {
164 if (ret.textcode == "ROUTE_ITEM")
165 display_transit_slip(ret);
167 alert(my_ils_error(localeStrings.RETURN_ERROR, ret));
169 /* XXX speedbump should go, but something has to happen else
170 * there's no indication to staff that anything happened when
171 * starting from a fresh (blank) return interface.
173 alert(localeStrings.RETURN_SUCCESS);
175 this.populate(); /* Won't recurse with no args. All is well. */
178 Populator.prototype.populate = function(barcode, which) {
180 if (barcode.patron) {
181 this.patron_barcode = barcode.patron;
183 else if (barcode.resource) { /* resource OR patron, not both */
184 if (!this.return_by_resource(barcode.resource))
188 if (!this.patron_barcode) {
189 alert(localeStrings.NO_PATRON_BARCODE);
193 if (!which) which = this.all;
195 var result = fieldmapper.standardRequest(
196 ["open-ils.booking", "open-ils.booking.reservations.get_captured"],
197 [openils.User.authtoken, this.patron_barcode, which]
201 this.patron_barcode = undefined;
202 alert(localeStrings.RESERVATIONS_NO_RESPONSE);
203 } else if (is_ils_event(result)) {
204 this.patron_barcode = undefined;
205 alert(my_ils_error(localeStrings.RESERVATIONS_ERROR, result));
207 for (var k in result)
208 this["populate_" + k](result[k]);
211 Populator.prototype.toggle_anyness = function(any, which) {
212 var widget = this.widgets[which].domNode;
213 var empty_alternate = document.getElementById("no_" + widget.id);
214 var controls = document.getElementById("controls_" + widget.id);
216 reveal_dom_element(widget);
217 if (empty_alternate) hide_dom_element(empty_alternate);
218 if (controls) reveal_dom_element(controls);
220 hide_dom_element(widget);
221 if (empty_alternate) reveal_dom_element(empty_alternate);
222 if (controls) hide_dom_element(controls);
225 Populator.prototype.pickup = function(reservation) {
226 return fieldmapper.standardRequest(
227 ["open-ils.circ", "open-ils.circ.reservation.pickup"],
228 [openils.User.authtoken, {
229 "patron_barcode": this.patron_barcode,
230 "reservation": reservation
234 Populator.prototype.return = function(reservation) {
235 return fieldmapper.standardRequest(
236 ["open-ils.circ", "open-ils.circ.reservation.return"],
237 [openils.User.authtoken, {
238 "patron_barcode": this.patron_barcode,
239 "reservation": reservation.id()
240 /* yeah just id here ------^; lack of parallelism */
244 Populator.prototype.act_on_selected = function(how, which) {
245 var widget = this.widgets[which];
246 var cache = this.cache[which];
247 var no_response_msg = localeStrings[how.toUpperCase() + "_NO_RESPONSE"];
248 var error_msg = localeStrings[how.toUpperCase() + "_ERROR"];
250 var selected_id_list =
251 widget.selection.getSelected().map(function(o) { return o.id[0]; });
253 if (!selected_id_list || !selected_id_list.length) {
254 alert(localeStrings.SELECT_SOMETHING);
258 var reservations = selected_id_list.map(function(o) { return cache[o]; });
260 /* Do we have to process these one at a time? I think so... */
261 for (var i in reservations) {
262 var result = this[how](reservations[i]);
264 alert(no_response_msg);
265 } else if (is_ils_event(result) && result.textcode != "SUCCESS") {
266 if (result.textcode == "ROUTE_ITEM")
267 display_transit_slip(result);
269 alert(my_ils_error(error_msg, result));
278 Populator.prototype.reset = function() {
279 for (var k in this.widgets) {
280 this.hide_container(this.widgets[k]);
282 this.patron_barcode = undefined;
284 if (typeof(this._extra_resetting) == "function")
285 this._extra_resetting();
287 if (this.primary_input) {
288 this.primary_input.value = "";
289 this.primary_input.focus();
293 /* XXX needs to be combined with the code that shows transit slips in the
294 * booking capture interface. */
295 function display_transit_slip(e) {
296 var ou = fieldmapper.aou.findOrgUnit(e.org, /* slim_ok */false);
297 var ma = (new openils.PermaCrud()).retrieve("aoa", ou.mailing_address());
299 dojo.string.substitute(
300 localeStrings.ADDRESS,
301 [ma.street1(),ma.street2(),ma.city(),ma.state(),ma.post_code()].map(
302 function(o) { return o ? o : ""; }
304 ).replace("\n\n", "\n").replace("\n", "<br />") : "[Unknown address]";
305 /* XXX i18n and/or template */
307 var win = window.open(
308 "","","resizeable,width=600,height=400,scrollbars=1"
310 win.document.body.innerHTML =
311 "<h1>Transit Slip</h1>\n" +
312 //"<img src='/xul/server/skin/media/images/turtle.gif' />\n" +
313 "<p>Destination: <strong>" + ou.name() + "</strong></p>\n" +
314 "<p>" + mas + "</p>\n" +
315 "<p>Barcode: " + e.payload.copy.barcode() + "<br />\n" +
316 "Title: <span id='title'></span><br />\n" +
317 "Author: <span id='author'></span><br />\n" +
319 dojo.date.locale.format(new Date(), {"formatLength": "short"}) +
321 fieldmapper.standardRequest(
322 ["open-ils.search", "open-ils.search.biblio.mods_from_copy"], {
323 "params": [e.payload.copy.id()],
325 "onresponse": function(r) {
326 var mvr = openils.Util.readResponse(r);
327 dojo.byId("title", win.document).innerHTML = mvr.title();
328 dojo.byId("author", win.document).innerHTML = mvr.author();
330 "oncomplete": function() {
331 win[confirm("Print transit slip?") ? "print" : "close"]();
336 alert("exception rendering transit slip: " + E); // XXX