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