]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/ui/default/acq/common/li_table.js
plugged in mark-po-received action
[working/Evergreen.git] / Open-ILS / web / js / ui / default / acq / common / li_table.js
1 dojo.require('dijit.form.Button');
2 dojo.require('dijit.form.TextBox');
3 dojo.require('dijit.form.FilteringSelect');
4 dojo.require('dijit.ProgressBar');
5 dojo.require('openils.User');
6 dojo.require('openils.Util');
7 dojo.require('openils.acq.Lineitem');
8 dojo.require('openils.acq.PO');
9 dojo.require('openils.acq.Picklist');
10 dojo.require('openils.widget.AutoFieldWidget');
11 dojo.require('dojo.data.ItemFileReadStore');
12 dojo.require('openils.widget.ProgressDialog');
13
14 function AcqLiTable() {
15
16     var self = this;
17     this.liCache = {};
18     this.toggleState = false;
19     this.tbody = dojo.byId('acq-lit-tbody');
20     this.selectors = [];
21     this.authtoken = openils.User.authtoken;
22     this.rowTemplate = this.tbody.removeChild(dojo.byId('acq-lit-row'));
23     this.copyTbody = dojo.byId('acq-lit-li-details-tbody');
24     this.copyRow = this.copyTbody.removeChild(dojo.byId('acq-lit-li-details-row'));
25     this.copyBatchRow = dojo.byId('acq-lit-li-details-batch-row');
26     this.copyBatchWidgets = {};
27
28     dojo.connect(acqLitLiActionsSelector, 'onChange', 
29         function() { 
30             self.applySelectedLiAction(this.attr('value')) 
31             acqLitLiActionsSelector.attr('value', '_');
32         });
33
34     acqLitCreatePoSubmit.onClick = function() {
35         acqLitPoCreateDialog.hide();
36         self._createPO(acqLitPoCreateDialog.getValues());
37     }
38
39     acqLitSavePlButton.onClick = function() {
40         acqLitSavePlDialog.hide();
41         self._savePl(acqLitSavePlDialog.getValues());
42     }
43
44     dojo.byId('acq-lit-select-toggle').onclick = function(){self.toggleSelect()};
45     dojo.byId('acq-lit-info-back-button').onclick = function(){self.show('list')};
46     dojo.byId('acq-lit-copies-back-button').onclick = function(){self.show('list')};
47
48     this.reset = function() {
49         while(self.tbody.childNodes[0])
50             self.tbody.removeChild(self.tbody.childNodes[0]);
51         self.selectors = [];
52     };
53     
54     this.setNext = function(handler) {
55         var link = dojo.byId('acq-lit-next');
56         if(handler) {
57             dojo.style(link, 'visibility', 'visible');
58             link.onclick = handler;
59         } else {
60             dojo.style(link, 'visibility', 'hidden');
61         }
62     };
63
64     this.setPrev = function(handler) {
65         var link = dojo.byId('acq-lit-prev');
66         if(handler) {
67             dojo.style(link, 'visibility', 'visible'); 
68             link.onclick = handler; 
69         } else {
70             dojo.style(link, 'visibility', 'hidden');
71         }
72     };
73
74     this.show = function(div) {
75         openils.Util.hide('acq-lit-table-div');
76         openils.Util.hide('acq-lit-info-div');
77         openils.Util.hide('acq-lit-li-details');
78         switch(div){
79             case 'list':
80                 openils.Util.show('acq-lit-table-div');
81                 break;
82             case 'info':
83                 openils.Util.show('acq-lit-info-div');
84                 break;
85             case 'copies':
86                 openils.Util.show('acq-lit-li-details');
87                 break;
88             default:
89                 if(div) 
90                     openils.Util.show(div);
91         }
92     }
93
94     this.hide = function() {
95         this.show(null);
96     }
97
98     this.toggleSelect = function() {
99         if(self.toggleState) 
100             dojo.forEach(self.selectors, function(i){i.checked = false});
101         else 
102             dojo.forEach(self.selectors, function(i){i.checked = true});
103         self.toggleState = !self.toggleState;
104     };
105
106
107     /** @param all If true, assume all are selected */
108     this.getSelected = function(all) {
109         var selected = [];
110         dojo.forEach(self.selectors, 
111             function(i) { 
112                 if(i.checked || all)
113                     selected.push(self.liCache[i.parentNode.parentNode.getAttribute('li')]);
114             }
115         );
116         return selected;
117     };
118
119     this.setRowAttr = function(td, liWrapper, field, type) {
120         var val = liWrapper.findAttr(field, type || 'lineitem_marc_attr_definition') || '';
121         td.appendChild(document.createTextNode(val));
122     };
123
124     this.addLineitem = function(li) {
125         this.liCache[li.id()] = li;
126         var liWrapper = new openils.acq.Lineitem({lineitem:li});
127         var row = self.rowTemplate.cloneNode(true);
128         row.setAttribute('li', li.id());
129         var tds = dojo.query('[attr]', row);
130         dojo.forEach(tds, function(td) {self.setRowAttr(td, liWrapper, td.getAttribute('attr'), td.getAttribute('attr_type'));});
131         dojo.query('[name=source_label]', row)[0].appendChild(document.createTextNode(li.source_label()));
132
133         var isbn = liWrapper.findAttr('isbn', 'lineitem_marc_attr_definition');
134         if(isbn) {
135             // XXX media prefix for added content
136             dojo.query('[name=jacket]', row)[0].setAttribute('src', '/opac/extras/ac/jacket/small/' + isbn);
137         }
138
139         dojo.query('[attr=title]', row)[0].onclick = function() {self.drawInfo(li.id())};
140         dojo.query('[name=copieslink]', row)[0].onclick = function() {self.drawCopies(li.id())};
141         dojo.query('[name=count]', row)[0].appendChild(document.createTextNode(li.item_count()));
142         dojo.query('[name=estimated_price]', row)[0].value =  
143             liWrapper.findAttr('estimated_price', 'lineitem_local_attr_definition');
144
145         self.tbody.appendChild(row);
146         self.selectors.push(dojo.query('[name=selectbox]', row)[0]);
147     };
148
149     this.removeLineitem = function(liId) {
150         this.tbody.removeChild(dojo.query('[li='+liId+']', this.tbody)[0]);
151         delete this.liCache[liId];
152     }
153
154     this.drawInfo = function(liId) {
155         this.show('info');
156         openils.acq.Lineitem.fetchAttrDefs(
157             function() { 
158                 self._fetchLineitem(liId, function(li){self._drawInfo(li);}); 
159             } 
160         );
161     };
162
163     this._fetchLineitem = function(liId, handler) {
164
165         var li = this.liCache[liId];
166         if(li && li.marc() && li.lineitem_details())
167             return handler(li);
168         
169         fieldmapper.standardRequest(
170             ['open-ils.acq', 'open-ils.acq.lineitem.retrieve'],
171             {   async: true,
172
173                 params: [self.authtoken, liId, {
174                     flesh_attrs: true,
175                     flesh_li_details: true,
176                     flesh_fund_debit: true }],
177
178                 oncomplete: function(r) {
179                     var li = openils.Util.readResponse(r);
180                     handler(li)
181                 }
182             }
183         );
184     };
185
186     this._drawInfo = function(li) {
187
188         acqLitEditMarc.onClick = function() { self.editMarc(li); }
189         this.drawMarcHTML(li);
190         this.infoTbody = dojo.byId('acq-lit-info-tbody');
191
192         if(!this.infoRow)
193             this.infoRow = this.infoTbody.removeChild(dojo.byId('acq-lit-info-row'));
194         while(this.infoTbody.childNodes[0])
195             this.infoTbody.removeChild(this.infoTbody.childNodes[0]);
196
197         for(var i = 0; i < li.attributes().length; i++) {
198             var attr = li.attributes()[i];
199             var row = this.infoRow.cloneNode(true);
200
201             var type = attr.attr_type().replace(/lineitem_(.*)_attr_definition/, '$1');
202             var name = openils.acq.Lineitem.attrDefs[type].filter(
203                 function(a) {
204                     return (a.code() == attr.attr_name());
205                 }
206             ).pop().description();
207
208             dojo.query('[name=label]', row)[0].appendChild(document.createTextNode(name));
209             dojo.query('[name=value]', row)[0].appendChild(document.createTextNode(attr.attr_value()));
210             this.infoTbody.appendChild(row);
211         }
212     };
213
214     this.drawMarcHTML = function(li) {
215         fieldmapper.standardRequest(
216             ['open-ils.search', 'open-ils.search.biblio.record.html'],
217             {   async: true,
218                 params: [null, true, li.marc()],
219                 oncomplete: function(r) {
220                     dojo.byId('acq-lit-marc-div').innerHTML = 
221                         openils.Util.readResponse(r);
222                 }
223             }
224         );
225     }
226
227     this.drawCopies = function(liId) {
228         this.show('copies');
229         var self = this;
230         this.copyCache = {};
231         this.copyWidgetCache = {};
232
233         acqLitSaveCopies.onClick = function() { self.saveCopyChanges(liId) };
234         acqLitBatchUpdateCopies.onClick = function() { self.batchCopyUpdate() };
235
236         while(this.copyTbody.childNodes[0])
237             this.copyTbody.removeChild(this.copyTbody.childNodes[0]);
238
239         this._drawBatchCopyWidgets();
240
241         this._fetchDistribFormulas(
242             function() {
243                 openils.acq.Lineitem.fetchAttrDefs(
244                     function() { 
245                         self._fetchLineitem(liId, function(li){self._drawCopies(li);}); 
246                     } 
247                 );
248             }
249         );
250     };
251
252     this._fetchDistribFormulas = function(onload) {
253         if(this.distribForms) {
254             onload();
255         } else {
256             var self = this;
257             fieldmapper.standardRequest(
258                 ['open-ils.acq', 'open-ils.acq.distribution_formula.ranged.retrieve.atomic'],
259                 {   async: true,
260                     params: [openils.User.authtoken],
261                     oncomplete: function(r) {
262                         self.distribForms = openils.Util.readResponse(r);
263                         self.distribFormulaStore = 
264                             new dojo.data.ItemFileReadStore(
265                                 {data:acqdf.toStoreData(self.distribForms)});
266                         onload();
267                     }
268                 }
269             );
270         }
271     }
272
273     this._drawBatchCopyWidgets = function() {
274         var row = this.copyBatchRow;
275         dojo.forEach(['fund', 'owning_lib', 'location'],
276             function(field) {
277                 if(self.copyBatchRowDrawn) {
278                     self.copyBatchWidgets[field].attr('value', null);
279                 } else {
280                     var widget = new openils.widget.AutoFieldWidget({
281                         fmField : field,
282                         fmClass : 'acqlid',
283                         parentNode : dojo.query('[name='+field+']', row)[0],
284                         orgLimitPerms : ['CREATE_PICKLIST'],
285                         dijitArgs : {required:false}
286                     });
287                     widget.build();
288                     self.copyBatchWidgets[field] = widget.widget;
289                 }
290             }
291         );
292         this.copyBatchRowDrawn = true;
293     };
294
295     this.batchCopyUpdate = function() {
296         var self = this;
297         var fields = ['fund', 'owning_lib', 'location'];
298         for(var k in this.copyWidgetCache) {
299             var cache = this.copyWidgetCache[k];
300             dojo.forEach(fields, function(f) {
301                 var newval = self.copyBatchWidgets[f].attr('value');
302                 if(newval) cache[f].attr('value', newval);
303             });
304         }
305     };
306
307     this._drawCopies = function(li) {
308         acqLitAddCopyCount.onClick = function() { 
309             var count = acqLitCopyCountInput.attr('value');
310             for(var i = 0; i < count; i++)
311                 self.addCopy(li); 
312         }
313         if(li.lineitem_details().length > 0) {
314             dojo.forEach(li.lineitem_details(),
315                 function(copy) {
316                     self.addCopy(li, copy);
317                 }
318             );
319         } else {
320             self.addCopy(li);
321         }
322     };
323
324     this.virtCopyId = -1;
325     this.addCopy = function(li, copy) {
326         var row = this.copyRow.cloneNode(true);
327         this.copyTbody.appendChild(row);
328         var self = this;
329
330         if(!copy) {
331             copy = new fieldmapper.acqlid();
332             copy.isnew(true);
333             copy.id(this.virtCopyId--);
334             copy.lineitem(li.id());
335         }
336
337         this.copyCache[copy.id()] = copy;
338         row.setAttribute('copy_id', copy.id());
339         self.copyWidgetCache[copy.id()] = {};
340
341         dojo.forEach(['fund', 'owning_lib', 'location', 'barcode', 'cn_label'],
342             function(field) {
343                 var widget = new openils.widget.AutoFieldWidget({
344                     fmObject : copy,
345                     fmField : field,
346                     fmClass : 'acqlid',
347                     parentNode : dojo.query('[name='+field+']', row)[0],
348                     orgLimitPerms : ['CREATE_PICKLIST'],
349                     readOnly : self.isPO
350                 });
351                 widget.build(
352                     // make sure we capture the value from any async widgets
353                     function(w, ww) { copy[field](ww.getFormattedValue()) }
354                 );
355                 dojo.connect(widget.widget, 'onChange', 
356                     function(val) { 
357                         if(copy.isnew() || val != copy[field]()) {
358                             // prevent setting ischanged() automatically on widget load for existing copies
359                             copy[field](widget.getFormattedValue()) 
360                             copy.ischanged(true);
361                         }
362                     }
363                 );
364                 self.copyWidgetCache[copy.id()][field] = widget.widget;
365             }
366         );
367
368         if(this.isPO) {
369             openils.Util.hide(dojo.query('[name=delete]', row)[0].parentNode);
370         } else {
371             dojo.query('[name=delete]', row)[0].onclick = 
372                 function() { self.deleteCopy(row) };
373         }
374     };
375
376     this.deleteCopy = function(row) {
377         var copy = this.copyCache[row.getAttribute('copy_id')];
378         copy.isdeleted(true);
379         if(copy.isnew())
380             delete this.copyCache[copy.id()];
381         this.copyTbody.removeChild(row);
382     }
383
384     this.saveCopyChanges = function(liId) {
385         var self = this;
386         var copies = [];
387
388         openils.Util.show('acq-lit-update-copies-progress');
389
390         for(var id in this.copyCache) {
391             var c = this.copyCache[id];
392             if(c.isnew() || c.ischanged() || c.isdeleted()) {
393                 if(c.id() < 0) c.id(null);
394                 copies.push(c);
395             }
396         }
397
398         if(copies.length == 0)
399             return;
400
401         fieldmapper.standardRequest(
402             ['open-ils.acq', 'open-ils.acq.lineitem_detail.cud.batch'],
403             {   async: true,
404                 params: [openils.User.authtoken, copies],
405                 onresponse: function(r) {
406                     var res = openils.Util.readResponse(r);
407                     litUpdateCopiesProgress.update(res);
408                 },
409                 oncomplete: function() {
410                     openils.Util.hide('acq-lit-update-copies-progress');
411                     self.drawCopies(liId); 
412                 }
413             }
414         );
415     }
416
417     this.applySelectedLiAction = function(action) {
418         var self = this;
419         switch(action) {
420
421             case 'delete_selected':
422                 this._deleteLiList(self.getSelected());
423                 break;
424
425             case 'create_order':
426
427                 if(!this.createPoProviderSelector) {
428                     var widget = new openils.widget.AutoFieldWidget({
429                         fmField : 'provider',
430                         fmClass : 'acqpo',
431                         parentNode : dojo.byId('acq-lit-po-provider'),
432                         orgLimitPerms : ['CREATE_PURCHASE_ORDER'],
433                     });
434                     widget.build(
435                         function(w) { self.createPoProviderSelector = w; }
436                     );
437                 }
438          
439                 acqLitPoCreateDialog.show();
440                 break;
441
442             case 'save_picklist':
443                 this._loadPLSelect();
444                 acqLitSavePlDialog.show();
445                 break;
446
447             case 'print_po':
448                 this.printPO();
449                 break;
450
451             case 'receive_po':
452                 this.receivePO();
453                 break;
454         }
455     }
456
457     this.printPO = function() {
458         if(!this.isPO) return;
459         progressDialogInd.show();
460         fieldmapper.standardRequest(
461             ['open-ils.acq', 'open-ils.acq.purchase_order.format'],
462             {   async: true,
463                 params: [this.authtoken, this.isPO, 'html'],
464                 oncomplete: function(r) {
465                     progressDialogInd.hide();
466                     var evt = openils.Util.readResponse(r);
467                     if(evt && evt.template_output()) {
468                         win = window.open('','', 'resizable,width=700,height=500,scrollbars=1');
469                         win.document.body.innerHTML = evt.template_output().data();
470                     }
471                 }
472             }
473         );
474     }
475
476
477     this.receivePO = function() {
478         if(!this.isPO) return;
479         progressDialog.show();
480         var maximum = 1;
481         dojo.forEach(this.liCache, function(){maximum += 1; });
482         dojo.forEach(this.copyCache, function(){maximum += 1; });
483         fieldmapper.standardRequest(
484             ['open-ils.acq', 'open-ils.acq.purchase_order.receive'],
485             {   async: true,
486                 params: [this.authtoken, this.isPO],
487                 onresponse : function(r) {
488                     var stat = openils.Util.readResponse(r);
489                     
490                     // we don't know the total amount of items to be processed
491                     // since we only have 1 page of data
492                     if(stat.progress > maximum) maximum *= 2;
493
494                     progressDialog.update({maximum:maximum, progress:stat.progress});
495                     if(stat.complete) {
496                         // XXX
497                         location.href = location.href;
498                     }
499                 },
500             }
501         );
502     }
503
504
505     this._createPO = function(fields) {
506         this.show('acq-lit-create-po-progress');
507         var po = new fieldmapper.acqpo();
508         po.provider(this.createPoProviderSelector.attr('value'));
509
510         var selected = this.getSelected( (fields.create_from == 'all') );
511         if(selected.length == 0) return;
512
513         var max = selected.length * 3;
514
515         fieldmapper.standardRequest(
516             ['open-ils.acq', 'open-ils.acq.purchase_order.create'],
517             {   async: true,
518                 params: [
519                     openils.User.authtoken, 
520                     po, 
521                     {
522                         lineitems : selected.map(function(li) { return li.id() }),
523                         create_assets : true,
524                         create_debits : true,
525                         circ_modifier : 'book', /* XXX */
526                     }
527                 ],
528                 onresponse : function(r) {
529                     var resp = openils.Util.readResponse(r);
530                     openils.Util.appendClear('acq-lit-po-encumbered', document.createTextNode(resp.total_debits));
531                     openils.Util.appendClear('acq-lit-po-copies', document.createTextNode(resp.total_copies));
532                     litPoTotalProgress.update({maximum:max, progress:resp.progress});
533                     if(resp.complete) 
534                         location.href = oilsBasePath + '/eg/acq/po/view/' + resp.purchase_order;
535                 }
536             }
537         );
538     }
539
540     this._deleteLiList = function(list, idx) {
541         if(idx == null) idx = 0;
542         if(idx >= list.length) return;
543         var liId = list[idx].id();
544         fieldmapper.standardRequest(
545             ['open-ils.acq', 'open-ils.acq.lineitem.delete'],
546             {   async: true,
547                 params: [openils.User.authtoken, liId],
548                 oncomplete: function(r) {
549                     self.removeLineitem(liId);
550                     self._deleteLiList(list, ++idx);
551                 }
552             }
553         );
554     }
555
556     this.editMarc = function(li) {
557
558         /*  To run in Firefox directly, must set signed.applets.codebase_principal_support
559             to true in about:config */
560
561         netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
562         win = window.open('/xul/server/cat/marcedit.xul'); // XXX version?
563
564         var self = this;
565         win.xulG = {
566             record : {marc : li.marc()},
567             save : {
568                 label: 'Save Record', // XXX I18N
569                 func: function(xmlString) {
570                     li.marc(xmlString);
571                     fieldmapper.standardRequest(
572                         ['open-ils.acq', 'open-ils.acq.lineitem.update'],
573                         {   async: true,
574                             params: [openils.User.authtoken, li],
575                             oncomplete: function(r) {
576                                 openils.Util.readResponse(r);
577                                 win.close();
578                                 self.drawInfo(li.id())
579                             }
580                         }
581                     );
582                 },
583             }
584         };
585     }
586
587
588     this._savePl = function(values) {
589         var self = this;
590         var selected = this.getSelected( (values.which == 'all') );
591         openils.Util.show('acq-lit-generic-progress');
592
593         if(values.new_name) {
594             openils.acq.Picklist.create(
595                 {name: values.new_name}, 
596                 function(id) {
597                     self._updateLiList(id, selected, 0, 
598                         function(){
599                             location.href = oilsBasePath + '/eg/acq/picklist/view/' + id;
600                         });
601                 }
602             );
603         } else if(values.existing_pl) {
604             // update lineitems to use an existing picklist
605             self._updateLiList(values.existing_pl, selected, 0, 
606                 function(){
607                     location.href = oilsBasePath + '/eg/acq/picklist/view/' + values.existing_pl;
608                 });
609         }
610     }
611
612     this._updateLiList = function(pl, list, idx, oncomplete) {
613         if(idx >= list.length) return oncomplete();
614         var li = list[idx];
615         li.picklist(pl);
616         litGenericProgress.update({maximum: list.length, progress: idx});
617         new openils.acq.Lineitem({lineitem:li}).update(
618             function(r) {
619                 self._updateLiList(pl, list, ++idx, oncomplete);
620             }
621         );
622     }
623
624     this._loadPLSelect = function() {
625         if(this._plSelectLoaded) return;
626         var plList = [];
627         function handleResponse(r) {
628             plList.push(r.recv().content());
629         }
630         var method = 'open-ils.acq.picklist.user.retrieve';
631         fieldmapper.standardRequest(
632             ['open-ils.acq', method],
633             {   async: true,
634                 params: [this.authtoken],
635                 onresponse: handleResponse,
636                 oncomplete: function() {
637                     self._plSelectLoaded = true;
638                     acqLitAddExistingSelect.store = 
639                         new dojo.data.ItemFileReadStore({data:acqpl.toStoreData(plList)});
640                     acqLitAddExistingSelect.setValue();
641                 }
642             }
643         );
644     }
645 }
646
647
648