]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/booking/populator.js
Patch from Lebbeous Fogle-Weekley implementing pickup and return interfaces for booki...
[working/Evergreen.git] / Open-ILS / web / js / ui / default / booking / populator.js
1 /* This module depends on common.js being loaded, as well as the
2  * localization (Dojo/nls) for pickup and return . */
3
4 dojo.require("dojo.data.ItemFileReadStore");
5
6 function Populator(widgets, primary_input) {
7     this.widgets = widgets;
8
9     this.all = [];
10     for (var k in widgets) this.all.push(k);
11
12     if (primary_input) this.primary_input = primary_input;
13
14     this.prepare_cache();
15     this.prepare_empty_stores();
16     this.reset();
17 }
18 Populator.prototype.prepare_cache = function(data) {
19     this.cache = {};
20     for (var k in this.all) this.cache[this.all[k]] = {};
21 };
22 Populator.prototype.prepare_empty_stores = function(data) {
23     this.empty_stores = {};
24
25     for (var i in this.all) {
26         var name = this.all[i];
27
28         if (this.widgets[name] && this["flatten_" + name]) {
29             this.empty_stores[name] =
30                 new dojo.data.ItemFileReadStore({
31                     "data": this["flatten_" + name]([])
32                 });
33             this.widgets[name].setStore(this.empty_stores[name]);
34         }
35     }
36 };
37 Populator.prototype.flatten_ready = function(data) {
38     return {
39         "label": "id",
40         "identifier": "id",
41         "items": data.map(function(o) {
42             return {
43                 "id": o.id(),
44                 "type": o.target_resource_type().name(),
45                 "resource": o.current_resource().barcode(),
46                 "start_time": humanize_timestamp_string(o.start_time()),
47                 "end_time": humanize_timestamp_string(o.end_time())
48             };
49         })
50     };
51 };
52 Populator.prototype.flatten_out = function(data) {
53     return {
54         "label": "id",
55         "identifier": "id",
56         "items": data.map(function(o) {
57             return {
58                 "id": o.id(),
59                 "type": o.target_resource_type().name(),
60                 "resource": o.current_resource().barcode(),
61                 "pickup_time": humanize_timestamp_string(o.pickup_time()),
62                 "end_time": humanize_timestamp_string(o.end_time())
63             };
64         })
65     };
66 };
67 Populator.prototype.flatten_in = function(data) {
68     return {
69         "label": "id",
70         "identifier": "id",
71         "items": data.map(function(o) {
72             return {
73                 "id": o.id(),
74                 "type": o.target_resource_type().name(),
75                 "resource": o.current_resource().barcode(),
76                 "due_time": humanize_timestamp_string(o.end_time()),
77                 "return_time": humanize_timestamp_string(o.return_time())
78             };
79         })
80     };
81 };
82 Populator.prototype.reveal_container = function(widget) {
83     var el = document.getElementById("contains_" + widget.id);
84     if (el) reveal_dom_element(el);
85 };
86 Populator.prototype.hide_container = function(widget) {
87     var el = document.getElementById("contains_" + widget.id);
88     if (el) hide_dom_element(el);
89 };
90 Populator.prototype.populate_ready = function(data) {
91     return this._populate_any_resv_grid(data, "ready");
92 };
93 Populator.prototype.populate_out = function(data) {
94     return this._populate_any_resv_grid(data, "out");
95 };
96 Populator.prototype.populate_in = function(data) {
97     return this._populate_any_resv_grid(data, "in");
98 };
99 Populator.prototype._populate_any_resv_grid = function(data, which) {
100     var flattener = this["flatten_" + which];
101     var widget = this.widgets[which];
102     var cache = this.cache[which];
103     var empty_store = this.empty_stores[which];
104
105     this.reveal_container(widget);
106
107     if (!data || !data.length) {
108         widget.setStore(empty_store);
109         this.toggle_anyness(false, which);
110     } else {
111         for (var i in data) cache[data[i].id()] = data[i];
112
113         widget.setStore(
114             new dojo.data.ItemFileReadStore({"data": flattener(data)})
115         );
116
117         this.toggle_anyness(true, which);
118
119         /* Arrrgh! Horrid but necessary: */
120         setTimeout(function() { widget.sort(); }, 100);
121     }
122 };
123 Populator.prototype.populate_patron = function(data) {
124     var h2 = document.createElement("h2");
125     h2.setAttribute("class", "booking");
126     h2.appendChild(document.createTextNode(formal_name(data)));
127
128     this.widgets.patron.innerHTML = "";
129     this.widgets.patron.appendChild(h2);
130
131     this.reveal_container(this.widgets.patron);
132     /* Maybe add patron's home OU or something here later... */
133 };
134 Populator.prototype.return_by_resource = function(barcode) {
135     /* XXX instead of talking to the server every time we do this, we could
136      * also check the "out" cache, iff we have one.  */
137     var r = fieldmapper.standardRequest(
138         ["open-ils.booking",
139         "open-ils.booking.reservations.by_returnable_resource_barcode"],
140         [xulG.auth.session.key, barcode]
141     );
142     if (!r) {
143         alert(localeStrings.NO_SUCH_RETURNABLE_RESOURCE);
144     } else if (is_ils_error(r)) {
145         alert(my_ils_error(localeStrings.RETURNABLE_RESOURCE_ERROR, r));
146     } else {
147         var new_barcode = r.usr().card().barcode();
148         if (this.patron_barcode && this.patron_barcode != new_barcode) {
149             /* XXX make this more subtle, i.e. flash something in background */
150             alert(localeStrings.NOTICE_CHANGE_OF_PATRON);
151         }
152         this.patron_barcode = new_barcode;
153         var ret = this.return(r);
154         if (!ret) {
155             alert(localeStrings.RETURN_NO_RESPONSE);
156         } else if (is_ils_error(ret)) {
157             alert(my_ils_error(localeStrings.RETURN_ERROR, ret));
158         } else {
159             /* XXX speedbump should go, but something has to happen else
160              * there's no indication to staff that anything happened when
161              * starting from a fresh (blank) return interface.
162              */
163             alert(localeStrings.RETURN_SUCCESS);
164         }
165         this.populate(); /* Won't recurse with no args. All is well. */
166     }
167 };
168 Populator.prototype.populate = function(barcode, which) {
169     if (barcode) {
170         if (barcode.patron) {
171             this.patron_barcode = barcode.patron;
172         }
173         else if (barcode.resource) { /* resource OR patron, not both */
174             if (!this.return_by_resource(barcode.resource))
175                 return;
176         }
177     }
178     if (!this.patron_barcode) {
179         alert(localeStrings.NO_PATRON_BARCODE);
180         return;
181     }
182
183     if (!which) which = this.all;
184
185     var result = fieldmapper.standardRequest(
186         ["open-ils.booking", "open-ils.booking.reservations.get_captured"],
187         [xulG.auth.session.key, this.patron_barcode, which]
188     );
189
190     if (!result) {
191         this.patron_barcode = undefined;
192         alert(localeStrings.RESERVATIONS_NO_RESPONSE);
193     } else if (is_ils_error(result)) {
194         this.patron_barcode = undefined;
195         alert(my_ils_error(localeStrings.RESERVATIONS_ERROR, result));
196     } else {
197         for (var k in result)
198             this["populate_" + k](result[k]);
199     }
200 };
201 Populator.prototype.toggle_anyness = function(any, which) {
202     var widget = this.widgets[which].domNode;
203     var empty_alternate = document.getElementById("no_" + widget.id); 
204     var controls = document.getElementById("controls_" + widget.id); 
205     if (any) {
206         reveal_dom_element(widget);
207         if (empty_alternate) hide_dom_element(empty_alternate);
208         if (controls) reveal_dom_element(controls);
209     } else {
210         hide_dom_element(widget);
211         if (empty_alternate) reveal_dom_element(empty_alternate);
212         if (controls) hide_dom_element(controls);
213     }
214 };
215 Populator.prototype.pickup = function(reservation) {
216     return fieldmapper.standardRequest(
217         ["open-ils.circ", "open-ils.circ.reservation.pickup"],
218         [xulG.auth.session.key, {
219             "patron_barcode": this.patron_barcode,
220             "reservation": reservation
221         }]
222     );
223 };
224 Populator.prototype.return = function(reservation) {
225     return fieldmapper.standardRequest(
226         ["open-ils.circ", "open-ils.circ.reservation.return"],
227         [xulG.auth.session.key, {
228             "patron_barcode": this.patron_barcode,
229             "reservation": reservation.id()
230             /* yeah just id here ------^; lack of parallelism */
231         }]
232     );
233 };
234 Populator.prototype.act_on_selected = function(how, which) {
235     var widget = this.widgets[which];
236     var cache = this.cache[which];
237     var no_response_msg = localeStrings[how.toUpperCase() + "_NO_RESPONSE"];
238     var error_msg = localeStrings[how.toUpperCase() + "_ERROR"];
239
240     var selected_id_list =
241         widget.selection.getSelected().map(function(o) { return o.id[0]; });
242
243     if (!selected_id_list || !selected_id_list.length) {
244         alert(localeStrings.SELECT_SOMETHING);
245         return;
246     }
247
248     var reservations = selected_id_list.map(function(o) { return cache[o]; });
249
250     /* Do we have to process these one at a time?  I think so... */
251     for (var i in reservations) {
252         var result = this[how](reservations[i]);
253         if (!result) {
254             alert(no_response_msg);
255         } else if (is_ils_error(result)) {
256             alert(my_ils_error(error_msg, result));
257         } else {
258             continue;
259         }
260         break;
261     }
262
263     this.populate();
264 };
265 Populator.prototype.reset = function() {
266     for (var k in this.widgets) {
267         this.hide_container(this.widgets[k]);
268     }
269     this.patron_barcode = undefined;
270     if (this.primary_input) {
271         this.primary_input.value = "";
272         this.primary_input.focus();
273     }
274 };