]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/acq/po/search.js
5ef4d24e268067dddaca9ac45bdd95dc36a22ffd
[working/Evergreen.git] / Open-ILS / web / js / ui / default / acq / po / search.js
1 dojo.require('dijit.form.Form');
2 dojo.require('dijit.form.Button');
3 dojo.require('dijit.form.CheckBox');
4 dojo.require('dijit.form.FilteringSelect');
5 dojo.require('dijit.form.NumberTextBox');
6 dojo.require('dojo.data.ItemFileWriteStore');
7 dojo.require('dojo.date.locale');
8 dojo.require('dojo.date.stamp');
9 dojo.require('openils.User');
10 dojo.require('openils.Util');
11 dojo.require('openils.widget.AutoGrid');
12 dojo.require('openils.widget.AutoFieldWidget');
13 dojo.require('openils.PermaCrud');
14
15 var metaPO;
16 var _last_fields;
17 var general_po_search_opts = {"order_by": {"acqpo": "edit_time DESC"}};
18
19 function getPOOwner(rowIndex, item) {
20     if(!item) return '';
21     var data = this.grid.store.getValue(item, 'owner');
22     return new openils.User({id:data}).user.usrname();
23 }
24
25 function doSearch(fields) {
26     _last_fields = dojo.clone(fields); /* Save for re-use */
27     var metapo_view = false;
28
29     /* Remove the metapo_view field from 'fields'... we'll use it later */
30     if (fields.metapo_view && fields.metapo_view[0]) {
31         metapo_view = true;
32         delete fields.metapo_view;
33     }
34
35     if (
36         !(fields.id && fields.id.constructor.name == 'Array') && 
37         isNaN(fields.id)
38     ) {
39         delete fields.id;
40         for(var k in fields) {
41             if(fields[k] == '' || fields[k] == null)
42                 delete fields[k];
43         }
44     } else {
45         // ID search trumps other searches
46         fields = {id:fields.id};
47     }
48
49     // no search fields
50     var some = false;
51     for(var k in fields) some = true;
52     if(!some) fields.id = {'!=' : null};
53
54
55     if (metapo_view) {
56         openils.Util.hide("holds_po_grid");
57         loadMetaPO(fields);
58     } else {
59         if (metaPO) metaPO.myHide();
60         openils.Util.show("holds_po_grid");
61         poGrid.resetStore();
62         poGrid.loadAll(general_po_search_opts, fields);
63     }
64 }
65
66 function loadForm() {
67
68     new openils.widget.AutoFieldWidget({
69         fmClass : 'acqpo', 
70         fmField : 'provider', 
71         parentNode : dojo.byId('po-search-provider-selector'),
72         orgLimitPerms : ['VIEW_PURCHASE_ORDER'],
73         dijitArgs : {name:'provider', required:false}
74     }).build();
75
76     new openils.widget.AutoFieldWidget({
77         fmClass : 'acqpo', 
78         fmField : 'ordering_agency', 
79         parentNode : dojo.byId('po-search-agency-selector'),
80         orgLimitPerms : ['VIEW_PURCHASE_ORDER'],
81         dijitArgs : {name:'ordering_agency', required:false}
82     }).build();
83
84     if (poIds && poIds.length > 0) {
85         dijit.byId("metapo_view").attr("checked", true);
86         doSearch({"id": poIds, "metapo_view": [true] /* [sic] */});
87     } else {
88         doSearch({"ordering_agency": openils.User.user.ws_ou()});
89     }
90 }
91
92 function loadMetaPO(fields) {
93     var pcrud = new openils.PermaCrud();
94     var po_list = pcrud.search("acqpo", fields, general_po_search_opts);
95     if (!po_list || !po_list.length) {
96         alert(localeStrings.NO_PO_RESULTS);
97     } else {
98         if (!metaPO) {
99             metaPO = new AcqLiTable();
100
101             /* We need to know the width (in cells) of the template row for
102              * the LI table, and we don't want to hardcode it here. */
103             metaPO.n_cells = dojo.query("> td", metaPO.rowTemplate).length;
104
105             metaPO._copy_count_cb = function(liId, count) {
106                 var poId = this.liCache[liId].purchase_order();
107
108                 if (this.copy_counts[poId] == undefined)
109                     this.copy_counts[poId] = {};
110                 this.copy_counts[poId][liId] = count;
111
112                 this.renderCopyCounts(poId);
113                 this.renderSummary("copies");
114             };
115             metaPO.myHide = function() {
116                 this.hide();
117                 openils.Util.hide("oils-acq-holds-metapo-summary");
118             };
119             metaPO.renderSummary = function(part) {
120                 var self = this;
121                 /* The idea here will be that if "part" is defined, we'll
122                  * just update that part of the metaPO summary, otherwise,
123                  * the whole thing. */
124                 if (part != undefined) {
125                     var target = dojo.byId("oils-acq-metapo-summary-" + part);
126                     switch (part) {
127                         case "copies":
128                             target.innerHTML = self.copiesTotal();
129                             break;
130                         case "po":
131                             target.innerHTML = self.working_po_list.length;
132                             break;
133                         /* Any numeric fields should be named here. */
134                         case "amount_encumbered":
135                         case "amount_spent":
136                             target.innerHTML = self.numericFieldTotal(part);
137                             break;
138                         default:
139                             /* assume a field on the acqpo's themselves */
140                             target.innerHTML = self.anyFieldTotal(part);
141                             break;
142                     }
143                 } else {
144                     openils.Util.show("oils-acq-holds-metapo-summary");
145                     self.totalable_fields.forEach(
146                         function(f) { self.renderSummary(f); }
147                     );
148                 }
149             };
150             metaPO.numericFieldTotal = function(field) {
151                 var self = this;
152                 var pennies = self.working_po_list.reduce(
153                     /* working_po_list contains unfleshed acqpo's, so we must
154                      * find the same PO in the poCache */
155                     function(p, c) {
156                         c = self.poCache[c.id()][field]();
157                         return p + Number(c) * 100;
158                     }, 0
159                 );
160                 return pennies / 100;
161             };
162             metaPO.anyFieldTotal = function(field) {
163                 var self = this;
164                 return self.working_po_list.reduce(
165                     /* working_po_list contains unfleshed acqpo's, so we must
166                      * find the same PO in the poCache */
167                     function(p, c) {
168                         c = self.poCache[c.id()][field]();
169                         return p + Number(c);
170                     }, 0
171                 );
172             };
173             metaPO.renderCopyCounts = function(poId) {
174                 try {
175                     dojo.query("td#oils-acq-po-heading-" + poId +
176                         ' span span[attr="copies"]')[0].innerHTML =
177                             this.copiesByPOId(poId);
178                 } catch (E) {
179                     ;
180                 }
181             };
182             metaPO.sectionHeadingById = function(id) {
183                 var headings = dojo.query("#po-heading-" + id, this.tbody);
184                 if (headings.length != 1) {
185                     alert(localeStrings.PO_HEADING_ERROR);
186                     return undefined;
187                 } else {
188                     return headings[0];
189                 }
190             };
191             metaPO.sectionHeadingByPOId = function(poId) {
192                 return this.sectionHeadingById(this.sections_by_poid[poId]);
193             };
194             metaPO.addSection = function(po) {
195                 var s = this.sections_by_poid[po.id()] = this.sections++;
196
197                 this.tbody.appendChild(
198                     dojo.create("tr", {
199                         "class": "acq-lit-po-heading", "id": "po-heading-" + s
200                     })
201                 );
202
203                 return s;
204             };
205             metaPO.addLineitemToSection = function(li, section) {
206                 dojo.place(
207                     this.addLineitem(li, true /* skip_final_placement */),
208                     this.sectionHeadingById(section),
209                     "after"
210                 );
211             };
212             metaPO.generateActivator = function(id) {
213                 return function() {
214                     progressDialog.show(true);
215                     try {
216                         fieldmapper.standardRequest(
217                             ["open-ils.acq",
218                                 "open-ils.acq.purchase_order.activate"], {
219                                 "async": true,
220                                 "params": [openils.User.authtoken, id],
221                                 "oncomplete": function() {
222                                     progressDialog.hide();
223                                     doSearch(_last_fields);
224                                 }
225                             }
226                         );
227                     } catch (E) {
228                         progressDialog.hide();
229                         alert(E); /* XXX */
230                     }
231                 };
232             };
233             metaPO.renderHeading = function(poId) {
234                 var self = this;
235                 var td = dojo.create("td", {"colspan": self.n_cells});
236                 td.id = "oils-acq-po-heading-" + poId;
237
238                 /* Build our HTML structure from the template... */
239                 dojo.query("> span", "oils-acq-po-heading-template").forEach(
240                     function(s) { td.appendChild(s.cloneNode(true)); }
241                 );
242
243                 /* Some fields straight from the PO object... */
244                 self.po_fields_for_display.forEach(
245                     function(f) {
246                         dojo.query('[attr="' + f + '"]', td)[0].innerHTML =
247                             self.poCache[poId][f]();
248                     }
249                 );
250
251                 /* The name field needs special treatment: it's a link */
252                 dojo.attr(
253                     dojo.query('a[attr="name"]', td)[0],
254                     "href",
255                     oilsBasePath + '/acq/po/view/' + poId
256                 );
257
258                 /* Show an "activate" link, or not, based on "state"... */
259                 var a = dojo.query('a[attr="activator"]', td)[0];
260                 if (self.poCache[poId].state() == "pending") {
261                     a.onclick = self.generateActivator(poId);
262                     openils.Util.show(a, "inline");
263                 } else {
264                     openils.Util.hide(a);
265                 }
266
267                 /* Put the new heading cell in place... */
268                 dojo.place(td, self.sectionHeadingByPOId(poId), "only");
269
270                 /* And finally, render copy info (must happen _after_ heading
271                  * is attached to the DOM tree */
272                 this.renderCopyCounts(poId);
273             };
274             metaPO.copiesByPOId = function(poId) {
275                 if (!this.copy_counts[poId]) return undefined;
276                 var total = 0;
277                 for (var liId in this.copy_counts[poId]) {
278                     total += this.copy_counts[poId][liId];
279                 }
280                 return total;
281             };
282             metaPO.copiesTotal = function() {
283                 var total = 0;
284                 for (var poId in this.copy_counts)
285                     total += this.copiesByPOId(poId);
286                 return total;
287             };
288             metaPO.myReset = function() {
289                 this.isMeta = true;
290                 this.sections = 0;
291                 this.sections_by_poid = {};
292                 this.copy_counts = {};
293                 this.po_fields_for_display = [
294                     "name", "lineitem_count", "amount_encumbered",
295                     "amount_spent", "state"
296                 ];
297                 this.totalable_fields = [
298                     "po", "lineitem_count", "copies",
299                     "amount_encumbered", "amount_spent"
300                 ];
301                 openils.Util.hide("oils-acq-holds-metapo-summary");
302             };
303             metaPO.populate = function(list) {
304                 var self = this;
305                 var done = 0;
306
307                 self.working_po_list = [];
308
309                 progressDialog.show(true);
310                 list.forEach(function(po) {
311                     var sec = self.addSection(po);
312                     fieldmapper.standardRequest(
313                         ["open-ils.acq", "open-ils.acq.lineitem.search"], {
314                             "async": true,
315                             "params": [
316                                 openils.User.authtoken,
317                                 {"purchase_order": po.id()},
318                                 {"flesh_attrs": true, "flesh_notes": true}
319                             ],
320                             "onresponse": function(r) {
321                                 var li = openils.Util.readResponse(r);
322                                 if (li) /* sometimes empty string: disregard */
323                                     self.addLineitemToSection(li, sec);
324                             },
325                             "oncomplete": function(r) {
326                                 self.working_po_list.push(po);
327                                 self.renderHeading(po.id());
328                                 self.renderSummary();
329                                 /* This mechanism avoids calling .show() too
330                                  * often or before results are ready, and
331                                  * thus smooths out DOM rendering glitches. */
332                                 if (++done >= list.length) {
333                                     done = -1;
334                                     self.show("list");
335                                     progressDialog.hide();
336                                 }
337                             }
338                         }
339                     );
340                 });
341                 /* This mechanism sees to it that we call .show() at least once
342                  * even if the search result population seems to be timing
343                  * out or failing. */
344                 setTimeout(
345                     function() {
346                         if (done != -1) {
347                             self.show("list");
348                             progressDialog.hide();
349                         }
350                     }, 10000    /* 10 seconds: make this configurable? */
351                 );
352             };
353         }
354
355         metaPO.reset();
356         metaPO.myReset();
357         metaPO.populate(po_list);
358     }
359 }
360
361 openils.Util.addOnLoad(loadForm);