]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/xul/staff_client/server/serial/manage_items.js
Teach the i18n Makefile how to handle serial.properties
[working/Evergreen.git] / Open-ILS / xul / staff_client / server / serial / manage_items.js
1 dump('entering manage_items.js\n');
2
3 function $(id) { return document.getElementById(id); }
4
5 if (typeof serial == 'undefined') serial = {};
6 serial.manage_items = function (params) {
7
8         JSAN.use('util.error'); this.error = new util.error();
9         JSAN.use('util.network'); this.network = new util.network();
10         JSAN.use('OpenILS.data'); this.data = new OpenILS.data(); this.data.init({'via':'stash'});
11
12     this.current_sunit_id = -1; //default to **AUTO**
13     this.mode = 'receive';
14
15 }
16
17 serial.manage_items.prototype = {
18
19         'list_sitem_map' : {},
20
21     'set_sdist_ids' : function () {
22                 var obj = this;
23
24         try {
25             obj.holding_lib = $('serial_item_lib_menu').value;
26             var robj = obj.network.request(
27                 'open-ils.pcrud',
28                 'open-ils.pcrud.id_list.sdist',
29                 [ ses(), {"holding_lib" : obj.holding_lib, "+ssub":{"record_entry" : obj.docid}}, {"join":"ssub"} ]
30             );
31             if (robj != null) {
32                 if (typeof robj.ilsevent != 'undefined') throw(robj);
33                 obj.sdist_ids = robj.length ? robj : [robj];
34             } else {
35                 obj.sdist_ids = [];
36             }
37         } catch(E) {
38             obj.error.standard_unexpected_error_alert('set_sdist_ids failed!',E);
39         }
40     },
41
42     'build_menus' : function () {
43                 var obj = this;
44
45         // draw library drop-down
46         obj.org_ids = obj.network.simple_request('FM_SSUB_AOU_IDS_RETRIEVE_VIA_RECORD_ID.authoritative',[ obj.docid ]);
47         if (typeof obj.org_ids.ilsevent != 'undefined') throw(obj.org_ids);
48         JSAN.use('util.functional');
49         obj.org_ids = util.functional.map_list( obj.org_ids, function (o) { return Number(o); });
50
51         var org = obj.data.hash.aou[ obj.data.list.au[0].ws_ou() ];
52
53         JSAN.use('util.file'); JSAN.use('util.widgets');
54
55         var file; var list_data; var ml;
56
57         file = new util.file('offline_ou_list');
58         if (file._file.exists()) {
59             list_data = file.get_object(); file.close();
60             ml = util.widgets.make_menulist( list_data[0], list_data[1] );
61             ml.setAttribute('id','serial_item_lib_menu'); document.getElementById('serial_item_lib_menu_box').appendChild(ml);
62             //TODO: class this menu properly
63             for (var i = 0; i < obj.org_ids.length; i++) {
64                 ml.getElementsByAttribute('value',obj.org_ids[i])[0].setAttribute('class','has_distributions');
65             }
66             /*TODO: add/enable this legend?
67             ml.firstChild.addEventListener(
68                 'popupshown',
69                 function(ev) {
70                     document.getElementById('legend').setAttribute('hidden','false');
71                 },
72                 false
73             );
74             ml.firstChild.addEventListener(
75                 'popuphidden',
76                 function(ev) {
77                     document.getElementById('legend').setAttribute('hidden','true');
78                 },
79                 false
80             );*/
81             ml.addEventListener(
82                 'command',
83                 function(ev) {
84                     //if (document.getElementById('serial_item_refresh_button')) document.getElementById('serial_item_refresh_button').focus();
85                     obj.save_settings();
86                     // get latest sdist id list based on library drowdown
87                     obj.set_sdist_ids();
88                     obj.refresh_list('main');
89                     obj.refresh_list('workarea');
90                 },
91                 false
92             );
93
94         } else {
95             throw(document.getElementById('catStrings').getString('staff.cat.copy_browser.missing_library') + '\n');
96         }
97         file = new util.file('serial_items_prefs.'+obj.data.server_unadorned);
98         util.widgets.load_attributes(file);
99         ml.value = ml.getAttribute('value');
100         if (! ml.value) {
101             ml.value = org.id();
102             ml.setAttribute('value',ml.value);
103         }
104         
105         // deal with mode radio selectedIndex, as load_attributes is setting a "read-only" value
106         if ($('mode_receive').getAttribute('selected')) {
107             $('serial_manage_items_mode').selectedIndex = 0;
108         } else {
109             $('serial_manage_items_mode').selectedIndex = 1;
110         }
111
112         // setup recent sunits list
113         var recent_sunits_file = new util.file('serial_items_recent_sunits_'+obj.docid+'.'+obj.data.server_unadorned);
114         util.widgets.load_attributes(recent_sunits_file);
115         var recent_sunits_popup = $('serial_items_recent_sunits');
116         obj.sunit_entries = JSON2js(recent_sunits_popup.getAttribute('sunit_json'));
117         for (i = 0; i < obj.sunit_entries.length; i++) {
118             var sunit_info = obj.sunit_entries[i];
119             var new_menu_item = recent_sunits_popup.appendItem(sunit_info.label);
120             new_menu_item.setAttribute('id', 'serial_items_recent_sunits_entry_'+sunit_info.id);
121             new_menu_item.setAttribute('sunit_id', sunit_info.id);
122             new_menu_item.setAttribute('command', 'cmd_set_sunit');
123         }
124     },
125
126         'init' : function( params ) {
127                 var obj = this;
128
129                 obj.docid = params['docid'];
130
131         obj.build_menus();
132         obj.set_sunit($('serial_items_current_sunit').getAttribute('sunit_id'), $('serial_items_current_sunit').getAttribute('sunit_label'), $('serial_items_current_sunit').getAttribute('sdist_id'), $('serial_items_current_sunit').getAttribute('sstr_id'));
133         obj.set_sdist_ids();
134                 obj.init_lists();
135
136         var mode_radio_group = $('serial_manage_items_mode');
137         obj.set_mode(mode_radio_group.selectedItem.id.substr(5));
138         mode_radio_group.addEventListener(
139             'command',
140             function(ev) {
141                 obj.save_settings();
142                 var mode = ev.target.id.substr(5); //strip out 'mode_'
143                 obj.set_mode(mode);
144                 obj.refresh_list('main');
145                 obj.refresh_list('workarea');
146             },
147             false
148         );
149         $('serial_manage_items_show_all').addEventListener(
150             'command',
151             function(ev) {
152                 obj.save_settings();
153                 obj.set_mode();
154                 obj.refresh_list('main');
155                 obj.refresh_list('workarea');
156             },
157             false
158         );
159
160                 JSAN.use('util.controller'); obj.controller = new util.controller();
161                 obj.controller.init(
162                         {
163                                 'control_map' : {
164                                         'save_columns' : [ [ 'command' ], function() { obj.lists.main.save_columns(); } ],
165                                         'cmd_broken' : [ ['command'], function() { alert('Not Yet Implemented'); } ],
166                                         'sel_clip' : [ ['command'], function() { obj.lists.main.clipboard(); } ],
167                     'cmd_add_item' : [
168                         ['command'],
169                         function() {
170                             try {
171                                 var new_item = new sitem();
172                                 new_item.issuance(new siss());
173                                 new_item.stream(1); //FIXME: hard-coded stream
174                                 new_item.issuance().subscription(1); //FIXME: hard-coded subscription
175                                 new_item.isnew(1);
176                                 new_item.issuance().isnew(1);
177                                 spawn_sitem_editor( {'sitems' : [new_item], 'do_edit' : 1 } );
178
179                                 obj.refresh_list('main');
180
181                             } catch(E) {
182                                 obj.error.standard_unexpected_error_alert(document.getElementById('catStrings').getString('staff.cat.copy_browser.edit_items.error'),E);
183                             }
184                         }
185                     ],
186                     'cmd_edit_items' : [
187                         ['command'],
188                         function() {
189                             try {
190                                 if (!obj.retrieve_ids || obj.retrieve_ids.length == 0) return;
191
192                                 JSAN.use('util.functional');
193                                 var list = util.functional.map_list(
194                                         obj.retrieve_ids,
195                                         function (o) {
196                                             return o.sitem_id;
197                                         }
198                                     );
199
200                                 spawn_sitem_editor( { 'sitem_ids' : list, 'do_edit' : 1 } );
201
202                                 obj.refresh_list(obj.selected_list);
203
204                             } catch(E) {
205                                 obj.error.standard_unexpected_error_alert(document.getElementById('catStrings').getString('staff.cat.copy_browser.edit_items.error'),E);
206                             }
207                         }
208                     ],
209                     'cmd_reset_items' : [
210                         ['command'],
211                         function() {
212                             try {
213                                 if (!obj.retrieve_ids || obj.retrieve_ids.length == 0) return;
214
215                                 JSAN.use('util.functional');
216                                 var list = util.functional.map_list(
217                                         obj.retrieve_ids,
218                                         function (o) {
219                                             return o.sitem_id;
220                                         }
221                                     );
222
223                                 var robj = obj.network.request(
224                                             'open-ils.serial',
225                                             'open-ils.serial.reset_items',
226                                             [ ses(), list ]
227                                         );
228                                 if (typeof robj.ilsevent != 'undefined') throw(robj);
229
230                                 alert('Successfully reset '+robj.num_items+' item(s)');
231
232                                 obj.refresh_list('main');
233                                 obj.refresh_list('workarea');
234                             } catch(E) {
235                                 obj.error.standard_unexpected_error_alert('staff.serial.manage_items.reset_items.error',E);
236                             }
237                         }
238                     ],
239                     'cmd_delete_items' : [
240                         ['command'],
241                         function() {
242                             try {
243                                 JSAN.use('util.functional');
244                                 var list = util.functional.map_list(
245                                         obj.retrieve_ids,
246                                         function (o) {
247                                             return obj.list_sitem_map[o.sitem_id];
248                                         }
249                                     );
250                                 var delete_msg;
251                                 if (list.length != 1) {
252                                     delete_msg = document.getElementById('catStrings').getFormattedString('staff.cat.copy_browser.delete_items.confirm.plural', [list.length]);
253                                 } else {
254                                     delete_msg = document.getElementById('catStrings').getString('staff.cat.copy_browser.delete_items.confirm');
255                                 }
256                                 var r = obj.error.yns_alert(
257                                         delete_msg,
258                                         document.getElementById('catStrings').getString('staff.cat.copy_browser.delete_items.title'),
259                                         document.getElementById('catStrings').getString('staff.cat.copy_browser.delete_items.delete'),
260                                         document.getElementById('catStrings').getString('staff.cat.copy_browser.delete_items.cancel'),
261                                         null,
262                                         document.getElementById('commonStrings').getString('common.confirm')
263                                 );
264
265                                 if (r == 0) {
266                                     for (var i = 0; i < list.length; i++) {
267                                         list[i].isdeleted('1');
268                                     }
269                                     var robj = obj.network.request(
270                                             'open-ils.serial',
271                                             'open-ils.serial.item.fleshed.batch.update',
272                                         [ ses(), list, true ],
273                                         null,
274                                         {
275                                             'title' : document.getElementById('catStrings').getString('staff.cat.copy_browser.delete_items.override'),
276                                             'overridable_events' : [ // FIXME: replace or delete these events
277                                                 1208 /* TITLE_LAST_COPY */,
278                                                 1227 /* COPY_DELETE_WARNING */,
279                                             ]
280                                         }
281                                     );
282                                     if (robj == null) throw(robj);
283                                     if (typeof robj.ilsevent != 'undefined') {
284                                         if ( (robj.ilsevent != 0) && (robj.ilsevent != 1227 /* COPY_DELETE_WARNING */) && (robj.ilsevent != 1208 /* TITLE_LAST_COPY */) ) throw(robj);
285                                     }
286                                     obj.refresh_list(obj.selected_list);
287                                 }
288
289
290                             } catch(E) {
291                                 obj.error.standard_unexpected_error_alert('staff.serial.manage_items.delete_items.error',E);
292                                 obj.refresh_list();
293                             }
294                         }
295                     ],
296                     'cmd_set_sunit' : [
297                         ['command'],
298                         function(evt) {
299                             try {
300                                 var target = evt.explicitOriginalTarget;
301                                 var label = target.label;
302                                 var sunit_id = target.getAttribute('sunit_id');
303                                 var sdist_id = target.getAttribute('sdist_id');
304                                 var sstr_id = target.getAttribute('sstr_id');
305                                 obj.set_sunit(sunit_id, label, sdist_id, sstr_id);
306                                 obj.save_sunit(sunit_id, label, sdist_id, sstr_id);
307                                 if (obj.mode == 'bind') obj.refresh_list('workarea');
308                             } catch(E) {
309                                 obj.error.standard_unexpected_error_alert('cmd_set_sunit failed!',E);
310                             }
311                         }
312                     ],
313                     'cmd_set_other_sunit' : [
314                         ['command'],
315                         function() {
316                             obj.set_other_sunit();
317                             if (obj.mode == 'bind') obj.refresh_list('workarea');
318                         }
319                     ],
320                     'cmd_predict_items' : [
321                         ['command'],
322                         function() {
323                             alert('Subscription selection needed here'); //FIXME: make this prompt, or discard this feature
324                         }
325                     ],
326                     'cmd_receive_items' : [
327                         ['command'],
328                         function() {
329                             try {
330                                 JSAN.use('util.functional');
331                                 var list = util.functional.map_list(
332                                         obj.retrieve_ids,
333                                         function (o) {
334                                             var item = obj.list_sitem_map[o.sitem_id];
335                                             item.unit(obj.current_sunit_id);
336                                             return item;
337                                         }
338                                     );
339
340                                 var method; var success_label;
341                                 if (obj.mode == 'receive') {
342                                     method = 'open-ils.serial.receive_items';
343                                     success_label = 'received';
344                                 } else { // bind mode
345                                     method = 'open-ils.serial.bind_items';
346                                     success_label = 'bound';
347                                 } 
348
349                                 // deal with barcodes and call numbers for *NEW* units
350                                 var barcodes = {};
351                                 var call_numbers = {};
352                                 var call_numbers_by_issuance_id = {};
353
354                                 if (obj.current_sunit_id < 0) { // **AUTO** or **NEW** units
355                                     var new_unit_barcode = '';
356                                     var new_unit_call_number = '';
357                                     for (var i = 0; i < list.length; i++) {
358                                         var item = list[i];
359                                         if (new_unit_barcode) {
360                                             barcodes[item.id()] = new_unit_barcode;
361                                             call_numbers[item.id()] = new_unit_call_number;
362                                             continue;
363                                         }
364                                         var prompt_text;
365                                         if (obj.current_sunit_id == -1) {
366                                             prompt_text = 'for '+item.issuance().label()+ ' from Distribution: '+item.stream().distribution().label()+'/'+item.stream().id()+':';
367                                         } else { // must be -2
368                                             prompt_text = 'for the new unit:';
369                                         }
370
371                                         // first barcodes
372                                         var barcode = window.prompt('Please enter a barcode ' + prompt_text,
373                                             '@@AUTO',
374                                             'Unit Barcode Prompt');
375                                         barcode = String( barcode ).replace(/\s/g,'');
376                                         /* Casting a possibly null input value to a String turns it into "null" */
377                                         if (!barcode || barcode == 'null') {
378                                             alert('Invalid barcode entered, defaulting to system-generated.');
379                                             barcode = '@@AUTO';
380                                         } else {
381                                             var test = obj.network.simple_request('FM_ACP_RETRIEVE_VIA_BARCODE',[ barcode ]);
382                                             if (typeof test.ilsevent == 'undefined') {
383                                                 alert('Another copy has barcode "' + barcode + '", defaulting to system-generated.');
384                                                 barcode = '@@AUTO';
385                                             }
386                                         }
387                                         barcodes[item.id()] = barcode;
388
389                                         // now call numbers
390                                         if (typeof call_numbers_by_issuance_id[item.issuance().id()] == 'undefined') {
391                                             var default_cn = 'DEFAULT';
392                                             // if they defined a *_call_number, honor it as the default
393                                             var preset_cn_id = item.stream().distribution()[obj.mode + '_call_number']();
394                                             if (preset_cn_id) {
395                                                 var preset_default_cn = obj.network.request(
396                                                         'open-ils.pcrud',
397                                                         'open-ils.pcrud.retrieve.acn',
398                                                         [ ses(), preset_cn_id ]
399                                                 );
400                                                 if (preset_default_cn) {
401                                                     default_cn = preset_default_cn.label();
402                                                 }
403                                             } else {
404                                                 // for now, let's default to the last created call number if there is one
405                                                 // TODO: make this distribution specific
406                                                 var acn_list = obj.network.request(
407                                                         'open-ils.pcrud',
408                                                         'open-ils.pcrud.search.acn',
409                                                         [ ses(), {"record" : obj.docid, "owning_lib" : obj.holding_lib, "deleted" : 'f' }, {"order_by" : {"acn" : "create_date DESC"}, "limit" : "1" } ]
410                                                 );
411
412                                                 if (acn_list) {
413                                                     default_cn = acn_list.label();
414                                                 }
415                                             }
416                                             var call_number = window.prompt('Please enter/adjust a call number ' + prompt_text,
417                                                 default_cn, //TODO: real default by setting
418                                                 'Unit Call Number Prompt');
419                                             call_number = String( call_number ).replace(/^\s+/,'').replace(/\s$/,'');
420                                             /* Casting a possibly null input value to a String turns it into "null" */
421                                             if (!call_number || call_number == 'null') {
422                                                 alert('Invalid call number entered, setting to "DEFAULT".');
423                                                 call_number = 'DEFAULT'; //TODO: real default by setting
424                                             }
425                                             call_numbers[item.id()] = call_number;
426                                             call_numbers_by_issuance_id[item.issuance().id()] = call_number;
427                                         } else {
428                                             // we have already seen this same issuance, so use the same call number
429                                             call_numbers[item.id()] = call_numbers_by_issuance_id[item.issuance().id()];
430                                         }
431
432                                         if (obj.current_sunit_id == -2) {
433                                             new_unit_barcode = barcode;
434                                             new_unit_call_number = call_number;
435                                         }
436                                     }
437                                 }
438
439                                 var robj = obj.network.request(
440                                             'open-ils.serial',
441                                             method,
442                                             [ ses(), list, barcodes, call_numbers ]
443                                         );
444                                 if (typeof robj.ilsevent != 'undefined') throw(robj); //TODO: catch for override
445
446                                 alert('Successfully '+success_label+' '+robj.num_items+' item(s)');
447
448                                 if (obj.current_sunit_id == -2) {
449                                     obj.current_sunit_id = robj.new_unit_id;
450                                 }
451
452                                 obj.rebuild_current_sunit(list[0].stream().distribution().label(), list[0].stream().distribution().id(), list[0].stream().id());
453                                 obj.refresh_list('main');
454                                 obj.refresh_list('workarea');
455                                 
456                             } catch(E) {
457                                 obj.error.standard_unexpected_error_alert('cmd_receive_items failed!',E);
458                             }
459                         }
460                     ],
461                     'cmd_edit_sunit' : [
462                         ['command'],
463                         function() {
464                             try {
465                                 /*if (!obj.retrieve_ids || obj.retrieve_ids.length == 0) return;
466
467                                 JSAN.use('util.functional');
468                                 var list = util.functional.map_list(
469                                         obj.retrieve_ids,
470                                         function (o) {
471                                             return o.sitem_id;
472                                         }
473                                     );
474 */
475                                 spawn_sunit_editor( { 'sunit_ids' : [1], 'edit' : 1 } ); //FIXME: hard-coded sunit
476
477                             } catch(E) {
478                                 obj.error.standard_unexpected_error_alert('cmd_edit_sunit failed!',E);
479                             }
480                         }
481                     ],
482
483                     'cmd_items_print' : [ ['command'], function() { obj.items_print(obj.selected_list); } ],
484                                         'cmd_items_export' : [ ['command'], function() { obj.items_export(obj.selected_list); } ],
485                                         'cmd_refresh_list' : [ ['command'], function() { obj.set_sdist_ids(); obj.refresh_list('main'); obj.refresh_list('workarea'); } ]
486                                 }
487                         }
488                 );
489         
490                 obj.retrieve('main'); // retrieve main list
491         obj.retrieve('workarea'); // retrieve shelving unit list
492
493                 obj.controller.view.sel_clip.setAttribute('disabled','true');
494
495         },
496
497         'items_print' : function(which) {
498                 var obj = this;
499                 try {
500                         var list = obj.lists[which];
501 /* FIXME: serial items print template?                  JSAN.use('patron.util');
502                         var params = { 
503                                 'patron' : patron.util.retrieve_fleshed_au_via_id(ses(),obj.patron_id), 
504                                 'template' : 'items_out'
505                         }; */
506                         list.print( params );
507                 } catch(E) {
508                         obj.error.standard_unexpected_error_alert('manage_items printing',E);
509                 }
510         },
511
512         'items_export' : function(which) {
513                 var obj = this;
514                 try {
515                         var list = obj.lists[which];
516                         list.dump_csv_to_clipboard();
517                 } catch(E) {
518                         obj.error.standard_unexpected_error_alert('manage_items export',E);
519                 }
520         },
521
522         'rebuild_current_sunit' : function(sdist_label, sdist_id, sstr_id) {
523                 var obj = this;
524                 try {
525             var robj = obj.network.request(
526                 'open-ils.pcrud',
527                 'open-ils.pcrud.retrieve.sunit',
528                 [ ses(),  obj.current_sunit_id]
529             );
530             if (!robj) return; // current sunit is NEW or AUTO
531
532             var label = '[' + sdist_label + '/' + sstr_id + ' #' + obj.current_sunit_id + '] ' + robj.summary_contents();
533             obj.set_sunit(obj.current_sunit_id, label, sdist_id, sstr_id);
534             obj.save_sunit(obj.current_sunit_id, label, sdist_id, sstr_id);
535                 } catch(E) {
536                         obj.error.standard_unexpected_error_alert('serial items set_sunit',E);
537                 }
538         },
539
540         'set_sunit' : function(sunit_id, label, sdist_id, sstr_id) {
541                 var obj = this;
542                 try {
543             obj.current_sunit_id = sunit_id;
544             obj.current_sunit_sdist_id = sdist_id;
545             obj.current_sunit_sstr_id = sstr_id;
546             if (sunit_id < 0) {
547                 $('serial_workarea_sunit_desc').firstChild.nodeValue = '**' + label + '**';
548             } else {
549                 $('serial_workarea_sunit_desc').firstChild.nodeValue = label;
550                 obj.add_sunit_to_menu(sunit_id, label, sdist_id, sstr_id);
551             }
552                 } catch(E) {
553                         obj.error.standard_unexpected_error_alert('serial items set_sunit',E);
554                 }
555         },
556
557         'save_sunit' : function(sunit_id, label, sdist_id, sstr_id) {
558                 var obj = this;
559                 try {
560             $('serial_items_current_sunit').setAttribute('sunit_id', sunit_id);
561             $('serial_items_current_sunit').setAttribute('sunit_label', label);
562             if (sunit_id > 0) {
563                 $('serial_items_current_sunit').setAttribute('sdist_id', sdist_id);
564                 $('serial_items_current_sunit').setAttribute('sstr_id', sstr_id);
565             }
566             var recent_sunits_file = new util.file('serial_items_recent_sunits_'+obj.docid+'.'+obj.data.server_unadorned);
567             util.widgets.save_attributes(recent_sunits_file, { 'serial_items_recent_sunits' : [ 'sunit_json' ], 'serial_items_current_sunit' : [ 'sunit_id', 'sunit_label', 'sdist_id', 'sstr_id' ] });
568                 } catch(E) {
569                         obj.error.standard_unexpected_error_alert('serial items save_sunit',E);
570                 }
571         },
572
573         'set_other_sunit' : function() {
574                 var obj = this;
575                 try {
576             JSAN.use('util.window'); var win = new util.window();
577             var select_unit_window = win.open(
578                 xulG.url_prefix(urls.XUL_SERIAL_SELECT_UNIT),
579                 '_blank',
580                 'chrome,resizable,modal,centerscreen',
581                 {'sdist_ids' : obj.sdist_ids}
582             );
583             if (!select_unit_window.sunit_selection) {
584                 return;
585             }
586
587             var selection = select_unit_window.sunit_selection;
588             var sunit_id = selection.sunit;
589             var sdist_id = selection.sdist;
590             var sstr_id = selection.sstr;
591             var label = selection.label;
592
593             obj.set_sunit(sunit_id, label, sdist_id, sstr_id);
594             obj.save_sunit(sunit_id, label, sdist_id, sstr_id);
595                 } catch(E) {
596                         obj.error.standard_unexpected_error_alert('serial items set_other_sunit',E);
597                 }
598         },
599
600         'add_sunit_to_menu' : function(sunit_id, label, sdist_id, sstr_id) {
601                 var obj = this;
602                 try {
603             if (sunit_id > 0) {
604                 // check if it is already in sunit_entries, remove it
605                 for (i = 0; i < obj.sunit_entries.length; i++) {
606                     if (obj.sunit_entries[i].id == sunit_id) {
607                         obj.sunit_entries.splice(i,1);
608                         var menu_item = $('serial_items_recent_sunits_entry_'+sunit_id);
609                         menu_item.parentNode.removeChild(menu_item);
610                         i--;
611                     }
612                 }
613                 // add to front of array
614                 obj.sunit_entries.unshift({"id" : sunit_id, "label" : label, "sdist_id" : sdist_id, "sstr_id" : sstr_id});
615                 var recent_sunits_popup = $('serial_items_recent_sunits');
616                 var new_menu_item = recent_sunits_popup.insertItemAt(0,label);
617                 new_menu_item.setAttribute('id', 'serial_items_recent_sunits_entry_'+sunit_id);
618                 new_menu_item.setAttribute('sunit_id', sunit_id);
619                 new_menu_item.setAttribute('sdist_id', sdist_id);
620                 new_menu_item.setAttribute('sstr_id', sstr_id);
621                 new_menu_item.setAttribute('command', 'cmd_set_sunit');
622
623                 // pop off from sunit_entries if it already has 10 sunits
624                 if (obj.sunit_entries.length > 10) {
625                     var sunit_info = obj.sunit_entries.pop();
626                     var menu_item = $('serial_items_recent_sunits_entry_'+sunit_info.id);
627                     menu_item.parentNode.removeChild(menu_item);
628                 }
629
630                 recent_sunits_popup.setAttribute('sunit_json', js2JSON(obj.sunit_entries));
631             }
632                 } catch(E) {
633                         obj.error.standard_unexpected_error_alert('serial items add_sunit_to_menu',E);
634                 }
635         },
636
637         'set_mode' : function(mode) {
638                 var obj = this;
639
640         if (!mode) {
641             mode = obj.mode;
642         } else {
643             obj.mode = mode;
644         }
645
646         if (mode == 'receive') {
647             $('serial_workarea_mode_label').value = 'Recently Received';
648             if ($('serial_manage_items_show_all').checked) {
649                 obj.lists.main.sitem_retrieve_params = {};
650             } else {
651                 obj.lists.main.sitem_retrieve_params = {'date_received' : null };
652             }
653             obj.lists.main.sitem_extra_params ={'order_by' : {'sitem' : 'date_expected ASC, stream ASC'}};
654
655             obj.lists.workarea.sitem_retrieve_params = {'date_received' : {"!=" : null}};
656             obj.lists.workarea.sitem_extra_params ={'order_by' : {'sitem' : 'date_received DESC'}, 'limit' : 30};
657         } else { // bind mode
658             $('serial_workarea_mode_label').value = 'Bound Items in Current Working Unit';
659             if ($('serial_manage_items_show_all').checked) {
660                 obj.lists.main.sitem_retrieve_params = {};
661             } else {
662                 obj.lists.main.sitem_retrieve_params = {'date_received' : {'!=' : null}}; // unit set dynamically in 'retrieve'
663             }
664             obj.lists.main.sitem_extra_params ={'order_by' : {'sitem' : 'date_expected ASC, stream ASC'}};
665
666             obj.lists.workarea.sitem_retrieve_params = {}; // unit set dynamically in 'retrieve'
667             obj.lists.workarea.sitem_extra_params ={'order_by' : {'sitem' : 'date_received DESC'}};
668
669             // default to **NEW UNIT**
670             // For now, keep the unit static.  TODO: Eventually, keep track of and store the last used unit value for both receive and bind separately
671             // obj.set_sunit(-2, 'New Unit', '', '');
672         }
673     },
674
675         'save_settings' : function() {
676                 var obj = this;
677
678         JSAN.use('util.file'); var file = new util.file('serial_items_prefs.'+obj.data.server_unadorned);
679         util.widgets.save_attributes(file, { 'serial_item_lib_menu' : [ 'value' ], 'mode_receive' : [ 'selected' ], 'mode_bind' : [ 'selected' ], 'serial_manage_items_show_all' : [ 'checked' ] });
680     },
681
682         'init_lists' : function() {
683                 var obj = this;
684
685                 JSAN.use('circ.util');
686         var columns = item_columns({});
687
688         function retrieve_row(params) {
689                         try { 
690                                 var row = params.row;
691                 obj.network.simple_request(
692                     'FM_SITEM_FLESHED_BATCH_RETRIEVE.authoritative',
693                     [[row.my.sitem_id]],
694                     //[ ses(), row.my.sitem_id, {"flesh":2,"flesh_fields":{"sitem":["creator","editor","issuance","stream","unit","notes"], "sunit":["call_number"], "sstr":["distribution"]}}],
695                     function(req) {
696                         try {
697                             var robj = req.getResultObject();
698                             if (typeof robj.ilsevent != 'undefined') throw(robj);
699                             if (typeof robj.ilsevent == 'null') throw('null result');
700                             var sitem = robj[0];
701                             obj.list_sitem_map[sitem.id()] = sitem;
702                             row.my.sitem = sitem;
703                             //params.row_node.setAttribute( 'retrieve_id', js2JSON({'copy_id':copy_id,'circ_id':row.my.circ.id(),'barcode':row.my.acp.barcode(),'doc_id': ( row.my.record ? row.my.record.id() : null ) }) );
704                             params.row_node.setAttribute( 'retrieve_id', js2JSON({'sitem_id':sitem.id()}) );
705                             dump('dumping... ' + js2JSON(obj.list_sitem_map[sitem.id()]));
706                             if (typeof params.on_retrieve == 'function') {
707                                 params.on_retrieve(row);
708                             }
709
710                         } catch(E) {
711                             obj.error.standard_unexpected_error_alert('staff.serial.manage_items.retrieve_row.callback_error', E);
712                         }
713                     }
714                 );
715                                 return row;
716                         } catch(E) {
717                                 obj.error.standard_unexpected_error_alert('staff.serial.manage_items.retrieve_row.error_in_retrieve_row',E);
718                                 return params.row;
719                         }
720                 }
721
722                 JSAN.use('util.list');
723
724         obj.lists = {};
725         obj.lists.main = new util.list('item_tree');
726                 obj.lists.main.init(
727                         {
728                                 'columns' : columns,
729                                 'map_row_to_columns' : circ.util.std_map_row_to_columns(),
730                                 'retrieve_row' : retrieve_row,
731                                 'on_select' : function(ev) {
732                     obj.selected_list = 'main';
733                                         JSAN.use('util.functional');
734                                         var sel = obj.lists.main.retrieve_selection();
735                                         obj.controller.view.sel_clip.setAttribute('disabled',sel.length < 1);
736                                         var list = util.functional.map_list(
737                                                 sel,
738                                                 function(o) { return JSON2js( o.getAttribute('retrieve_id') ); }
739                                         );
740                                         if (typeof obj.on_select == 'function') {
741                                                 obj.on_select(list);
742                                         }
743                                         if (typeof window.xulG == 'object' && typeof window.xulG.on_select == 'function') {
744                                                 obj.error.sdump('D_CAT','manage_items: Calling external .on_select()\n');
745                                                 window.xulG.on_select(list);
746                                         }
747                                 }
748                         }
749                 );
750
751         obj.lists.workarea = new util.list('workarea_tree');
752                 obj.lists.workarea.init(
753                         {
754                                 'columns' : columns,
755                                 'map_row_to_columns' : circ.util.std_map_row_to_columns(),
756                                 'retrieve_row' : retrieve_row,
757                                 'on_select' : function(ev) {
758                     obj.selected_list = 'workarea';
759                                         JSAN.use('util.functional');
760                                         var sel = obj.lists.workarea.retrieve_selection();
761                                         obj.controller.view.sel_clip.setAttribute('disabled',sel.length < 1);
762                                         var list = util.functional.map_list(
763                                                 sel,
764                                                 function(o) { return JSON2js( o.getAttribute('retrieve_id') ); }
765                                         );
766                                         if (typeof obj.on_select == 'function') {
767                                                 obj.on_select(list);
768                                         }
769                                         if (typeof window.xulG == 'object' && typeof window.xulG.on_select == 'function') {
770                                                 obj.error.sdump('D_CAT','serctrl: Calling external .on_select()\n');
771                                                 window.xulG.on_select(list);
772                                         } else {
773                                                 obj.error.sdump('D_CAT','serctrl: No external .on_select()\n');
774                                         }
775                                 }
776                         }
777                 );
778     },
779
780         'refresh_list' : function(list_name) {
781         var obj = this;
782
783         //TODO Optimize this?
784         obj.retrieve(list_name);
785     },
786
787         'retrieve' : function(list_name) {
788                 var obj = this;
789         var list = obj.lists[list_name];
790         
791                 list.clear();
792
793         if (!obj.sdist_ids.length) { // no sdists to retrieve items for
794             return;
795         }
796
797         var rparams = list.sitem_retrieve_params;
798         var robj;
799         rparams['+sstr'] = { "distribution" : obj.sdist_ids };
800
801         if (obj.mode == 'bind') {
802             if (list_name == 'workarea') {
803                 rparams['unit'] = obj.current_sunit_id;
804             } else if (!$('serial_manage_items_show_all').checked){
805                 rparams['unit'] = {"<>" : obj.current_sunit_id};
806             }
807         }
808
809         var other_params = list.sitem_extra_params;
810         other_params.join = 'sstr';
811
812         robj = obj.network.simple_request(
813             'FM_SITEM_ID_LIST',
814             [ ses(), rparams, other_params ]
815         );
816         if (!robj) {
817             robj = [];
818         } else if (typeof robj.ilsevent!='undefined') {
819             obj.error.standard_unexpected_error_alert('Failed to retrieve serial item ID list',E);
820         } else if (!robj.length) {
821             robj = [robj];
822         }
823
824         for (i = 0; i < robj.length; i++) {
825             list.append( { 'row' : { 'my' : { 'sitem_id' : robj[i] } }, 'to_bottom' : true, 'no_auto_select' : true } );
826         }
827         },
828
829         'on_select' : function(list) {
830
831                 dump('manage_items.on_select list = ' + js2JSON(list) + '\n');
832
833                 var obj = this;
834
835                 /*obj.controller.view.cmd_items_claimed_returned.setAttribute('disabled','false');
836                 obj.controller.view.sel_mark_items_missing.setAttribute('disabled','false');*/
837
838                 obj.retrieve_ids = list;
839         }
840 }
841
842 function item_columns(modify,params) {
843
844     JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
845     //JSAN.use('util.network'); var network = new util.network();
846
847     var c = [
848         {
849             'id' : 'sitem_id',
850             'label' : 'Item ID',
851             'flex' : 1,
852             'primary' : false,
853             'hidden' : false,
854             'render' : function(my) { return my.sitem.id(); },
855             'persist' : 'hidden width ordinal'
856         },
857         {
858             'id' : 'label',
859             'label' : 'Issuance Label',
860             'flex' : 1,
861             'primary' : false,
862             'hidden' : false,
863             'render' : function(my) { return my.sitem.issuance().label(); },
864             'persist' : 'hidden width ordinal'
865         },
866         {
867             'id' : 'distribution',
868             'label' : 'Distribution',
869             'flex' : 1,
870             'primary' : false,
871             'hidden' : false,
872             'persist' : 'hidden width ordinal',
873             'render' : function(my) { return my.sitem.stream().distribution().label(); }
874         },
875         {
876             'id' : 'stream_id',
877             'label' : 'Stream ID',
878             'flex' : 1,
879             'primary' : false,
880             'hidden' : false,
881             'persist' : 'hidden width ordinal',
882             'render' : function(my) { return my.sitem.stream().id(); }
883         },
884         {
885             'id' : 'date_published',
886             'label' : 'Date Published',
887             'flex' : 1,
888             'primary' : false,
889             'hidden' : false,
890             'render' : function(my) { return my.sitem.issuance().date_published().substr(0,10); },
891             'persist' : 'hidden width ordinal'
892         },
893         {
894             'id' : 'date_expected',
895             'label' : 'Date Expected',
896             'flex' : 1,
897             'primary' : false,
898             'hidden' : false,
899             'render' : function(my) { return my.sitem.date_expected().substr(0,10); },
900             'persist' : 'hidden width ordinal'
901         },
902         {
903             'id' : 'date_received',
904             'label' : 'Date Received',
905             'flex' : 1,
906             'primary' : false,
907             'hidden' : false,
908             'render' : function(my) { return my.sitem.date_received().substr(0,10); },
909             'persist' : 'hidden width ordinal'
910         },
911         {
912             'id' : 'notes',
913             'label' : 'Notes',
914             'flex' : 1,
915             'primary' : false,
916             'hidden' : false,
917             'render' : function(my) { return my.sitem.notes().length; },
918             'persist' : 'hidden width ordinal'
919         },
920         {
921             'id' : 'call_number',
922             'label' : 'Call Number',
923             'flex' : 1,
924             'primary' : false,
925             'hidden' : false,
926             'persist' : 'hidden width ordinal',
927             'render' : function(my) { return my.sitem.unit().call_number().label(); }
928         },
929         {
930             'id' : 'unit_id_contents',
931             'label' : 'Unit ID / Contents',
932             'flex' : 1,
933             'primary' : false,
934             'hidden' : false,
935             'render' : function(my) { return '[' + my.sitem.unit().id() + '] ' + my.sitem.unit().summary_contents() ; },
936             'persist' : 'hidden width ordinal'
937         },
938         {
939             'id' : 'creator',
940             'label' : 'Creator',
941             'flex' : 1,
942             'primary' : false,
943             'hidden' : true,
944             'persist' : 'hidden width ordinal',
945             'render' : function(my) { return my.sitem.creator().usrname(); }
946         },
947         {
948             'id' : 'create_date',
949             'label' : document.getElementById('circStrings').getString('staff.circ.utils.create_date'),
950             'flex' : 1,
951             'primary' : false,
952             'hidden' : true,
953             'persist' : 'hidden width ordinal',
954             'render' : function(my) { return my.sitem.create_date().substr(0,10); }
955         },
956         {
957             'id' : 'editor',
958             'label' : 'Editor',
959             'flex' : 1,
960             'primary' : false,
961             'hidden' : true,
962             'persist' : 'hidden width ordinal',
963             'render' : function(my) { return my.sitem.editor().usrname(); }
964         },
965         {
966             'id' : 'edit_date',
967             'label' : document.getElementById('circStrings').getString('staff.circ.utils.edit_date'),
968             'flex' : 1,
969             'primary' : false,
970             'hidden' : false,
971             'persist' : 'hidden width ordinal',
972             'render' : function(my) { return my.sitem.edit_date().substr(0,10); }
973         },
974         {
975             'id' : 'holding_code',
976             'label' : 'Holding Code',
977             'flex' : 1,
978             'primary' : false,
979             'hidden' : true,
980             'render' : function(my) { return my.sitem.issuance().holding_code(); },
981             'persist' : 'hidden width ordinal'
982         },
983         {
984             'id' : 'holding_type',
985             'label' : 'Holding Type',
986             'flex' : 1,
987             'primary' : false,
988             'hidden' : true,
989             'render' : function(my) { return my.sitem.issuance().holding_type(); },
990             'persist' : 'hidden width ordinal'
991         },
992         {
993             'id' : 'holding_link_id',
994             'label' : 'Holding Link ID',
995             'flex' : 1,
996             'primary' : false,
997             'hidden' : true,
998             'render' : function(my) { return my.sitem.issuance().holding_link_id(); },
999             'persist' : 'hidden width ordinal'
1000         }
1001     ];
1002     for (var i = 0; i < c.length; i++) {
1003         if (modify[ c[i].id ]) {
1004             for (var j in modify[ c[i].id ]) {
1005                 c[i][j] = modify[ c[i].id ][j];
1006             }
1007         }
1008     }
1009     if (params) {
1010         if (params.just_these) {
1011             JSAN.use('util.functional');
1012             var new_c = [];
1013             for (var i = 0; i < params.just_these.length; i++) {
1014                 var x = util.functional.find_list(c,function(d){return(d.id==params.just_these[i]);});
1015                 new_c.push( function(y){ return y; }( x ) );
1016             }
1017             c = new_c;
1018         }
1019         if (params.except_these) {
1020             JSAN.use('util.functional');
1021             var new_c = [];
1022             for (var i = 0; i < c.length; i++) {
1023                 var x = util.functional.find_list(params.except_these,function(d){return(d==c[i].id);});
1024                 if (!x) new_c.push(c[i]);
1025             }
1026             c = new_c;
1027         }
1028     }
1029     //return c.sort( function(a,b) { if (a.label < b.label) return -1; if (a.label > b.label) return 1; return 0; } );
1030     return c;
1031 };
1032
1033 spawn_sitem_editor = function(params) {
1034     try {
1035         if (!params.sitem_ids && !params.sitems) return;
1036         if (params.sitem_ids && params.sitem_ids.length == 0) return;
1037         if (params.sitems && params.sitems.length == 0) return;
1038         if (params.sitem_ids) params.sitem_ids = js2JSON(params.sitem_ids); // legacy
1039         if (!params.caller_handles_update) params.handle_update = 1; // legacy
1040
1041         var obj = {};
1042         JSAN.use('util.network'); obj.network = new util.network();
1043         JSAN.use('util.error'); obj.error = new util.error();
1044
1045         var title = '';
1046         if (params.sitem_ids && params.sitem_ids.length > 1 && params.do_edit == 1)
1047             title = 'Batch Edit Items';
1048         else /* if(params.sitems && params.sitems.length > 1 && params.do_edit == 1)
1049             title = 'Batch View Items';
1050         else if(params.sitem_ids && params.sitem_ids.length == 1) */
1051             title = 'Edit Item';/*
1052         else
1053             title = 'View Item';*/
1054
1055         JSAN.use('util.window'); var win = new util.window();
1056         params.in_modal = true;
1057         var my_xulG = win.open(
1058             (urls.XUL_SERIAL_ITEM_EDITOR),
1059             title,
1060             'chrome,modal,resizable',
1061             params
1062         );
1063         if (my_xulG.sitems && params.do_edit) {
1064             return my_xulG.sitems;
1065         } else {
1066             return [];
1067         }
1068     } catch(E) {
1069         JSAN.use('util.error'); var error = new util.error();
1070         error.standard_unexpected_error_alert('error in spawn_sitem_editor',E);
1071     }
1072 }
1073
1074 dump('exiting manage_items.js\n');