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");
7 dojo.require("dojo.string");
9 function Populator(widgets, primary_input) {
10 this.widgets = widgets;
13 for (var k in widgets) this.all.push(k);
15 if (primary_input) this.primary_input = primary_input;
18 this.prepare_empty_stores();
21 Populator.prototype.prepare_cache = function(data) {
23 for (var k in this.all) this.cache[this.all[k]] = {};
25 Populator.prototype.prepare_empty_stores = function(data) {
26 this.empty_stores = {};
28 for (var i in this.all) {
29 var name = this.all[i];
31 if (this.widgets[name] && this["flatten_" + name]) {
32 this.empty_stores[name] =
33 new dojo.data.ItemFileReadStore({
34 "data": this["flatten_" + name]([])
36 this.widgets[name].setStore(this.empty_stores[name]);
40 Populator.prototype.flatten_ready = function(data) {
44 "items": data.map(function(o) {
47 "type": o.target_resource_type().name(),
48 "resource": o.current_resource().barcode(),
49 "start_time": humanize_timestamp_string(o.start_time()),
50 "end_time": humanize_timestamp_string(o.end_time())
55 Populator.prototype.flatten_out = function(data) {
59 "items": data.map(function(o) {
62 "type": o.target_resource_type().name(),
63 "resource": o.current_resource().barcode(),
64 "pickup_time": humanize_timestamp_string(o.pickup_time()),
65 "end_time": humanize_timestamp_string(o.end_time())
70 Populator.prototype.flatten_in = function(data) {
74 "items": data.map(function(o) {
77 "type": o.target_resource_type().name(),
78 "resource": o.current_resource().barcode(),
79 "due_time": humanize_timestamp_string(o.end_time()),
80 "return_time": humanize_timestamp_string(o.return_time())
85 Populator.prototype.reveal_container = function(widget) {
86 var el = document.getElementById("contains_" + widget.id);
87 if (el) reveal_dom_element(el);
89 Populator.prototype.hide_container = function(widget) {
90 var el = document.getElementById("contains_" + widget.id);
91 if (el) hide_dom_element(el);
93 Populator.prototype.populate_ready = function(data) {
94 return this._populate_any_resv_grid(data, "ready");
96 Populator.prototype.populate_out = function(data) {
97 return this._populate_any_resv_grid(data, "out");
99 Populator.prototype.populate_in = function(data) {
100 return this._populate_any_resv_grid(data, "in");
102 Populator.prototype._populate_any_resv_grid = function(data, which) {
103 var flattener = this["flatten_" + which];
104 var widget = this.widgets[which];
105 var cache = this.cache[which];
106 var empty_store = this.empty_stores[which];
108 this.reveal_container(widget);
110 if (!data || !data.length) {
111 widget.setStore(empty_store);
112 this.toggle_anyness(false, which);
114 for (var i in data) cache[data[i].id()] = data[i];
117 new dojo.data.ItemFileReadStore({"data": flattener(data)})
120 this.toggle_anyness(true, which);
122 /* Arrrgh! Horrid but necessary: */
123 setTimeout(function() { widget.sort(); }, 100);
126 Populator.prototype.populate_patron = function(data) {
127 var h2 = document.createElement("h2");
128 h2.setAttribute("class", "booking");
129 h2.appendChild(document.createTextNode(formal_name(data)));
131 this.widgets.patron.innerHTML = "";
132 this.widgets.patron.appendChild(h2);
134 this.reveal_container(this.widgets.patron);
135 /* Maybe add patron's home OU or something here later... */
137 Populator.prototype.return_by_resource = function(barcode, override) {
138 /* XXX instead of talking to the server every time we do this, we could
139 * also check the "out" cache, iff we have one. */
140 var r = fieldmapper.standardRequest(
142 "open-ils.booking.reservations.by_returnable_resource_barcode"],
143 [openils.User.authtoken, barcode]
145 if (!r || r.length < 1) {
146 alert(localeStrings.NO_SUCH_RETURNABLE_RESOURCE);
147 } else if (is_ils_event(r)) {
148 alert(my_ils_error(localeStrings.RETURNABLE_RESOURCE_ERROR, r));
151 var new_barcode = r.usr().card().barcode();
153 alert(localeStrings.RETURN_ERROR + "\nr: " + js2JSON(r) + "\n" + E);
156 if (this.patron_barcode && this.patron_barcode != new_barcode) {
157 /* XXX make this more subtle, i.e. flash something in background */
158 alert(localeStrings.NOTICE_CHANGE_OF_PATRON);
160 this.patron_barcode = new_barcode;
161 var ret = this.return(r, override);
163 alert(localeStrings.RETURN_NO_RESPONSE);
164 } else if (is_ils_event(ret) && ret.textcode != "SUCCESS") {
165 if (ret.textcode == "ROUTE_ITEM") {
166 display_transit_slip(ret);
167 } else if (ret.textcode == "COPY_ALERT_MESSAGE") {
170 dojo.string.substitute(
171 localeStrings.COPY_ALERT, [ret.desc, ret.payload]
175 this.return_by_resource(barcode, true /*override*/);
179 alert(my_ils_error(localeStrings.RETURN_ERROR, ret));
182 /* XXX speedbump should go, but something has to happen else
183 * there's no indication to staff that anything happened when
184 * starting from a fresh (blank) return interface.
186 alert(localeStrings.RETURN_SUCCESS);
188 this.populate(); /* Won't recurse with no args. All is well. */
191 Populator.prototype.populate = function(barcode, which) {
193 if (barcode.patron) {
194 this.patron_barcode = barcode.patron;
196 else if (barcode.resource) { /* resource OR patron, not both */
197 if (!this.return_by_resource(barcode.resource))
201 if (!this.patron_barcode) {
202 alert(localeStrings.NO_PATRON_BARCODE);
206 if (!which) which = this.all;
208 var result = fieldmapper.standardRequest(
209 ["open-ils.booking", "open-ils.booking.reservations.get_captured"],
210 [openils.User.authtoken, this.patron_barcode, which]
214 this.patron_barcode = undefined;
215 alert(localeStrings.RESERVATIONS_NO_RESPONSE);
216 } else if (is_ils_event(result)) {
217 this.patron_barcode = undefined;
218 alert(my_ils_error(localeStrings.RESERVATIONS_ERROR, result));
220 for (var k in result)
221 this["populate_" + k](result[k]);
224 Populator.prototype.toggle_anyness = function(any, which) {
225 var widget = this.widgets[which].domNode;
226 var empty_alternate = document.getElementById("no_" + widget.id);
227 var controls = document.getElementById("controls_" + widget.id);
229 reveal_dom_element(widget);
230 if (empty_alternate) hide_dom_element(empty_alternate);
231 if (controls) reveal_dom_element(controls);
233 hide_dom_element(widget);
234 if (empty_alternate) reveal_dom_element(empty_alternate);
235 if (controls) hide_dom_element(controls);
238 Populator.prototype.pickup = function(reservation) {
239 return fieldmapper.standardRequest(
240 ["open-ils.circ", "open-ils.circ.reservation.pickup"],
241 [openils.User.authtoken, {
242 "patron_barcode": this.patron_barcode,
243 "reservation": reservation
247 Populator.prototype.return = function(reservation, override) {
248 var method = "open-ils.circ.reservation.return";
249 if (override) method += ".override";
250 return fieldmapper.standardRequest(
251 ["open-ils.circ", method],
252 [openils.User.authtoken, {
253 "patron_barcode": this.patron_barcode,
254 "reservation": reservation.id()
255 /* yeah just id here ------^; lack of parallelism */
259 Populator.prototype.act_on_selected = function(how, which) {
260 var widget = this.widgets[which];
261 var cache = this.cache[which];
262 var no_response_msg = localeStrings[how.toUpperCase() + "_NO_RESPONSE"];
263 var error_msg = localeStrings[how.toUpperCase() + "_ERROR"];
265 var selected_id_list =
266 widget.selection.getSelected().map(function(o) { return o.id[0]; });
268 if (!selected_id_list || !selected_id_list.length) {
269 alert(localeStrings.SELECT_SOMETHING);
273 var reservations = selected_id_list.map(function(o) { return cache[o]; });
275 /* Do we have to process these one at a time? I think so... */
277 function looper(reservation, override) {
278 if (looper._done) return;
279 var result = self[how](reservation, override);
281 alert(no_response_msg);
282 } else if (is_ils_event(result) && result.textcode != "SUCCESS") {
283 if (result.textcode == "ROUTE_ITEM") {
284 display_transit_slip(result);
285 } else if (result.textcode == "COPY_ALERT_MESSAGE") {
287 dojo.string.substitute(
288 localeStrings.COPY_ALERT, [result.desc, result.payload]
291 looper(reservation, true);
293 return; // continues processing other resvs
295 alert(my_ils_error(error_msg, result));
302 dojo.forEach(reservations, looper);
306 Populator.prototype.reset = function() {
307 for (var k in this.widgets) {
308 this.hide_container(this.widgets[k]);
310 this.patron_barcode = undefined;
312 if (typeof(this._extra_resetting) == "function")
313 this._extra_resetting();
315 if (this.primary_input) {
316 this.primary_input.value = "";
317 this.primary_input.focus();
321 /* XXX needs to be combined with the code that shows transit slips in the
322 * booking capture interface. */
323 function display_transit_slip(e) {
324 var ou = fieldmapper.aou.findOrgUnit(e.org, /* slim_ok */false);
325 var ma = (new openils.PermaCrud()).retrieve("aoa", ou.mailing_address());
327 dojo.string.substitute(
328 localeStrings.ADDRESS,
329 [ma.street1(),ma.street2(),ma.city(),ma.state(),ma.post_code()].map(
330 function(o) { return o ? o : ""; }
332 ).replace("\n\n", "\n").replace("\n", "<br />") : "[Unknown address]";
333 /* XXX i18n and/or template */
335 var win = window.open(
336 "","","resizeable,width=600,height=400,scrollbars=1"
338 win.document.body.innerHTML =
339 "<h1>Transit Slip</h1>\n" +
340 //"<img src='/xul/server/skin/media/images/turtle.gif' />\n" +
341 "<p>Destination: <strong>" + ou.name() + "</strong></p>\n" +
342 "<p>" + mas + "</p>\n" +
343 "<p>Barcode: " + e.payload.copy.barcode() + "<br />\n" +
344 "Title: <span id='title'></span><br />\n" +
345 "Author: <span id='author'></span><br />\n" +
347 dojo.date.locale.format(new Date(), {"formatLength": "short"}) +
349 fieldmapper.standardRequest(
350 ["open-ils.search", "open-ils.search.biblio.mods_from_copy"], {
351 "params": [e.payload.copy.id()],
353 "onresponse": function(r) {
354 var mvr = openils.Util.readResponse(r);
355 dojo.byId("title", win.document).innerHTML = mvr.title();
356 dojo.byId("author", win.document).innerHTML = mvr.author();
358 "oncomplete": function() {
359 win[confirm("Print transit slip?") ? "print" : "close"]();
364 alert("exception rendering transit slip: " + E); // XXX