]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/web/js/ui/default/acq/common/li_table.js
tighter control over displaying mark-recived and update-barcodes links in lineitem...
[Evergreen.git] / Open-ILS / web / js / ui / default / acq / common / li_table.js
1 dojo.require('dojo.date.locale');
2 dojo.require('dojo.date.stamp');
3 dojo.require('dijit.form.Button');
4 dojo.require('dijit.form.TextBox');
5 dojo.require('dijit.form.FilteringSelect');
6 dojo.require('dijit.form.Textarea');
7 dojo.require('dijit.ProgressBar');
8 dojo.require('openils.User');
9 dojo.require('openils.Util');
10 dojo.require('openils.acq.Lineitem');
11 dojo.require('openils.acq.PO');
12 dojo.require('openils.acq.Picklist');
13 dojo.require('openils.widget.AutoFieldWidget');
14 dojo.require('dojo.data.ItemFileReadStore');
15 dojo.require('openils.widget.ProgressDialog');
16 dojo.require('openils.PermaCrud');
17 dojo.require('openils.XUL');
18
19 dojo.requireLocalization('openils.acq', 'acq');
20 var localeStrings = dojo.i18n.getLocalization('openils.acq', 'acq');
21 const XUL_OPAC_WRAPPER = 'chrome://open_ils_staff_client/content/cat/opac.xul';
22
23 function nodeByName(name, context) {
24     return dojo.query('[name='+name+']', context)[0];
25 }
26
27
28 var liDetailBatchFields = ['fund', 'owning_lib', 'location', 'collection_code', 'circ_modifier', 'cn_label'];
29 var liDetailFields = liDetailBatchFields.concat(['barcode', 'note']);
30
31 function AcqLiTable() {
32
33     var self = this;
34     this.liCache = {};
35     this.toggleState = false;
36     this.tbody = dojo.byId('acq-lit-tbody');
37     this.selectors = [];
38     this.authtoken = openils.User.authtoken;
39     this.rowTemplate = this.tbody.removeChild(dojo.byId('acq-lit-row'));
40     this.copyTbody = dojo.byId('acq-lit-li-details-tbody');
41     this.copyRow = this.copyTbody.removeChild(dojo.byId('acq-lit-li-details-row'));
42     this.copyBatchRow = dojo.byId('acq-lit-li-details-batch-row');
43     this.copyBatchWidgets = {};
44     this.liNotesTbody = dojo.byId('acq-lit-notes-tbody');
45     this.liNotesRow = this.liNotesTbody.removeChild(dojo.byId('acq-lit-notes-row'));
46     this.realCopiesTbody = dojo.byId('acq-lit-real-copies-tbody');
47     this.realCopiesRow = this.realCopiesTbody.removeChild(dojo.byId('acq-lit-real-copies-row'));
48
49     dojo.connect(acqLitLiActionsSelector, 'onChange', 
50         function() { 
51             self.applySelectedLiAction(this.attr('value')) 
52             acqLitLiActionsSelector.attr('value', '_');
53         });
54
55     acqLitCreatePoSubmit.onClick = function() {
56         acqLitPoCreateDialog.hide();
57         self._createPO(acqLitPoCreateDialog.getValues());
58     }
59
60     acqLitSavePlButton.onClick = function() {
61         acqLitSavePlDialog.hide();
62         self._savePl(acqLitSavePlDialog.getValues());
63     }
64
65
66     //dojo.byId('acq-lit-notes-new-button').onclick = function(){acqLitCreateLiNoteDialog.show();}
67
68     dojo.byId('acq-lit-select-toggle').onclick = function(){self.toggleSelect()};
69     dojo.byId('acq-lit-info-back-button').onclick = function(){self.show('list')};
70     dojo.byId('acq-lit-copies-back-button').onclick = function(){self.show('list')};
71     dojo.byId('acq-lit-notes-back-button').onclick = function(){self.show('list')};
72     dojo.byId('acq-lit-real-copies-back-button').onclick = function(){self.show('list')};
73
74     this.reset = function() {
75         while(self.tbody.childNodes[0])
76             self.tbody.removeChild(self.tbody.childNodes[0]);
77         self.selectors = [];
78     };
79     
80     this.setNext = function(handler) {
81         var link = dojo.byId('acq-lit-next');
82         if(handler) {
83             dojo.style(link, 'visibility', 'visible');
84             link.onclick = handler;
85         } else {
86             dojo.style(link, 'visibility', 'hidden');
87         }
88     };
89
90     this.setPrev = function(handler) {
91         var link = dojo.byId('acq-lit-prev');
92         if(handler) {
93             dojo.style(link, 'visibility', 'visible'); 
94             link.onclick = handler; 
95         } else {
96             dojo.style(link, 'visibility', 'hidden');
97         }
98     };
99
100     this.show = function(div) {
101         openils.Util.hide('acq-lit-table-div');
102         openils.Util.hide('acq-lit-info-div');
103         openils.Util.hide('acq-lit-li-details');
104         openils.Util.hide('acq-lit-notes-div');
105         openils.Util.hide('acq-lit-real-copies-div');
106         switch(div) {
107             case 'list':
108                 openils.Util.show('acq-lit-table-div');
109                 break;
110             case 'info':
111                 openils.Util.show('acq-lit-info-div');
112                 break;
113             case 'copies':
114                 openils.Util.show('acq-lit-li-details');
115                 break;
116             case 'real-copies':
117                 openils.Util.show('acq-lit-real-copies-div');
118                 break;
119             case 'notes':
120                 openils.Util.show('acq-lit-notes-div');
121                 break;
122             default:
123                 if(div) 
124                     openils.Util.show(div);
125         }
126     }
127
128     this.hide = function() {
129         this.show(null);
130     }
131
132     this.toggleSelect = function() {
133         if(self.toggleState) 
134             dojo.forEach(self.selectors, function(i){i.checked = false});
135         else 
136             dojo.forEach(self.selectors, function(i){i.checked = true});
137         self.toggleState = !self.toggleState;
138     };
139
140
141     /** @param all If true, assume all are selected */
142     this.getSelected = function(all) {
143         var selected = [];
144         dojo.forEach(self.selectors, 
145             function(i) { 
146                 if(i.checked || all)
147                     selected.push(self.liCache[i.parentNode.parentNode.getAttribute('li')]);
148             }
149         );
150         return selected;
151     };
152
153     this.setRowAttr = function(td, liWrapper, field, type) {
154         var val = liWrapper.findAttr(field, type || 'lineitem_marc_attr_definition') || '';
155         td.appendChild(document.createTextNode(val));
156     };
157
158     /**
159      * Inserts a single lineitem into the growing table of lineitems
160      * @param {Object} li The lineitem object to insert
161      */
162     this.addLineitem = function(li) {
163         this.liCache[li.id()] = li;
164
165         // sort the lineitem notes on edit_time
166         if(!li.lineitem_notes()) li.lineitem_notes([]);
167
168         var liWrapper = new openils.acq.Lineitem({lineitem:li});
169         var row = self.rowTemplate.cloneNode(true);
170         row.setAttribute('li', li.id());
171         var tds = dojo.query('[attr]', row);
172         dojo.forEach(tds, function(td) {self.setRowAttr(td, liWrapper, td.getAttribute('attr'), td.getAttribute('attr_type'));});
173         dojo.query('[name=source_label]', row)[0].appendChild(document.createTextNode(li.source_label()));
174
175         var isbn = liWrapper.findAttr('isbn', 'lineitem_marc_attr_definition');
176         if(isbn) {
177             // XXX media prefix for added content
178             dojo.query('[name=jacket]', row)[0].setAttribute('src', '/opac/extras/ac/jacket/small/' + isbn);
179         }
180
181         dojo.query('[attr=title]', row)[0].onclick = function() {self.drawInfo(li.id())};
182         dojo.query('[name=copieslink]', row)[0].onclick = function() {self.drawCopies(li.id())};
183         dojo.query('[name=notes_count]', row)[0].innerHTML = li.lineitem_notes().length;
184         dojo.query('[name=noteslink]', row)[0].onclick = function() {self.drawLiNotes(li)};
185
186         var countNode = nodeByName('count', row);
187         countNode.innerHTML = li.item_count() || 0;
188         countNode.id = 'acq-lit-copy-count-label-' + li.id();
189
190         // lineitem state
191         nodeByName('li_state', row).innerHTML = li.state(); // TODO i18n state labels
192
193         // lineitem price
194         var priceInput = dojo.query('[name=price]', row)[0];
195         var priceData = liWrapper.getPrice();
196         priceInput.value = (priceData) ? priceData.price : '';
197         priceInput.onchange = function() { self.updateLiPrice(priceInput, li) };
198
199         var recv_link = dojo.query('[name=receive_link]', row)[0];
200
201         if(li.state == 'on-order') {
202             recv_link.onclick = function() {
203                 self.receiveLi(li);
204                 openils.Util.hide(recv_link)
205             }
206         } else {
207             openils.Util.hide(recv_link);
208         }
209
210         // TODO we should allow editing before receipt, in which case the
211         // test should be "if 1 or more real (acp) copies exist
212         if(li.state() == 'received') {
213             var real_copies_link = dojo.query('[name=real_copies_link]', row)[0];
214             openils.Util.show(real_copies_link);
215             real_copies_link.onclick = function() {
216                 self.showRealCopies(li);
217             }
218         }
219
220         self.tbody.appendChild(row);
221         self.selectors.push(dojo.query('[name=selectbox]', row)[0]);
222     };
223
224     /**
225      * Draws and shows the lineitem notes pane
226      */
227     this.drawLiNotes = function(li) {
228         var self = this;
229
230         li.lineitem_notes(
231             li.lineitem_notes().sort(
232                 function(a, b) { 
233                     if(a.edit_time() < b.edit_time()) return 1;
234                     return -1;
235                 }
236             )
237         );
238
239         while(this.liNotesTbody.childNodes[0])
240             this.liNotesTbody.removeChild(this.liNotesTbody.childNodes[0]);
241         this.show('notes');
242
243         acqLitCreateLiNoteSubmit.onClick = function() {
244             var value = acqLitCreateNoteText.attr('value');
245             if(!value) return;
246             var note = new fieldmapper.acqlin();
247             note.isnew(true);
248             note.value(value);
249             note.lineitem(li.id());
250             self.updateLiNotes(li, note);
251         }
252
253         dojo.byId('acq-lit-notes-save-button').onclick = function() {
254             self.updateLiNotes(li);
255         }
256
257         dojo.forEach(li.lineitem_notes(), function(note) { self.addLiNote(li, note) });
258     }
259
260     /**
261      * Draws a single lineitem note in the notes pane
262      */
263     this.addLiNote = function(li, note) {
264         if(note.isdeleted()) return;
265         var self = this;
266         var row = self.liNotesRow.cloneNode(true);
267         dojo.query('[name=value]', row)[0].innerHTML = note.value();
268
269         dojo.query('[name=delete]', row)[0].onclick = function() {
270             note.isdeleted(true);
271             self.liNotesTbody.removeChild(row);
272         };
273
274         if(note.edit_time()) {
275             dojo.query('[name=edit_time]', row)[0].innerHTML = 
276                 dojo.date.locale.format(
277                     dojo.date.stamp.fromISOString(note.edit_time()), 
278                     {formatLength:'short'});
279         }
280
281         self.liNotesTbody.appendChild(row);
282     }
283
284     /**
285      * Updates any new/changed/deleted notes on the server
286      */
287     this.updateLiNotes = function(li, newNote) {
288
289         var notes;
290         if(newNote) {
291             notes = [newNote];
292         } else {
293             notes = li.lineitem_notes().filter(
294                 function(note) {
295                     if(note.ischanged() || note.isnew() || note.isdeleted())
296                         return note;
297                 }
298             );
299         }
300
301         if(notes.length == 0) return;
302         progressDialog.show();
303
304         fieldmapper.standardRequest(
305             ['open-ils.acq', 'open-ils.acq.lineitem_note.cud.batch'],
306             {   async : true,
307                 params : [this.authtoken, notes],
308                 onresponse : function(r) {
309                     var resp = openils.Util.readResponse(r);
310
311                     if(resp.complete) {
312
313                         if(!newNote) {
314                             // remove the old changed notes
315                             var list = [];
316                             dojo.forEach(li.lineitem_notes(), 
317                                 function(note) {
318                                     if(!(note.ischanged() || note.isnew() || note.isdeleted()))
319                                         list.push(note);
320                                 }
321                             );
322                             li.lineitem_notes(list);
323                         }
324
325                         progressDialog.hide();
326                         self.drawLiNotes(li);
327                         return;
328                     }
329
330                     progressDialog.update(resp);
331                     var newnote = resp.note;
332
333                     if(!newnote.isdeleted()) {
334                         newnote.isnew(false);
335                         newnote.ischanged(false);
336                         li.lineitem_notes().push(newnote);
337                     }
338                 },
339             }
340         );
341     }
342
343     this.updateLiPrice = function(input, li) {
344
345         var price = input.value;
346         var liWrapper = new openils.acq.Lineitem({lineitem:li});
347         var oldPrice = liWrapper.getPrice() || null;
348
349         if(oldPrice) oldPrice = oldPrice.price;
350         if(price == oldPrice) return;
351
352         fieldmapper.standardRequest(
353             ['open-ils.acq', 'open-ils.acq.lineitem.price.set'],
354             {   async : true,
355                 params : [this.authtoken, li.id(), price],
356                 oncomplete : function(r) {
357                     openils.Util.readResponse(r);
358                 }
359             }
360         );
361     }
362
363     this.removeLineitem = function(liId) {
364         this.tbody.removeChild(dojo.query('[li='+liId+']', this.tbody)[0]);
365         delete this.liCache[liId];
366         //selected.push(self.liCache[i.parentNode.parentNode.getAttribute('li')]);
367     }
368
369     this.drawInfo = function(liId) {
370         this.show('info');
371         openils.acq.Lineitem.fetchAttrDefs(
372             function() { 
373                 self._fetchLineitem(liId, function(li){self._drawInfo(li);}); 
374             } 
375         );
376     };
377
378     this._fetchLineitem = function(liId, handler) {
379
380         var li = this.liCache[liId];
381         if(li && li.marc() && li.lineitem_details())
382             return handler(li);
383         
384         fieldmapper.standardRequest(
385             ['open-ils.acq', 'open-ils.acq.lineitem.retrieve'],
386             {   async: true,
387
388                 params: [self.authtoken, liId, {
389                     flesh_attrs: true,
390                     flesh_li_details: true,
391                     flesh_fund_debit: true }],
392
393                 oncomplete: function(r) {
394                     var li = openils.Util.readResponse(r);
395                     handler(li)
396                 }
397             }
398         );
399     };
400
401     this._drawInfo = function(li) {
402
403         acqLitEditOrderMarc.onClick = function() { self.editOrderMarc(li); }
404
405         if(li.eg_bib_id()) {
406             openils.Util.hide('acq-lit-marc-order-record-label');
407             openils.Util.hide(acqLitEditOrderMarc.domNode);
408             openils.Util.show('acq-lit-marc-real-record-label');
409         } else {
410             openils.Util.show('acq-lit-marc-order-record-label');
411             openils.Util.show(acqLitEditOrderMarc.domNode);
412             openils.Util.hide('acq-lit-marc-real-record-label');
413         }
414
415         this.drawMarcHTML(li);
416         this.infoTbody = dojo.byId('acq-lit-info-tbody');
417
418         if(!this.infoRow)
419             this.infoRow = this.infoTbody.removeChild(dojo.byId('acq-lit-info-row'));
420         while(this.infoTbody.childNodes[0])
421             this.infoTbody.removeChild(this.infoTbody.childNodes[0]);
422
423         for(var i = 0; i < li.attributes().length; i++) {
424             var attr = li.attributes()[i];
425             var row = this.infoRow.cloneNode(true);
426
427             var type = attr.attr_type().replace(/lineitem_(.*)_attr_definition/, '$1');
428             var name = openils.acq.Lineitem.attrDefs[type].filter(
429                 function(a) {
430                     return (a.code() == attr.attr_name());
431                 }
432             ).pop().description();
433
434             dojo.query('[name=label]', row)[0].appendChild(document.createTextNode(name));
435             dojo.query('[name=value]', row)[0].appendChild(document.createTextNode(attr.attr_value()));
436             this.infoTbody.appendChild(row);
437         }
438
439         if(li.eg_bib_id()) {
440             openils.Util.show('acq-lit-info-cat-link');
441             var link = dojo.byId('acq-lit-info-cat-link').getElementsByTagName('a')[0];
442
443             if(openils.XUL.isXUL()) {
444
445                 var makeRecTab = function() {
446                                     xulG.new_tab(
447                         XUL_OPAC_WRAPPER,
448                                             {tab_name: localeStrings.XUL_RECORD_DETAIL_PAGE, browser:false},
449                                             {
450                             no_xulG : false, 
451                             show_nav_buttons : true, 
452                             show_print_button : true, 
453                             opac_url : xulG.url_prefix(xulG.urls.opac_rdetail + '?r=' + li.eg_bib_id())
454                         }
455                     );
456                 }
457                 link.setAttribute('href', 'javascript:void(0);');
458                 link.onclick = makeRecTab;
459
460             } else {
461                 var href = link.getAttribute('href');
462                 if(href.match(/=$/))
463                     link.setAttribute('href',  href + li.eg_bib_id());
464             }
465         } else {
466             openils.Util.hide('acq-lit-info-cat-link');
467         }
468     };
469
470     this.drawMarcHTML = function(li) {
471         var params = [null, true, li.marc()];
472         if(li.eg_bib_id()) 
473             params = [li.eg_bib_id(), true];
474
475         fieldmapper.standardRequest(
476             ['open-ils.search', 'open-ils.search.biblio.record.html'],
477             {   async: true,
478                 params: params,
479                 oncomplete: function(r) {
480                     dojo.byId('acq-lit-marc-div').innerHTML = 
481                         openils.Util.readResponse(r);
482                 }
483             }
484         );
485     }
486
487     this.drawCopies = function(liId) {
488         this.show('copies');
489         var self = this;
490         this.copyCache = {};
491         this.copyWidgetCache = {};
492
493         acqLitSaveCopies.onClick = function() { self.saveCopyChanges(liId) };
494         acqLitBatchUpdateCopies.onClick = function() { self.batchCopyUpdate() };
495
496         while(this.copyTbody.childNodes[0])
497             this.copyTbody.removeChild(this.copyTbody.childNodes[0]);
498
499         this._drawBatchCopyWidgets();
500
501         this._fetchDistribFormulas(
502             function() {
503                 openils.acq.Lineitem.fetchAttrDefs(
504                     function() { 
505                         self._fetchLineitem(liId, function(li){self._drawCopies(li);}); 
506                     } 
507                 );
508             }
509         );
510     };
511
512     this._fetchDistribFormulas = function(onload) {
513         if(this.distribForms) {
514             onload();
515         } else {
516             var self = this;
517             fieldmapper.standardRequest(
518                 ['open-ils.acq', 'open-ils.acq.distribution_formula.ranged.retrieve.atomic'],
519                 {   async: true,
520                     params: [openils.User.authtoken],
521                     oncomplete: function(r) {
522                         self.distribForms = openils.Util.readResponse(r);
523                         if(!self.distribForms || self.distribForms.length == 0) {
524                             self.distribForms  = [];
525                             return onload();
526                         }
527                         self.distribFormulaStore = 
528                             new dojo.data.ItemFileReadStore(
529                                 {data:acqdf.toStoreData(self.distribForms)});
530                         onload();
531                     }
532                 }
533             );
534         }
535     }
536
537     this._drawBatchCopyWidgets = function() {
538         var row = this.copyBatchRow;
539         dojo.forEach(liDetailBatchFields, 
540             function(field) {
541                 if(self.copyBatchRowDrawn) {
542                     self.copyBatchWidgets[field].attr('value', null);
543                 } else {
544                     var widget = new openils.widget.AutoFieldWidget({
545                         fmField : field,
546                         fmClass : 'acqlid',
547                         parentNode : dojo.query('[name='+field+']', row)[0],
548                         orgLimitPerms : ['CREATE_PICKLIST'],
549                         dijitArgs : {required:false},
550                         forceSync : true
551                     });
552                     widget.build(
553                         function(w, ww) {
554                             self.copyBatchWidgets[field] = w;
555                         }
556                     );
557                 }
558             }
559         );
560         this.copyBatchRowDrawn = true;
561     };
562
563     this.batchCopyUpdate = function() {
564         var self = this;
565         for(var k in this.copyWidgetCache) {
566             var cache = this.copyWidgetCache[k];
567             dojo.forEach(liDetailBatchFields, function(f) {
568                 var newval = self.copyBatchWidgets[f].attr('value');
569                 if(newval) cache[f].attr('value', newval);
570             });
571         }
572     };
573
574     this._drawCopies = function(li) {
575         acqLitAddCopyCount.onClick = function() { 
576             var count = acqLitCopyCountInput.attr('value');
577             for(var i = 0; i < count; i++)
578                 self.addCopy(li); 
579         }
580         if(li.lineitem_details().length > 0) {
581             dojo.forEach(li.lineitem_details(),
582                 function(copy) {
583                     self.addCopy(li, copy);
584                 }
585             );
586         } else {
587             self.addCopy(li);
588         }
589     };
590
591     this.virtCopyId = -1;
592     this.addCopy = function(li, copy) {
593         var row = this.copyRow.cloneNode(true);
594         this.copyTbody.appendChild(row);
595         var self = this;
596
597         if(!copy) {
598             copy = new fieldmapper.acqlid();
599             copy.isnew(true);
600             copy.id(this.virtCopyId--);
601             copy.lineitem(li.id());
602         }
603
604         this.copyCache[copy.id()] = copy;
605         row.setAttribute('copy_id', copy.id());
606         self.copyWidgetCache[copy.id()] = {};
607
608         dojo.forEach(liDetailFields,
609             function(field) {
610                 var widget = new openils.widget.AutoFieldWidget({
611                     fmObject : copy,
612                     fmField : field,
613                     fmClass : 'acqlid',
614                     parentNode : dojo.query('[name='+field+']', row)[0],
615                     orgLimitPerms : ['CREATE_PICKLIST', 'CREATE_PURCHASE_ORDER'],
616                     readOnly : Boolean(copy.eg_copy_id())
617                 });
618                 widget.build(
619                     // make sure we capture the value from any async widgets
620                     function(w, ww) { 
621                         copy[field](ww.getFormattedValue()) 
622                         self.copyWidgetCache[copy.id()][field] = w;
623                     }
624                 );
625                 dojo.connect(widget.widget, 'onChange', 
626                     function(val) { 
627                         if(copy.isnew() || val != copy[field]()) {
628                             // prevent setting ischanged() automatically on widget load for existing copies
629                             copy[field](widget.getFormattedValue()) 
630                             copy.ischanged(true);
631                         }
632                     }
633                 );
634             }
635         );
636
637         var recv_link = dojo.query('[name=receive]', row)[0];
638         if(copy.recv_time()) {
639             openils.Util.hide(recv_link);
640         } else {
641             recv_link.onclick = function() {
642                 self.receiveLid(copy);
643                 openils.Util.hide(recv_link);
644             }
645         }
646
647         if(this.isPO) {
648             openils.Util.hide(dojo.query('[name=delete]', row)[0].parentNode);
649         } else {
650             dojo.query('[name=delete]', row)[0].onclick = 
651                 function() { self.deleteCopy(row) };
652         }
653     };
654
655     this.deleteCopy = function(row) {
656         var copy = this.copyCache[row.getAttribute('copy_id')];
657         copy.isdeleted(true);
658         if(copy.isnew())
659             delete this.copyCache[copy.id()];
660         this.copyTbody.removeChild(row);
661     }
662
663     this.saveCopyChanges = function(liId) {
664         var self = this;
665         var copies = [];
666
667
668         openils.Util.show('acq-lit-update-copies-progress');
669
670         var total = 0;
671         for(var id in this.copyCache) {
672             var c = this.copyCache[id];
673             if(!c.isdeleted()) total++;
674             if(c.isnew() || c.ischanged() || c.isdeleted()) {
675                 if(c.id() < 0) c.id(null);
676                 copies.push(c);
677             }
678         }
679
680         dojo.byId('acq-lit-copy-count-label-' + liId).innerHTML = total;
681
682         if(copies.length == 0)
683             return;
684
685         fieldmapper.standardRequest(
686             ['open-ils.acq', 'open-ils.acq.lineitem_detail.cud.batch'],
687             {   async: true,
688                 params: [openils.User.authtoken, copies],
689                 onresponse: function(r) {
690                     var res = openils.Util.readResponse(r);
691                     litUpdateCopiesProgress.update(res);
692                 },
693                 oncomplete: function() {
694                     openils.Util.hide('acq-lit-update-copies-progress');
695                     self.drawCopies(liId); 
696                 }
697             }
698         );
699     }
700
701     this.applySelectedLiAction = function(action) {
702         var self = this;
703         switch(action) {
704
705             case 'delete_selected':
706                 this._deleteLiList(self.getSelected());
707                 break;
708
709             case 'create_order':
710
711                 if(!this.createPoProviderSelector) {
712                     var widget = new openils.widget.AutoFieldWidget({
713                         fmField : 'provider',
714                         fmClass : 'acqpo',
715                         parentNode : dojo.byId('acq-lit-po-provider'),
716                     });
717                     widget.build(
718                         function(w) { self.createPoProviderSelector = w; }
719                     );
720                 }
721
722                 if(!this.createPoAgencySelector) {
723                     var widget = new openils.widget.AutoFieldWidget({
724                         fmField : 'ordering_agency',
725                         fmClass : 'acqpo',
726                         parentNode : dojo.byId('acq-lit-po-agency'),
727                         orgLimitPerms : ['CREATE_PURCHASE_ORDER'],
728                     });
729                     widget.build(
730                         function(w) { self.createPoAgencySelector = w; }
731                     );
732                 }
733
734          
735                 acqLitPoCreateDialog.show();
736                 break;
737
738             case 'save_picklist':
739                 this._loadPLSelect();
740                 acqLitSavePlDialog.show();
741                 break;
742
743             case 'print_po':
744                 this.printPO();
745                 break;
746
747             case 'receive_po':
748                 this.receivePO();
749                 break;
750
751             case 'rollback_receive_po':
752                 this.rollbackPoReceive();
753                 break;
754
755             case 'create_assets':
756                 this.createAssets();
757                 break;
758
759             case 'add_brief_record':
760                 if(this.isPO)
761                     location.href = oilsBasePath + '/acq/picklist/brief_record?po=' + this.isPO;
762                 else
763                     location.href = oilsBasePath + '/acq/picklist/brief_record?pl=' + this.isPL;
764         }
765     }
766
767     this.createAssets = function() {
768         if(!this.isPO) return;
769         if(!confirm(localeStrings.CREATE_PO_ASSETS_CONFIRM)) return;
770         this.show('acq-lit-progress-numbers');
771         var self = this;
772         fieldmapper.standardRequest(
773             ['open-ils.acq', 'open-ils.acq.purchase_order.assets.create'],
774             {   async: true,
775                 params: [this.authtoken, this.isPO],
776                 onresponse: function(r) {
777                     var resp = openils.Util.readResponse(r);
778                     self._updateProgressNumbers(resp, true);
779                 }
780             }
781         );
782     }
783
784     this.printPO = function() {
785         if(!this.isPO) return;
786         progressDialog.show(true);
787         fieldmapper.standardRequest(
788             ['open-ils.acq', 'open-ils.acq.purchase_order.format'],
789             {   async: true,
790                 params: [this.authtoken, this.isPO, 'html'],
791                 oncomplete: function(r) {
792                     progressDialog.hide();
793                     var evt = openils.Util.readResponse(r);
794                     if(evt && evt.template_output()) {
795                         win = window.open('','', 'resizable,width=800,height=600,scrollbars=1');
796                         win.document.body.innerHTML = evt.template_output().data();
797                     }
798                 }
799             }
800         );
801     }
802
803
804     this.receivePO = function() {
805         if(!this.isPO) return;
806         this.show('acq-lit-progress-numbers');
807         var self = this;
808         fieldmapper.standardRequest(
809             ['open-ils.acq', 'open-ils.acq.purchase_order.receive'],
810             {   async: true,
811                 params: [this.authtoken, this.isPO],
812                 onresponse : function(r) {
813                     var resp = openils.Util.readResponse(r);
814                     self._updateProgressNumbers(resp, true);
815                 },
816             }
817         );
818     }
819
820     this.receiveLi = function(li) {
821         if(!this.isPO) return;
822         progressDialog.show(true);
823         fieldmapper.standardRequest(
824             ['open-ils.acq', 'open-ils.acq.lineitem.receive'],
825             {   async: true,
826                 params: [this.authtoken, li.id()],
827                 onresponse : function(r) {
828                     var resp = openils.Util.readResponse(r);
829                     progressDialog.hide();
830                 },
831             }
832         );
833     }
834
835     this.receiveLid = function(li) {
836         if(!this.isPO) return;
837         progressDialog.show(true);
838         fieldmapper.standardRequest(
839             ['open-ils.acq', 'open-ils.acq.lineitem_detail.receive'],
840             {   async: true,
841                 params: [this.authtoken, li.id()],
842                 onresponse : function(r) {
843                     var resp = openils.Util.readResponse(r);
844                     progressDialog.hide();
845                 },
846             }
847         );
848     }
849
850     this.rollbackPoReceive = function() {
851         if(!this.isPO) return;
852         if(!confirm(localeStrings.ROLLBACK_PO_RECEIVE_CONFIRM)) return;
853         this.show('acq-lit-progress-numbers');
854         var self = this;
855         fieldmapper.standardRequest(
856             ['open-ils.acq', 'open-ils.acq.purchase_order.receive.rollback'],
857             {   async: true,
858                 params: [this.authtoken, this.isPO],
859                 onresponse : function(r) {
860                     var resp = openils.Util.readResponse(r);
861                     self._updateProgressNumbers(resp, true);
862                 },
863             }
864         );
865     }
866
867     this._updateProgressNumbers = function(resp, reloadOnComplete) {
868         if(!resp) return;
869         dojo.byId('acq-pl-lit-li-processed').innerHTML = resp.li;
870         dojo.byId('acq-pl-lit-lid-processed').innerHTML = resp.lid;
871         dojo.byId('acq-pl-lit-debits-processed').innerHTML = resp.debits_accrued;
872         dojo.byId('acq-pl-lit-bibs-processed').innerHTML = resp.bibs;
873         dojo.byId('acq-pl-lit-indexed-processed').innerHTML = resp.indexed;
874         dojo.byId('acq-pl-lit-copies-processed').innerHTML = resp.copies;
875         if(resp.complete && reloadOnComplete) 
876             location.href = location.href;
877     }
878
879
880     this._createPO = function(fields) {
881         this.show('acq-lit-progress-numbers');
882         var po = new fieldmapper.acqpo();
883         po.provider(this.createPoProviderSelector.attr('value'));
884         po.ordering_agency(this.createPoAgencySelector.attr('value'));
885
886         var selected = this.getSelected( (fields.create_from == 'all') );
887         if(selected.length == 0) return;
888
889         var max = selected.length * 3;
890
891         var self = this;
892         fieldmapper.standardRequest(
893             ['open-ils.acq', 'open-ils.acq.purchase_order.create'],
894             {   async: true,
895                 params: [
896                     openils.User.authtoken, 
897                     po, 
898                     {
899                         lineitems : selected.map(function(li) { return li.id() }),
900                         create_assets : fields.create_assets[0],
901                     }
902                 ],
903
904                 onresponse : function(r) {
905                     var resp = openils.Util.readResponse(r);
906                     self._updateProgressNumbers(resp);
907                     if(resp.complete) 
908                         location.href = oilsBasePath + '/eg/acq/po/view/' + resp.purchase_order.id();
909                 }
910             }
911         );
912     }
913
914     this._deleteLiList = function(list, idx) {
915         if(idx == null) idx = 0;
916         if(idx >= list.length) return;
917         var liId = list[idx].id();
918         fieldmapper.standardRequest(
919             ['open-ils.acq', 'open-ils.acq.lineitem.delete'],
920             {   async: true,
921                 params: [openils.User.authtoken, liId],
922                 oncomplete: function(r) {
923                     self.removeLineitem(liId);
924                     self._deleteLiList(list, ++idx);
925                 }
926             }
927         );
928     }
929
930     this.editOrderMarc = function(li) {
931
932         /*  To run in Firefox directly, must set signed.applets.codebase_principal_support
933             to true in about:config */
934
935         if(!openils.XUL.enableXPConnect()) return;
936
937         if(openils.XUL.isXUL()) {
938             win = window.open('/xul/' + openils.XUL.buildId() + '/server/cat/marcedit.xul');
939         } else {
940
941             win = window.open('/xul/server/cat/marcedit.xul'); 
942             var self = this;
943             win.xulG = {
944                 record : {marc : li.marc()},
945                 save : {
946                     label: 'Save Record', // XXX I18N
947                     func: function(xmlString) {
948                         li.marc(xmlString);
949                         fieldmapper.standardRequest(
950                             ['open-ils.acq', 'open-ils.acq.lineitem.update'],
951                             {   async: true,
952                                 params: [openils.User.authtoken, li],
953                                 oncomplete: function(r) {
954                                     openils.Util.readResponse(r);
955                                     win.close();
956                                     self.drawInfo(li.id())
957                                 }
958                             }
959                         );
960                     },
961                 }
962             };
963         }
964     }
965
966     this._savePl = function(values) {
967         var self = this;
968         var selected = this.getSelected( (values.which == 'all') );
969         openils.Util.show('acq-lit-generic-progress');
970
971         if(values.new_name) {
972             openils.acq.Picklist.create(
973                 {name: values.new_name}, 
974                 function(id) {
975                     self._updateLiList(id, selected, 0, 
976                         function(){
977                             location.href = oilsBasePath + '/eg/acq/picklist/view/' + id;
978                         });
979                 }
980             );
981         } else if(values.existing_pl) {
982             // update lineitems to use an existing picklist
983             self._updateLiList(values.existing_pl, selected, 0, 
984                 function(){
985                     location.href = oilsBasePath + '/eg/acq/picklist/view/' + values.existing_pl;
986                 });
987         }
988     }
989
990     this._updateLiList = function(pl, list, idx, oncomplete) {
991         if(idx >= list.length) return oncomplete();
992         var li = list[idx];
993         li.picklist(pl);
994         litGenericProgress.update({maximum: list.length, progress: idx});
995         new openils.acq.Lineitem({lineitem:li}).update(
996             function(r) {
997                 self._updateLiList(pl, list, ++idx, oncomplete);
998             }
999         );
1000     }
1001
1002     this._loadPLSelect = function() {
1003         if(this._plSelectLoaded) return;
1004         var plList = [];
1005         function handleResponse(r) {
1006             plList.push(r.recv().content());
1007         }
1008         var method = 'open-ils.acq.picklist.user.retrieve';
1009         fieldmapper.standardRequest(
1010             ['open-ils.acq', method],
1011             {   async: true,
1012                 params: [this.authtoken],
1013                 onresponse: handleResponse,
1014                 oncomplete: function() {
1015                     self._plSelectLoaded = true;
1016                     acqLitAddExistingSelect.store = 
1017                         new dojo.data.ItemFileReadStore({data:acqpl.toStoreData(plList)});
1018                     acqLitAddExistingSelect.setValue();
1019                 }
1020             }
1021         );
1022     }
1023
1024     // grab the li-details for this lineitem, grab the linked copies and volumes, add them to the table
1025     this.showRealCopies = function(li) {
1026         while(this.realCopiesTbody.childNodes[0])
1027             this.realCopiesTbody.removeChild(this.realCopiesTbody.childNodes[0]);
1028         this.show('real-copies');
1029
1030         var pcrud = new openils.PermaCrud({authtoken : this.authtoken});
1031         this.realCopyList = [];
1032         this.volCache = {};
1033         var tabIndex = 1000;
1034         var self = this;
1035
1036         acqLitSaveRealCopies.onClick = function() {
1037             self.saveRealCopies();
1038         }
1039
1040         this._fetchLineitem(li.id(), 
1041             function(fullLi) {
1042                 li = self.liCache[li.id()] = fullLi;
1043
1044                 pcrud.search(
1045                     'acp', {
1046                         id : li.lineitem_details().map(
1047                             function(item) { return item.eg_copy_id() }
1048                         )
1049                     }, {
1050                         async : true,
1051                         streaming : true,
1052                         onresponse : function(r) {
1053                             var copy = openils.Util.readResponse(r);
1054                             var volId = copy.call_number();
1055                             var volume = self.volCache[volId];
1056                             if(!volume) {
1057                                 volume = self.volCache[volId] = pcrud.retrieve('acn', volId);
1058                             }
1059                             self.addRealCopy(volume, copy, tabIndex++);
1060                         }
1061                     }
1062                 );
1063             }
1064         );
1065     }
1066
1067     this.addRealCopy = function(volume, copy, tabIndex) {
1068         var row = this.realCopiesRow.cloneNode(true);
1069         this.realCopyList.push(copy);
1070
1071         var selectNode;
1072         dojo.forEach(
1073             ['owning_lib', 'location', 'circ_modifier', 'label', 'barcode'],
1074
1075             function(field) {
1076                 var isvol = (field == 'owning_lib' || field == 'label');
1077                 var widget = new openils.widget.AutoFieldWidget({
1078                     fmField : field,
1079                     fmObject : isvol ? volume : copy,
1080                     parentNode : nodeByName(field, row),
1081                     readOnly : (field != 'barcode'),
1082                 });
1083
1084                 var widgetDrawn = null;
1085
1086                 if(field == 'barcode') {
1087
1088                     widgetDrawn = function(w, ww) {
1089                         var node = w.domNode;
1090                         node.setAttribute('tabindex', ''+tabIndex);
1091
1092                         // on enter, select the next barcode input
1093                         dojo.connect(w, 'onKeyDown',
1094                             function(e) {
1095                                 if(e.keyCode == dojo.keys.ENTER) {
1096                                     var ti = node.getAttribute('tabindex');
1097                                     var nextNode = dojo.query('[tabindex=' + String(Number(ti) + 1) + ']', self.realCopiesTbody)[0];
1098                                     if(nextNode) nextNode.select();
1099                                 }
1100                             }
1101                         );
1102
1103                         dojo.connect(w, 'onChange', 
1104                             function(val) { 
1105                                 if(!val || val == copy.barcode()) return;
1106                                 copy.ischanged(true);
1107                                 copy.barcode(val);
1108                             }
1109                         );
1110
1111
1112                         if(self.realCopiesTbody.getElementsByTagName('TR').length == 0)
1113                             selectNode = node;
1114                     }
1115                 }
1116
1117                 widget.build(widgetDrawn);
1118             }
1119         );
1120
1121         this.realCopiesTbody.appendChild(row);
1122         if(selectNode) selectNode.select();
1123     };
1124
1125     this.saveRealCopies = function() {
1126         var pcrud = new openils.PermaCrud({authtoken : this.authtoken});
1127         progressDialog.show(true);
1128         var list = this.realCopyList.filter(function(copy) { return copy.ischanged(); });
1129         pcrud.update(list, {oncomplete: function() { 
1130             progressDialog.hide();
1131             self.show('list');
1132         }});
1133     }
1134 }
1135
1136
1137