]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/xul/staff_client/server/serial/manage_items.js
696d819fb06c0cb907780dead3a5c00afc3de0d9
[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     'sdist_map' : {},
21     'ssub_map' : {},
22     'row_map' : {},
23
24     'retrieve_ssubs_and_sdists' : function () {
25                 var obj = this;
26
27         try {
28             obj.lib = $('serial_item_lib_menu').value;
29             var sdist_retrieve_params = {"+ssub":{"record_entry" : obj.docid}};
30             if (obj.mode == 'receive') {
31                 sdist_retrieve_params["+ssub"].owning_lib = obj.lib;
32             } else {
33                 sdist_retrieve_params.holding_lib = obj.lib;
34             }
35             var robj = obj.network.request(
36                 'open-ils.pcrud',
37                 'open-ils.pcrud.id_list.sdist',
38                 [ ses(), sdist_retrieve_params, {"join":"ssub"} ]
39             );
40             if (robj != null) {
41                 if (typeof robj.ilsevent != 'undefined') throw(robj);
42                 obj.sdist_ids = robj.length ? robj : [robj];
43                 // now get actual sdist and ssub objects
44                 robj = obj.network.simple_request(
45                     'FM_SDIST_FLESHED_BATCH_RETRIEVE.authoritative',
46                     [ obj.sdist_ids ]
47                 );
48                 if (robj != null) {
49                     if (typeof robj.ilsevent != 'undefined') throw(robj);
50                     robj = robj.length ? robj : [robj];
51                     for (var i = 0; i < robj.length; i++) {
52                         obj.sdist_map[robj[i].id()] = robj[i];
53                     }
54                 }
55                 robj = obj.network.request(
56                     'open-ils.pcrud',
57                     'open-ils.pcrud.id_list.ssub',
58                     [ ses(), {"+sdist" : {"id" : obj.sdist_ids}}, {"join":"sdist"} ]
59                 );
60                 var ssub_ids = robj.length ? robj : [robj];
61                 robj = obj.network.simple_request(
62                     'FM_SSUB_FLESHED_BATCH_RETRIEVE.authoritative',
63                     [ ssub_ids ]
64                 );
65                 if (robj != null) {
66                     if (typeof robj.ilsevent != 'undefined') throw(robj);
67                     robj = robj.length ? robj : [robj];
68                     for (var i = 0; i < robj.length; i++) {
69                         obj.ssub_map[robj[i].id()] = robj[i];
70                     }
71                 }
72             } else {
73                 obj.sdist_ids = [];
74             }
75
76         } catch(E) {
77             obj.error.standard_unexpected_error_alert('retrieve_ssubs_and_sdists failed!',E);
78         }
79     },
80
81     'build_menus' : function () {
82                 var obj = this;
83
84         // draw library drop-down
85         obj.org_ids = obj.network.simple_request('FM_SSUB_AOU_IDS_RETRIEVE_VIA_RECORD_ID.authoritative',[ obj.docid ]);
86         if (typeof obj.org_ids.ilsevent != 'undefined') throw(obj.org_ids);
87         JSAN.use('util.functional');
88         obj.org_ids = util.functional.map_list( obj.org_ids, function (o) { return Number(o); });
89
90         var org = obj.data.hash.aou[ obj.data.list.au[0].ws_ou() ];
91
92         JSAN.use('util.file'); JSAN.use('util.widgets');
93
94         var file; var list_data; var ml;
95
96         file = new util.file('offline_ou_list');
97         if (file._file.exists()) {
98             list_data = file.get_object(); file.close();
99             for (var i = 0; i < list_data[0].length; i++) { // make sure all entries are enabled
100                     list_data[0][i][2] = false;
101             }
102             ml = util.widgets.make_menulist( list_data[0], list_data[1] );
103             ml.setAttribute('id','serial_item_lib_menu'); document.getElementById('serial_item_lib_menu_box').appendChild(ml);
104             //TODO: class this menu properly
105             for (var i = 0; i < obj.org_ids.length; i++) {
106                 ml.getElementsByAttribute('value',obj.org_ids[i])[0].setAttribute('class','has_distributions');
107             }
108             /*TODO: add/enable this legend?
109             ml.firstChild.addEventListener(
110                 'popupshown',
111                 function(ev) {
112                     document.getElementById('legend').setAttribute('hidden','false');
113                 },
114                 false
115             );
116             ml.firstChild.addEventListener(
117                 'popuphidden',
118                 function(ev) {
119                     document.getElementById('legend').setAttribute('hidden','true');
120                 },
121                 false
122             );*/
123             ml.addEventListener(
124                 'command',
125                 function(ev) {
126                     //if (document.getElementById('serial_item_refresh_button')) document.getElementById('serial_item_refresh_button').focus();
127                     obj.save_settings();
128                     // get latest sdist id list based on library drowdown
129                     obj.retrieve_ssubs_and_sdists();
130                     obj.refresh_list('main');
131                     obj.refresh_list('workarea');
132                 },
133                 false
134             );
135
136         } else {
137             throw(document.getElementById('catStrings').getString('staff.cat.copy_browser.missing_library') + '\n');
138         }
139         file = new util.file('serial_items_prefs.'+obj.data.server_unadorned);
140         util.widgets.load_attributes(file);
141         ml.value = ml.getAttribute('value');
142         if (! ml.value) {
143             ml.value = org.id();
144             ml.setAttribute('value',ml.value);
145         }
146         
147         // deal with mode radio selectedIndex, as load_attributes is setting a "read-only" value
148         if ($('mode_receive').getAttribute('selected')) {
149             $('serial_manage_items_mode').selectedIndex = 0;
150         } else if ($('mode_advanced_receive').getAttribute('selected')) {
151             $('serial_manage_items_mode').selectedIndex = 1;
152         } else {
153             $('serial_manage_items_mode').selectedIndex = 2;
154         }
155
156         // setup recent sunits list
157         var recent_sunits_file = new util.file('serial_items_recent_sunits_'+obj.docid+'.'+obj.data.server_unadorned);
158         util.widgets.load_attributes(recent_sunits_file);
159         var recent_sunits_popup = $('serial_items_recent_sunits');
160         obj.sunit_entries = JSON2js(recent_sunits_popup.getAttribute('sunit_json'));
161         for (i = 0; i < obj.sunit_entries.length; i++) {
162             var sunit_info = obj.sunit_entries[i];
163             var new_menu_item = recent_sunits_popup.appendItem(sunit_info.label);
164             new_menu_item.setAttribute('id', 'serial_items_recent_sunits_entry_'+sunit_info.id);
165             new_menu_item.setAttribute('sunit_id', sunit_info.id);
166             new_menu_item.setAttribute('command', 'cmd_set_sunit');
167         }
168     },
169
170         'init' : function( params ) {
171                 var obj = this;
172
173                 obj.docid = params['docid'];
174
175         obj.build_menus();
176         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'));
177         //obj.retrieve_ssubs_and_sdists();
178                 obj.init_lists();
179
180         var mode_radio_group = $('serial_manage_items_mode');
181         obj.set_mode(mode_radio_group.selectedItem.id.substr(5));
182         mode_radio_group.addEventListener(
183             'command',
184             function(ev) {
185                 obj.save_settings();
186                 var mode = ev.target.id.substr(5); //strip out 'mode_'
187                 obj.set_mode(mode);
188                 obj.refresh_list('main');
189                 obj.refresh_list('workarea');
190             },
191             false
192         );
193         $('serial_manage_items_show_all').addEventListener(
194             'command',
195             function(ev) {
196                 obj.save_settings();
197                 obj.set_mode();
198                 obj.refresh_list('main');
199                 obj.refresh_list('workarea');
200             },
201             false
202         );
203
204         obj.set_alert_notes_button();
205
206                 JSAN.use('util.controller'); obj.controller = new util.controller();
207                 obj.controller.init(
208                         {
209                                 'control_map' : {
210                                         'save_columns' : [ [ 'command' ], function() { obj.lists.main.save_columns(); } ],
211                                         'cmd_broken' : [ ['command'], function() { alert('Not Yet Implemented'); } ],
212                                         'sel_clip' : [ ['command'], function() { obj.lists.main.clipboard(); } ],
213                     'cmd_add_item' : [
214                         ['command'],
215                         function() {
216                             try {
217                                 var new_item = new sitem();
218                                 new_item.issuance(new siss());
219                                 new_item.stream(1); //FIXME: hard-coded stream
220                                 new_item.issuance().subscription(1); //FIXME: hard-coded subscription
221                                 new_item.isnew(1);
222                                 new_item.issuance().isnew(1);
223                                 spawn_sitem_editor( {'sitems' : [new_item], 'do_edit' : 1 } );
224
225                                 obj.refresh_list('main');
226
227                             } catch(E) {
228                                 obj.error.standard_unexpected_error_alert(document.getElementById('catStrings').getString('staff.cat.copy_browser.edit_items.error'),E);
229                             }
230                         }
231                     ],
232                     'cmd_edit_items' : [
233                         ['command'],
234                         function() {
235                             try {
236                                 if (!obj.retrieve_ids || obj.retrieve_ids.length == 0) return;
237
238                                 JSAN.use('util.functional');
239                                 var list = util.functional.map_list(
240                                         obj.retrieve_ids,
241                                         function (o) {
242                                             return o.sitem_id;
243                                         }
244                                     );
245
246                                 spawn_sitem_editor( { 'sitem_ids' : list, 'do_edit' : 1 } );
247
248                                 obj.refresh_rows(list);
249
250                             } catch(E) {
251                                 obj.error.standard_unexpected_error_alert(document.getElementById('catStrings').getString('staff.cat.copy_browser.edit_items.error'),E);
252                             }
253                         }
254                     ],
255                     'cmd_reset_items' : [
256                         ['command'],
257                         function() {
258                             try {
259                                 if (!obj.retrieve_ids || obj.retrieve_ids.length == 0) return;
260
261                                 JSAN.use('util.functional');
262                                 var list = util.functional.map_list(
263                                         obj.retrieve_ids,
264                                         function (o) {
265                                             return o.sitem_id;
266                                         }
267                                     );
268
269                                 var robj = obj.network.request(
270                                             'open-ils.serial',
271                                             'open-ils.serial.reset_items',
272                                             [ ses(), list ]
273                                         );
274                                 if (typeof robj.ilsevent != 'undefined') throw(robj);
275
276                                 alert('Successfully reset '+robj.num_items+' item(s)');
277
278                                 obj.refresh_list('main');
279                                 obj.refresh_list('workarea');
280                             } catch(E) {
281                                 obj.error.standard_unexpected_error_alert('staff.serial.manage_items.reset_items.error',E);
282                             }
283                         }
284                     ],
285                     'cmd_claim_items' : [
286                         ['command'],
287                         function () { obj.set_items_special_status('Claimed','staff.serial.manage_items.set_claimed_success') }
288                     ],
289                     'cmd_set_items_not_published' : [
290                         ['command'],
291                         function () { obj.set_items_special_status('Not Published','staff.serial.manage_items.set_not_published_success') }
292                     ],
293                     'cmd_set_items_not_held' : [
294                         ['command'],
295                         function () { obj.set_items_special_status('Not Held','staff.serial.manage_items.set_not_held_success') }
296                     ],
297                     'cmd_delete_items' : [
298                         ['command'],
299                         function() {
300                             try {
301                                 JSAN.use('util.functional');
302                                 var list = util.functional.map_list(
303                                         obj.retrieve_ids,
304                                         function (o) {
305                                             return obj.list_sitem_map[o.sitem_id];
306                                         }
307                                     );
308                                 var delete_msg;
309                                 if (list.length != 1) {
310                                     delete_msg = document.getElementById('catStrings').getFormattedString('staff.cat.copy_browser.delete_items.confirm.plural', [list.length]);
311                                 } else {
312                                     delete_msg = document.getElementById('catStrings').getString('staff.cat.copy_browser.delete_items.confirm');
313                                 }
314                                 var r = obj.error.yns_alert(
315                                         delete_msg,
316                                         document.getElementById('catStrings').getString('staff.cat.copy_browser.delete_items.title'),
317                                         document.getElementById('catStrings').getString('staff.cat.copy_browser.delete_items.delete'),
318                                         document.getElementById('catStrings').getString('staff.cat.copy_browser.delete_items.cancel'),
319                                         null,
320                                         document.getElementById('commonStrings').getString('common.confirm')
321                                 );
322
323                                 if (r == 0) {
324                                     for (var i = 0; i < list.length; i++) {
325                                         list[i].isdeleted('1');
326                                     }
327                                     var robj = obj.network.request(
328                                             'open-ils.serial',
329                                             'open-ils.serial.item.fleshed.batch.update',
330                                         [ ses(), list ],
331                                         null,
332                                         {
333                                             'title' : document.getElementById('catStrings').getString('staff.cat.copy_browser.delete_items.override'),
334                                             'overridable_events' : [ // FIXME: replace or delete these events
335                                                 1208 /* TITLE_LAST_COPY */,
336                                                 1227 /* COPY_DELETE_WARNING */,
337                                             ]
338                                         }
339                                     );
340                                     if (robj == null) throw(robj);
341                                     if (typeof robj.ilsevent != 'undefined') {
342                                         if ( (robj.ilsevent != 0) && (robj.ilsevent != 1227 /* COPY_DELETE_WARNING */) && (robj.ilsevent != 1208 /* TITLE_LAST_COPY */) ) throw(robj);
343                                     }
344                                     obj.refresh_list(obj.selected_list);
345                                 }
346
347
348                             } catch(E) {
349                                 obj.error.standard_unexpected_error_alert('staff.serial.manage_items.delete_items.error',E);
350                                 obj.refresh_list();
351                             }
352                         }
353                     ],
354                     'cmd_set_sunit' : [
355                         ['command'],
356                         function(evt) {
357                             try {
358                                 var target = evt.explicitOriginalTarget;
359                                 obj.process_unit_selection(target);
360                             } catch(E) {
361                                 obj.error.standard_unexpected_error_alert('cmd_set_sunit failed!',E);
362                             }
363                         }
364                     ],
365                     'cmd_set_other_sunit' : [
366                         ['command'],
367                         function() {
368                             obj.set_other_sunit();
369                             if (obj.mode == 'bind') {
370                                 obj.refresh_list('main');
371                                 obj.refresh_list('workarea');
372                             }
373                         }
374                     ],
375                     'cmd_predict_items' : [
376                         ['command'],
377                         function() {
378                             alert('Subscription selection needed here'); //FIXME: make this prompt, or discard this feature
379                         }
380                     ],
381                     'cmd_read_alerts' : [
382                         ['command'],
383                         function() {
384                             try {
385                                 obj.view_alert_notes();
386                             } catch(E) {
387                                 obj.error.standard_unexpected_error_alert('cmd_read_alerts failed!',E);
388                             }
389                         }
390                     ],
391                     'cmd_receive_items' : [
392                         ['command'],
393                         function() {
394                             try {
395                                 JSAN.use('util.functional');
396                                 var donor_unit_ids = {};
397                                 var list = util.functional.map_list(
398                                         obj.retrieve_ids,
399                                         function (o) {
400                                             var item = obj.list_sitem_map[o.sitem_id];
401                                             if (item.unit()) {
402                                                 donor_unit_ids[item.unit().id()] = 1;
403                                             }
404                                             item.unit(obj.current_sunit_id);
405                                             return item;
406                                         }
407                                     );
408
409                                 var mode = obj.mode;
410                                 if (mode == 'advanced_receive') mode = 'receive';
411
412                                 var method; var success_label;
413                                 if (mode == 'receive') {
414                                     method = 'open-ils.serial.receive_items';
415                                     success_label = 'received';
416                                 } else { // bind mode
417                                     method = 'open-ils.serial.bind_items';
418                                     success_label = 'bound';
419                                 } 
420
421                                 // deal with barcodes and call numbers for *NEW* units
422                                 var barcodes = {};
423                                 var call_numbers = {};
424                                 var call_numbers_by_siss_and_sdist = {};
425
426                                 if (obj.current_sunit_id < 0) { // **AUTO** or **NEW** units
427                                     var new_unit_barcode = '';
428                                     var new_unit_call_number = '';
429                                     for (var i = 0; i < list.length; i++) {
430                                         var item = list[i];
431                                         if (new_unit_barcode) {
432                                             barcodes[item.id()] = new_unit_barcode;
433                                             call_numbers[item.id()] = new_unit_call_number;
434                                             continue;
435                                         }
436                                         var prompt_text;
437                                         if (obj.current_sunit_id == -1) {
438                                             prompt_text = 'for '+item.issuance().label()+ ' from Distribution: '+obj.sdist_map[item.stream().distribution()].label()+'/'+item.stream().id()+':';
439                                         } else { // must be -2
440                                             prompt_text = 'for the new unit:';
441                                         }
442
443                                         // first barcodes
444                                         var barcode = window.prompt('Please enter a barcode ' + prompt_text,
445                                             '@@AUTO',
446                                             'Unit Barcode Prompt');
447                                         barcode = String( barcode ).replace(/\s/g,'');
448                                         /* Casting a possibly null input value to a String turns it into "null" */
449                                         if (!barcode || barcode == 'null') {
450                                             alert('Invalid barcode entered, defaulting to system-generated.');
451                                             barcode = '@@AUTO';
452                                         } else {
453                                             // disable alarm sound temporarily
454                                             var sound_setting = obj.data.no_sound;
455                                             if (!sound_setting) { // undefined or false
456                                                 obj.data.no_sound = true; obj.data.stash('no_sound');
457                                             }
458                                             var test = obj.network.simple_request('FM_ACP_RETRIEVE_VIA_BARCODE',[ barcode ]);
459                                             if (typeof test.ilsevent == 'undefined') {
460                                                 alert('Another copy has barcode "' + barcode + '", defaulting to system-generated.');
461                                                 barcode = '@@AUTO';
462                                             }
463                                             if (!sound_setting) {
464                                                 obj.data.no_sound = sound_setting; obj.data.stash('no_sound');
465                                             }
466                                         }
467                                         barcodes[item.id()] = barcode;
468
469                                         // now call numbers
470                                         if (typeof call_numbers_by_siss_and_sdist[item.issuance().id() + '@' + item.stream().distribution()] == 'undefined') {
471                                             var default_cn = 'DEFAULT';
472                                             // if they defined a *_call_number, honor it as the default
473                                             var preset_cn = obj.sdist_map[item.stream().distribution()][mode + '_call_number']();
474                                             if (preset_cn) {
475                                                 default_cn = preset_cn.label();
476                                             } else {
477                                                 // for now, let's default to the last created call number if there is one
478                                                 var acn_list = obj.network.request(
479                                                         'open-ils.pcrud',
480                                                         'open-ils.pcrud.search.acn',
481                                                         [ ses(), {"record" : obj.docid, "owning_lib" : obj.sdist_map[item.stream().distribution()].holding_lib().id(), "deleted" : 'f' }, {"order_by" : {"acn" : "create_date DESC"}, "limit" : "1" } ]
482                                                 );
483
484                                                 if (acn_list) {
485                                                     default_cn = acn_list.label();
486                                                 }
487                                             }
488                                             var call_number = window.prompt('Please enter/adjust a call number ' + prompt_text,
489                                                 default_cn, //TODO: real default by setting
490                                                 'Unit Call Number Prompt');
491                                             call_number = String( call_number ).replace(/^\s+/,'').replace(/\s$/,'');
492                                             /* Casting a possibly null input value to a String turns it into "null" */
493                                             if (!call_number || call_number == 'null') {
494                                                 alert('Invalid call number entered, setting to "DEFAULT".');
495                                                 call_number = 'DEFAULT'; //TODO: real default by setting
496                                             }
497                                             call_numbers[item.id()] = call_number;
498                                             call_numbers_by_siss_and_sdist[item.issuance().id() + '@' + item.stream().distribution()] = call_number;
499                                         } else {
500                                             // we have already seen this same issuance and distribution combo, so use the same call number
501                                             call_numbers[item.id()] = call_numbers_by_siss_and_sdist[item.issuance().id() + '@' + item.stream().distribution()];
502                                         }
503
504                                         if (obj.current_sunit_id == -2) {
505                                             new_unit_barcode = barcode;
506                                             new_unit_call_number = call_number;
507                                         }
508                                     }
509                                 }
510
511                                 var robj = obj.network.request(
512                                             'open-ils.serial',
513                                             method,
514                                             [ ses(), list, barcodes, call_numbers, donor_unit_ids ]
515                                         );
516                                 if (typeof robj.ilsevent != 'undefined') throw(robj); //TODO: catch for override
517
518                                 alert('Successfully '+success_label+' '+robj.num_items+' item(s)');
519
520                                 if (obj.current_sunit_id == -2) {
521                                     obj.current_sunit_id = robj.new_unit_id;
522                                 }
523
524                                 obj.rebuild_current_sunit(obj.sdist_map[list[0].stream().distribution()].label(), list[0].stream().distribution(), list[0].stream().id());
525                                 obj.refresh_list('main');
526                                 obj.refresh_list('workarea');
527                                 
528                             } catch(E) {
529                                 obj.error.standard_unexpected_error_alert('cmd_receive_items failed!',E);
530                             }
531                         }
532                     ],
533                     'cmd_edit_sunit' : [
534                         ['command'],
535                         function() {
536                             try {
537                                 /*if (!obj.retrieve_ids || obj.retrieve_ids.length == 0) return;
538
539                                 JSAN.use('util.functional');
540                                 var list = util.functional.map_list(
541                                         obj.retrieve_ids,
542                                         function (o) {
543                                             return o.sitem_id;
544                                         }
545                                     );
546 */
547                                 spawn_sunit_editor( { 'sunit_ids' : [1], 'edit' : 1 } ); //FIXME: hard-coded sunit
548
549                             } catch(E) {
550                                 obj.error.standard_unexpected_error_alert('cmd_edit_sunit failed!',E);
551                             }
552                         }
553                     ],
554                     'cmd_view_sitem_notes' : [
555                         ['command'],
556                         function() {
557                             try {
558                                 obj.view_notes('sitem');
559                             } catch(E) {
560                                 obj.error.standard_unexpected_error_alert('cmd_view_sitem_notes failed!',E);
561                             }
562                         }
563                     ],
564                     'cmd_view_sdist_notes' : [
565                         ['command'],
566                         function() {
567                             try {
568                                 obj.view_notes('sdist');
569                             } catch(E) {
570                                 obj.error.standard_unexpected_error_alert('cmd_view_sdist_notes failed!',E);
571                             }
572                         }
573                     ],
574                     'cmd_view_ssub_notes' : [
575                         ['command'],
576                         function() {
577                             try {
578                                 obj.view_notes('ssub');
579                             } catch(E) {
580                                 obj.error.standard_unexpected_error_alert('cmd_view_ssub_notes failed!',E);
581                             }
582                         }
583                     ],
584                     'cmd_items_print' : [ ['command'], function() { obj.items_print(obj.selected_list); } ],
585                                         'cmd_items_export' : [ ['command'], function() { obj.items_export(obj.selected_list); } ],
586                                         'cmd_refresh_list' : [ ['command'], function() { obj.refresh_all(); } ]
587                                 }
588                         }
589                 );
590         
591                 obj.retrieve('main'); // retrieve main list
592         obj.retrieve('workarea'); // retrieve shelving unit list
593
594                 obj.controller.view.sel_clip.setAttribute('disabled','true');
595
596         },
597
598         'items_print' : function(which) {
599                 var obj = this;
600                 try {
601                         var list = obj.lists[which];
602 /* FIXME: serial items print template?                  JSAN.use('patron.util');
603                         var params = { 
604                                 'patron' : patron.util.retrieve_fleshed_au_via_id(ses(),obj.patron_id), 
605                                 'template' : 'items_out'
606                         }; */
607                         list.print( params );
608                 } catch(E) {
609                         obj.error.standard_unexpected_error_alert('manage_items printing',E);
610                 }
611         },
612
613         'items_export' : function(which) {
614                 var obj = this;
615                 try {
616                         var list = obj.lists[which];
617                         list.dump_csv_to_clipboard();
618                 } catch(E) {
619                         obj.error.standard_unexpected_error_alert('manage_items export',E);
620                 }
621         },
622
623         'rebuild_current_sunit' : function(sdist_label, sdist_id, sstr_id) {
624                 var obj = this;
625         if (!obj.current_sunit_id) return; // current sunit is NONE
626                 try {
627             var robj = obj.network.request(
628                 'open-ils.pcrud',
629                 'open-ils.pcrud.retrieve.sunit',
630                 [ ses(),  obj.current_sunit_id]
631             );
632             if (!robj) return; // current sunit is NEW or AUTO
633
634             var label = '[' + sdist_label + '/' + sstr_id + ' #' + obj.current_sunit_id + '] ' + robj.summary_contents();
635             obj.set_sunit(obj.current_sunit_id, label, sdist_id, sstr_id);
636             obj.save_sunit(obj.current_sunit_id, label, sdist_id, sstr_id);
637                 } catch(E) {
638                         obj.error.standard_unexpected_error_alert('serial items set_sunit',E);
639                 }
640         },
641
642         'set_sunit' : function(sunit_id, label, sdist_id, sstr_id) {
643                 var obj = this;
644                 try {
645             obj.current_sunit_id = sunit_id;
646             obj.current_sunit_sdist_id = sdist_id;
647             obj.current_sunit_sstr_id = sstr_id;
648             if (sunit_id < 0  || sunit_id === '') {
649                 $('serial_workarea_sunit_desc').firstChild.nodeValue = '**' + label + '**';
650             } else {
651                 $('serial_workarea_sunit_desc').firstChild.nodeValue = label;
652                 obj.add_sunit_to_menu(sunit_id, label, sdist_id, sstr_id);
653             }
654                 } catch(E) {
655                         obj.error.standard_unexpected_error_alert('serial items set_sunit',E);
656                 }
657         },
658
659         'save_sunit' : function(sunit_id, label, sdist_id, sstr_id) {
660                 var obj = this;
661                 try {
662             $('serial_items_current_sunit').setAttribute('sunit_id', sunit_id);
663             $('serial_items_current_sunit').setAttribute('sunit_label', label);
664             if (sunit_id > 0) {
665                 $('serial_items_current_sunit').setAttribute('sdist_id', sdist_id);
666                 $('serial_items_current_sunit').setAttribute('sstr_id', sstr_id);
667             }
668             var recent_sunits_file = new util.file('serial_items_recent_sunits_'+obj.docid+'.'+obj.data.server_unadorned);
669             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' ] });
670                 } catch(E) {
671                         obj.error.standard_unexpected_error_alert('serial items save_sunit',E);
672                 }
673         },
674
675         'set_other_sunit' : function() {
676                 var obj = this;
677                 try {
678             JSAN.use('util.window'); var win = new util.window();
679             var select_unit_window = win.open(
680                 xulG.url_prefix('XUL_SERIAL_SELECT_UNIT'),
681                 '_blank',
682                 'chrome,resizable,modal,centerscreen',
683                 {'sdist_ids' : obj.sdist_ids}
684             );
685             if (!select_unit_window.sunit_selection) {
686                 return;
687             }
688
689             var selection = select_unit_window.sunit_selection;
690             var sunit_id = selection.sunit;
691             var sdist_id = selection.sdist;
692             var sstr_id = selection.sstr;
693             var label = selection.label;
694
695             obj.set_sunit(sunit_id, label, sdist_id, sstr_id);
696             obj.save_sunit(sunit_id, label, sdist_id, sstr_id);
697                 } catch(E) {
698                         obj.error.standard_unexpected_error_alert('serial items set_other_sunit',E);
699                 }
700         },
701
702         'add_sunit_to_menu' : function(sunit_id, label, sdist_id, sstr_id) {
703                 var obj = this;
704                 try {
705             if (sunit_id > 0) {
706                 // check if it is already in sunit_entries, remove it
707                 for (i = 0; i < obj.sunit_entries.length; i++) {
708                     if (obj.sunit_entries[i].id == sunit_id) {
709                         obj.sunit_entries.splice(i,1);
710                         var menu_item = $('serial_items_recent_sunits_entry_'+sunit_id);
711                         menu_item.parentNode.removeChild(menu_item);
712                         i--;
713                     }
714                 }
715                 // add to front of array
716                 obj.sunit_entries.unshift({"id" : sunit_id, "label" : label, "sdist_id" : sdist_id, "sstr_id" : sstr_id});
717                 var recent_sunits_popup = $('serial_items_recent_sunits');
718                 var new_menu_item = recent_sunits_popup.insertItemAt(0,label);
719                 new_menu_item.setAttribute('id', 'serial_items_recent_sunits_entry_'+sunit_id);
720                 new_menu_item.setAttribute('sunit_id', sunit_id);
721                 new_menu_item.setAttribute('sdist_id', sdist_id);
722                 new_menu_item.setAttribute('sstr_id', sstr_id);
723                 new_menu_item.setAttribute('command', 'cmd_set_sunit');
724
725                 // pop off from sunit_entries if it already has 10 sunits
726                 if (obj.sunit_entries.length > 10) {
727                     var sunit_info = obj.sunit_entries.pop();
728                     var menu_item = $('serial_items_recent_sunits_entry_'+sunit_info.id);
729                     menu_item.parentNode.removeChild(menu_item);
730                 }
731
732                 recent_sunits_popup.setAttribute('sunit_json', js2JSON(obj.sunit_entries));
733             }
734                 } catch(E) {
735                         obj.error.standard_unexpected_error_alert('serial items add_sunit_to_menu',E);
736                 }
737         },
738
739         'set_mode' : function(mode) {
740                 var obj = this;
741
742         if (!mode) {
743             mode = obj.mode;
744         } else {
745             obj.mode = mode;
746         }
747
748         obj.retrieve_ssubs_and_sdists();
749
750         if (mode == 'receive' || mode == 'advanced_receive') {
751             $('serial_workarea_mode_label').value = 'Recently Received';
752             if ($('serial_manage_items_show_all').checked) {
753                 obj.lists.main.sitem_retrieve_params = {};
754             } else {
755                 obj.lists.main.sitem_retrieve_params = { 'date_received' : null, 'status' : {'not in' : ['Not Held', 'Not Published']} };
756             }
757             obj.lists.main.sitem_extra_params ={'order_by' : {'sitem' : 'date_expected ASC, stream ASC'}};
758
759             obj.lists.workarea.sitem_retrieve_params = {'date_received' : {"!=" : null}};
760             obj.lists.workarea.sitem_extra_params ={'order_by' : {'sitem' : 'date_received DESC'}, 'limit' : 30};
761             if (mode == 'receive') {
762                 $('serial_manage_items_context').value = $('serialStrings').getString('staff.serial.manage_items.subscriber.label') + ':';
763                 $('cmd_set_other_sunit').setAttribute('disabled','true');
764                 $('serial_items_recent_sunits').disabled = true;
765                 obj.process_unit_selection($('serial_items_auto_per_item_menuitem'));
766                 //obj.set_sunit(obj.current_sunit_id, label, sdist_id, sstr_id);
767             } else {
768                 $('serial_manage_items_context').value = $('serialStrings').getString('staff.serial.manage_items.holder.label') + ':';
769                 $('cmd_set_other_sunit').setAttribute('disabled','false');
770                 $('serial_items_recent_sunits').disabled = false;
771             }    
772         } else { // bind mode
773             $('serial_workarea_mode_label').value = 'Bound Items in Current Working Unit';
774             $('serial_manage_items_context').value = $('serialStrings').getString('staff.serial.manage_items.holder.label') + ':';
775             if ($('serial_manage_items_show_all').checked) {
776                 obj.lists.main.sitem_retrieve_params = {};
777             } else {
778                 obj.lists.main.sitem_retrieve_params = {'date_received' : {'!=' : null}}; // unit set dynamically in 'retrieve'
779             }
780             obj.lists.main.sitem_extra_params ={'order_by' : {'sitem' : 'date_expected ASC, stream ASC'}};
781
782             obj.lists.workarea.sitem_retrieve_params = {}; // unit set dynamically in 'retrieve'
783             obj.lists.workarea.sitem_extra_params ={'order_by' : {'sitem' : 'date_received DESC'}};
784
785             $('cmd_set_other_sunit').setAttribute('disabled','false');
786             $('serial_items_recent_sunits').disabled = false;
787             // default to **NEW UNIT**
788             // For now, keep the unit static.  TODO: Eventually, keep track of and store the last used unit value for both receive and bind separately
789             // obj.set_sunit(-2, 'New Unit', '', '');
790         }
791     },
792
793         'save_settings' : function() {
794                 var obj = this;
795
796         JSAN.use('util.file'); var file = new util.file('serial_items_prefs.'+obj.data.server_unadorned);
797         util.widgets.save_attributes(file, { 'serial_item_lib_menu' : [ 'value' ], 'mode_receive' : [ 'selected' ], 'mode_advanced_receive' : [ 'selected' ], 'mode_bind' : [ 'selected' ], 'serial_manage_items_show_all' : [ 'checked' ] });
798     },
799
800         'init_lists' : function() {
801                 var obj = this;
802
803                 JSAN.use('circ.util');
804         var columns = item_columns({});
805
806         function retrieve_row(params) {
807                         try { 
808                                 var row = params.row;
809                 obj.network.simple_request(
810                     'FM_SITEM_FLESHED_BATCH_RETRIEVE.authoritative',
811                     [[row.my.sitem_id]],
812                     //[ ses(), row.my.sitem_id, {"flesh":2,"flesh_fields":{"sitem":["creator","editor","issuance","stream","unit","notes"], "sunit":["call_number"], "sstr":["distribution"]}}],
813                     function(req) {
814                         try {
815                             var robj = req.getResultObject();
816                             if (typeof robj.ilsevent != 'undefined') throw(robj);
817                             if (typeof robj.ilsevent == 'null') throw('null result');
818                             var sitem = robj[0];
819                             obj.list_sitem_map[sitem.id()] = sitem;
820                             row.my.sitem = sitem;
821                             row.my.parent_obj = obj;
822                             //params.treeitem_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 ) }) );
823                             params.treeitem_node.setAttribute( 'retrieve_id', js2JSON({'sitem_id':sitem.id()}) );
824                             if (sitem.status() == 'Claimed') {
825                                 params.treeitem_node.firstChild.setAttribute( 'properties', 'makeItGray' );
826                             } else if (sitem.status() == 'Not Held' || sitem.status() == 'Not Published') {
827                                 var treecells = params.treeitem_node.firstChild.childNodes;
828                                 for (i = 0; i < treecells.length; i++) {
829                                     treecells[i].setAttribute( 'properties', 'crossItOut' );
830                                 }
831                             }
832                             dump('dumping... ' + js2JSON(obj.list_sitem_map[sitem.id()]));
833                             if (typeof params.on_retrieve == 'function') {
834                                 params.on_retrieve(row);
835                             }
836
837                         } catch(E) {
838                             obj.error.standard_unexpected_error_alert('staff.serial.manage_items.retrieve_row.callback_error', E);
839                         }
840                     }
841                 );
842                                 return row;
843                         } catch(E) {
844                                 obj.error.standard_unexpected_error_alert('staff.serial.manage_items.retrieve_row.error_in_retrieve_row',E);
845                                 return params.row;
846                         }
847                 }
848
849                 JSAN.use('util.list');
850
851         obj.lists = {};
852         obj.lists.main = new util.list('item_tree');
853                 obj.lists.main.init(
854                         {
855                                 'columns' : columns,
856                                 'retrieve_row' : retrieve_row,
857                                 'on_select' : function(ev) {
858                     obj.selected_list = 'main';
859                                         JSAN.use('util.functional');
860                                         var sel = obj.lists.main.retrieve_selection();
861                                         obj.controller.view.sel_clip.setAttribute('disabled',sel.length < 1);
862                                         var list = util.functional.map_list(
863                                                 sel,
864                                                 function(o) { return JSON2js( o.getAttribute('retrieve_id') ); }
865                                         );
866                                         if (typeof obj.on_select == 'function') {
867                                                 obj.on_select(list);
868                                         }
869                                         if (typeof window.xulG == 'object' && typeof window.xulG.on_select == 'function') {
870                                                 obj.error.sdump('D_CAT','manage_items: Calling external .on_select()\n');
871                                                 window.xulG.on_select(list);
872                                         }
873                                 }
874                         }
875                 );
876
877         obj.lists.workarea = new util.list('workarea_tree');
878                 obj.lists.workarea.init(
879                         {
880                                 'columns' : columns,
881                                 'retrieve_row' : retrieve_row,
882                                 'on_select' : function(ev) {
883                     obj.selected_list = 'workarea';
884                                         JSAN.use('util.functional');
885                                         var sel = obj.lists.workarea.retrieve_selection();
886                                         obj.controller.view.sel_clip.setAttribute('disabled',sel.length < 1);
887                                         var list = util.functional.map_list(
888                                                 sel,
889                                                 function(o) { return JSON2js( o.getAttribute('retrieve_id') ); }
890                                         );
891                                         if (typeof obj.on_select == 'function') {
892                                                 obj.on_select(list);
893                                         }
894                                         if (typeof window.xulG == 'object' && typeof window.xulG.on_select == 'function') {
895                                                 obj.error.sdump('D_CAT','serctrl: Calling external .on_select()\n');
896                                                 window.xulG.on_select(list);
897                                         } else {
898                                                 obj.error.sdump('D_CAT','serctrl: No external .on_select()\n');
899                                         }
900                                 }
901                         }
902                 );
903     },
904
905         'refresh_all' : function() {
906         var obj = this;
907
908         obj.retrieve_ssubs_and_sdists();
909         obj.refresh_list('main');
910         obj.refresh_list('workarea');
911     },
912
913     'refresh_list' : function(list_name) {
914         var obj = this;
915
916         //TODO Optimize this?
917         obj.retrieve(list_name);
918     },
919
920     // accepts a list of ids or a list of objects
921     'refresh_rows' : function(list) {
922         var obj = this;
923
924         var id_list;
925
926         if (typeof list[0] == 'object') {
927             id_list = util.functional.map_list(
928                 list,
929                 function(o) {
930                     return o.id()
931                 }
932             );
933         } else {
934             id_list = list;
935         }
936
937         for (var i = 0; i < id_list.length; i++) {
938             obj.lists[obj.selected_list].refresh_row(obj.row_map[id_list[i]]);
939         }
940     },
941
942         'retrieve' : function(list_name) {
943                 var obj = this;
944         var list = obj.lists[list_name];
945         
946                 list.clear();
947
948         if (!obj.sdist_ids.length) { // no sdists to retrieve items for
949             return;
950         }
951
952         var rparams = list.sitem_retrieve_params;
953         var robj;
954         rparams['+sstr'] = { "distribution" : obj.sdist_ids };
955
956         if (obj.mode == 'bind') {
957             if (list_name == 'workarea') {
958                 rparams['unit'] = obj.current_sunit_id;
959             } else if (!$('serial_manage_items_show_all').checked){
960                 rparams['unit'] = {"<>" : obj.current_sunit_id};
961             }
962         }
963
964         var other_params = list.sitem_extra_params;
965         other_params.join = 'sstr';
966
967         robj = obj.network.simple_request(
968             'FM_SITEM_ID_LIST',
969             [ ses(), rparams, other_params ]
970         );
971         if (!robj) {
972             robj = [];
973         } else if (typeof robj.ilsevent!='undefined') {
974             obj.error.standard_unexpected_error_alert('Failed to retrieve serial item ID list',E);
975         } else if (!robj.length) {
976             robj = [robj];
977         }
978
979         for (i = 0; i < robj.length; i++) {
980             var nparams = list.append( { 'row' : { 'my' : { 'sitem_id' : robj[i] } }, 'to_bottom' : true, 'no_auto_select' : true } );
981             obj.row_map[robj[i]] = nparams;
982         }
983         },
984
985         'on_select' : function(list) {
986
987                 dump('manage_items.on_select list = ' + js2JSON(list) + '\n');
988
989                 var obj = this;
990         obj.controller.view.cmd_claim_items.setAttribute('disabled','false');
991
992         for (var i = 0; i < list.length; i++) {
993             var item = obj.list_sitem_map[list[i].sitem_id];
994             if (item.status() != 'Expected') {
995                 obj.controller.view.cmd_claim_items.setAttribute('disabled','true');
996                 break;
997             }
998         }
999
1000                 /*obj.controller.view.cmd_items_claimed_returned.setAttribute('disabled','false');
1001                 obj.controller.view.sel_mark_items_missing.setAttribute('disabled','false');*/
1002
1003                 obj.retrieve_ids = list;
1004                 obj.set_alert_notes_button();
1005         },
1006
1007     'process_unit_selection' : function(menuitem) {
1008         var obj = this;
1009
1010         var label = menuitem.label;
1011         var sunit_id = menuitem.getAttribute('sunit_id');
1012         var sdist_id = menuitem.getAttribute('sdist_id');
1013         var sstr_id = menuitem.getAttribute('sstr_id');
1014         obj.set_sunit(sunit_id, label, sdist_id, sstr_id);
1015         obj.save_sunit(sunit_id, label, sdist_id, sstr_id);
1016         if (obj.mode == 'bind') {
1017             obj.refresh_list('main');
1018             obj.refresh_list('workarea');
1019         }
1020     },
1021
1022     'view_notes' : function(type) {
1023         var obj = this;
1024
1025         if (!obj.retrieve_ids || obj.retrieve_ids.length == 0) return;
1026
1027         var object_id_fn;
1028         var function_type;
1029         var object_type;
1030         var constructor;
1031
1032         switch(type) {
1033             case 'sitem':
1034                 object_id_fn = function(item) { return item.id() };
1035                 title_fn = function(item) { return fieldmapper.IDL.fmclasses.sitem.field_map.id.label + ' ' + item.id() };
1036                 function_type = 'SIN';
1037                 object_type = 'item';
1038                 constructor = sin;
1039                 break;
1040             case 'sdist':
1041                 object_id_fn = function(item) { return item.stream().distribution() };
1042                 title_fn = function(item) {
1043                     var sdist_id = object_id_fn(item);
1044                     return obj.sdist_map[sdist_id].label()
1045                         + ' -- ' + obj.sdist_map[sdist_id].holding_lib().shortname()
1046                         + ' (' + fieldmapper.IDL.fmclasses.sdist.field_map.id.label + ' ' + sdist_id + ')'
1047                 };
1048                 function_type = 'SDISTN';
1049                 object_type = 'distribution';
1050                 constructor = sdistn;
1051                 break;
1052             case 'ssub':
1053                 object_id_fn = function(item) { return item.issuance().subscription().id() };
1054                 title_fn = function(item) {
1055                     var ssub_id = object_id_fn(item);
1056                     return obj.ssub_map[ssub_id].owning_lib().shortname()
1057                         + ' (' + fieldmapper.IDL.fmclasses.ssub.field_map.id.label + ' ' + ssub_id + ')'
1058                 };
1059                 function_type = 'SSUBN';
1060                 object_type = 'subscription';
1061                 constructor = ssubn;
1062                 break;
1063             default:
1064                 return;
1065         }
1066
1067         var seen_ids = {};
1068         var notes_window;
1069         var sitem_ids = [];
1070         for (var i = 0; i < obj.retrieve_ids.length; i++) {
1071             var sitem_id = obj.retrieve_ids[i].sitem_id;
1072             var sitem = obj.list_sitem_map[sitem_id];
1073             sitem_ids.push(sitem_id);
1074             var obj_id = object_id_fn(sitem);
1075             if (seen_ids[obj_id]) continue;
1076             JSAN.use('util.window'); var win = new util.window();
1077             notes_window = win.open(
1078                 urls.XUL_SERIAL_NOTES,
1079                 '','chrome,resizable,modal',
1080                 { 'object_id' : obj_id, 'function_type' : function_type, 'object_type' : object_type, 'constructor' : constructor, 'title' : $('serialStrings').getString('staff.serial.'+type+'_editor.notes') + ' -- ' + title_fn(sitem) }
1081             );
1082             seen_ids[obj_id] = 1;
1083         }
1084         if (notes_window.notes_updated) { // we changed some notes
1085             if (notes_window.notes_updated.sdistn || notes_window.notes_updated.ssubn) {
1086                 obj.refresh_all();
1087             } else {
1088                 obj.refresh_rows(sitem_ids);
1089             }
1090         }
1091     },
1092
1093     '_fetch_alert_notes' : function() {
1094         var obj = this;
1095
1096         JSAN.use('util.functional');
1097         var notes = [];
1098
1099         var alert_ids = {
1100             "ssub" : [],
1101             "sdist" : [],
1102             "sitem" : []
1103         };
1104
1105         //gather selected item alerts
1106         if (obj.retrieve_ids) {
1107             var related_obj_ids = {'ssub' : {}, 'sdist' : {}};
1108             for (var i = 0; i < obj.retrieve_ids.length; i++) {
1109                 var item = obj.list_sitem_map[obj.retrieve_ids[i].sitem_id];
1110                 var my_notes = util.functional.filter_list(
1111                     item.notes(),
1112                     function (o) {
1113                         return get_bool(o.alert());
1114                     }
1115                 );
1116
1117                 related_obj_ids.ssub[item.issuance().subscription().id()] = 1;
1118                 related_obj_ids.sdist[item.stream().distribution()] = 1;
1119
1120                 if (my_notes.length) {
1121                     alert_ids['sitem'].push(item.id());
1122                     notes = notes.concat(my_notes);
1123                 }
1124             }
1125
1126             // gather related object (sub/dist) alerts
1127             ['sdist', 'ssub'].forEach(function(type) {
1128                 var obj_ids = related_obj_ids[type];
1129                 var type_map = obj[type + '_map'];
1130                 for (my_id in obj_ids) {
1131                     var my_notes = util.functional.filter_list(
1132                         type_map[my_id].notes(),
1133                         function (o) {
1134                             return get_bool(o.alert());
1135                         }
1136                     );
1137
1138                     if (my_notes.length) {
1139                         alert_ids[type].push(my_id);
1140                         notes = notes.concat(my_notes);
1141                     }
1142                 }
1143             });
1144         }
1145
1146         return {
1147             "notes" : notes,
1148             "alert_ids" : alert_ids
1149         };
1150     },
1151
1152     'set_alert_notes_button' : function() {
1153         var obj = this;
1154         var alert_data = obj._fetch_alert_notes();
1155
1156         var num_alerts = alert_data.notes.length;
1157         if (num_alerts > 0) {
1158             $('serial_alert_button').setAttribute('disabled','false');
1159             $('serial_alert_button_image').src = '/xul/server/skin/media/images/bell.png';
1160             if (num_alerts == 1) {
1161                 $('serial_alert_button_label').value = $('serialStrings').getString('staff.serial.manage_items.alert_button.label');
1162             } else {
1163                 $('serial_alert_button_label').value = $('serialStrings').getFormattedString('staff.serial.manage_items.alert_button.plural.label', num_alerts);
1164             }
1165         } else {
1166             $('serial_alert_button').setAttribute('disabled','true');
1167             $('serial_alert_button_image').src = '/xul/server/skin/media/images/bell_disabled.png';
1168             $('serial_alert_button_label').value = $('serialStrings').getFormattedString('staff.serial.manage_items.alert_button.plural.label', 0);
1169         }
1170     },
1171
1172     'view_alert_notes' : function() {
1173         var obj = this;
1174
1175         JSAN.use('util.functional');
1176         var alert_data = obj._fetch_alert_notes();
1177         var notes = alert_data.notes;
1178         var alert_ids = alert_data.alert_ids;
1179
1180         if (notes.length <= 0) return;
1181
1182         // create titles for each alerted objects notes
1183         var section_titles = {
1184             "ssubn" : [],
1185             "sdistn" : [],
1186             "sin" : []
1187         }
1188         for (type in alert_ids) {
1189             var typed_ids = alert_ids[type];
1190             for (var i = 0; i < typed_ids.length; i++) {
1191                 var my_id = typed_ids[i];
1192                 var title_chunk = '';
1193                 var fm_class = '';
1194                 switch(type) {
1195                     case 'sitem':
1196                         fm_class = 'sin';
1197                         break;
1198                     case 'ssub':
1199                         title_chunk = obj.ssub_map[my_id].owning_lib().shortname();
1200                         fm_class = 'ssubn';
1201                         break;
1202                     case 'sdist':
1203                         title_chunk = obj.sdist_map[my_id].label()
1204                             + ' -- '
1205                             + obj.sdist_map[my_id].holding_lib().shortname();
1206                         fm_class = 'sdistn';
1207                         break;
1208                 }
1209                 section_titles[fm_class].push(
1210                     $('serialStrings').getString('staff.serial.'+ type +'_editor.notes')
1211                     + ' -- ' + title_chunk + ' ('
1212                     + fieldmapper.IDL.fmclasses[type].field_map.id.label
1213                     + ' ' + my_id + ')'
1214                 );
1215             }
1216         }
1217
1218         JSAN.use('util.window'); var win = new util.window();
1219         var notes_window = win.open(
1220             urls.XUL_SERIAL_NOTES,
1221             '','chrome,resizable,modal',
1222             { 'notes' : notes, 'section_titles' : section_titles, 'title' : "Serial Alerts", 'disable_create' : true, 'section_id_names' : { 'ssubn' : 'subscription', 'sdistn' : 'distribution', 'sin' : 'item'} }
1223         );
1224         if (notes_window.notes_updated) { // we changed some notes
1225             if (notes_window.notes_updated.sdistn || notes_window.notes_updated.ssubn) {
1226                 obj.refresh_all();
1227             } else {
1228                 obj.refresh_rows(alert_ids["sitem"]);
1229             }
1230         }
1231         return;
1232     },
1233
1234     'set_items_special_status' : function(new_status, message) {
1235         var obj = this;
1236         try {
1237             if (!obj.retrieve_ids || obj.retrieve_ids.length == 0) return;
1238
1239             JSAN.use('util.functional');
1240             var list = util.functional.map_list(
1241                     obj.retrieve_ids,
1242                     function (o) {
1243                         var item = obj.list_sitem_map[o.sitem_id];
1244                         item.status(new_status);
1245                         obj.list_sitem_map[o.sitem_id] = item;
1246                         return item;
1247                     }
1248                 );
1249
1250             var robj = obj.network.request(
1251                         'open-ils.serial',
1252                         'open-ils.serial.item.fleshed.batch.update',
1253                         [ ses(), list ]
1254                     );
1255             if (typeof robj.ilsevent != 'undefined') throw(robj);
1256
1257             alert($('serialStrings').getFormattedString(message, [list.length]));
1258             obj.refresh_rows(list);
1259         } catch(E) {
1260             obj.error.standard_unexpected_error_alert('staff.serial.manage_items.set_items_special_status.error',E);
1261         }
1262     }
1263 }
1264
1265 function item_columns(modify,params) {
1266
1267     JSAN.use('OpenILS.data'); var data = new OpenILS.data(); data.init({'via':'stash'});
1268     //JSAN.use('util.network'); var network = new util.network();
1269
1270     var c = [
1271         {
1272             'id' : 'sitem_id',
1273             'label' : 'Item ID',
1274             'flex' : 1,
1275             'primary' : false,
1276             'hidden' : false,
1277             'render' : function(my) { return my.sitem.id(); },
1278             'persist' : 'hidden width ordinal'
1279         },
1280         {
1281             'id' : 'label',
1282             'label' : 'Issuance Label',
1283             'flex' : 1,
1284             'primary' : false,
1285             'hidden' : false,
1286             'render' : function(my) { return my.sitem.issuance().label(); },
1287             'persist' : 'hidden width ordinal'
1288         },
1289         {
1290             'id' : 'distribution',
1291             'label' : 'Distribution',
1292             'flex' : 1,
1293             'primary' : false,
1294             'hidden' : false,
1295             'persist' : 'hidden width ordinal',
1296             'render' : function(my) { return my.parent_obj.sdist_map[my.sitem.stream().distribution()].label(); }
1297         },
1298         {
1299             'id' : 'distribution_ou',
1300             'label' : $('serialStrings').getString('staff.serial.manage_items.holder.label'),
1301             'flex' : 1,
1302             'primary' : false,
1303             'hidden' : false,
1304             'persist' : 'hidden width ordinal',
1305             'render' : function(my) { return my.parent_obj.sdist_map[my.sitem.stream().distribution()].holding_lib().shortname(); }
1306         },
1307         {
1308             'id' : 'stream_id',
1309             'label' : 'Stream ID',
1310             'flex' : 1,
1311             'primary' : false,
1312             'hidden' : false,
1313             'persist' : 'hidden width ordinal',
1314             'render' : function(my) { return my.sitem.stream().id(); }
1315         },
1316         {
1317             'id' : 'date_published',
1318             'label' : 'Date Published',
1319             'flex' : 1,
1320             'primary' : false,
1321             'hidden' : false,
1322             'render' : function(my) { return my.sitem.issuance().date_published().substr(0,10); },
1323             'persist' : 'hidden width ordinal'
1324         },
1325         {
1326             'id' : 'date_expected',
1327             'label' : 'Date Expected',
1328             'flex' : 1,
1329             'primary' : false,
1330             'hidden' : false,
1331             'render' : function(my) { return my.sitem.date_expected().substr(0,10); },
1332             'persist' : 'hidden width ordinal'
1333         },
1334         {
1335             'id' : 'date_received',
1336             'label' : 'Date Received',
1337             'flex' : 1,
1338             'primary' : false,
1339             'hidden' : false,
1340             'render' : function(my) { return my.sitem.date_received().substr(0,10); },
1341             'persist' : 'hidden width ordinal'
1342         },
1343         {
1344             'id' : 'notes',
1345             'label' : $('serialStrings').getString('staff.serial.manage_items.notes_column.label'),
1346             'flex' : 1,
1347             'primary' : false,
1348             'hidden' : false,
1349             'render' : function(my) { return my.sitem.notes().length + ' / ' + my.parent_obj.sdist_map[my.sitem.stream().distribution()].notes().length + ' / ' + my.parent_obj.ssub_map[my.sitem.issuance().subscription().id()].notes().length; },
1350             'persist' : 'hidden width ordinal'
1351         },
1352         {
1353             'id' : 'call_number',
1354             'label' : 'Call Number',
1355             'flex' : 1,
1356             'primary' : false,
1357             'hidden' : false,
1358             'persist' : 'hidden width ordinal',
1359             'render' : function(my) { return my.sitem.unit().call_number().label(); }
1360         },
1361         {
1362             'id' : 'unit_id_contents',
1363             'label' : 'Unit ID / Contents',
1364             'flex' : 1,
1365             'primary' : false,
1366             'hidden' : false,
1367             'render' : function(my) { return '[' + my.sitem.unit().id() + '] ' + my.sitem.unit().summary_contents() ; },
1368             'persist' : 'hidden width ordinal'
1369         },
1370         {
1371             'id' : 'creator',
1372             'label' : 'Creator',
1373             'flex' : 1,
1374             'primary' : false,
1375             'hidden' : true,
1376             'persist' : 'hidden width ordinal',
1377             'render' : function(my) { return my.sitem.creator().usrname(); }
1378         },
1379         {
1380             'id' : 'create_date',
1381             'label' : document.getElementById('circStrings').getString('staff.circ.utils.create_date'),
1382             'flex' : 1,
1383             'primary' : false,
1384             'hidden' : true,
1385             'persist' : 'hidden width ordinal',
1386             'render' : function(my) { return my.sitem.create_date().substr(0,10); }
1387         },
1388         {
1389             'id' : 'editor',
1390             'label' : 'Editor',
1391             'flex' : 1,
1392             'primary' : false,
1393             'hidden' : true,
1394             'persist' : 'hidden width ordinal',
1395             'render' : function(my) { return my.sitem.editor().usrname(); }
1396         },
1397         {
1398             'id' : 'edit_date',
1399             'label' : document.getElementById('circStrings').getString('staff.circ.utils.edit_date'),
1400             'flex' : 1,
1401             'primary' : false,
1402             'hidden' : false,
1403             'persist' : 'hidden width ordinal',
1404             'render' : function(my) { return my.sitem.edit_date().substr(0,10); }
1405         },
1406         {
1407             'id' : 'holding_code',
1408             'label' : 'Holding Code',
1409             'flex' : 1,
1410             'primary' : false,
1411             'hidden' : true,
1412             'render' : function(my) { return my.sitem.issuance().holding_code(); },
1413             'persist' : 'hidden width ordinal'
1414         },
1415         {
1416             'id' : 'holding_type',
1417             'label' : 'Holding Type',
1418             'flex' : 1,
1419             'primary' : false,
1420             'hidden' : true,
1421             'render' : function(my) { return my.sitem.issuance().holding_type(); },
1422             'persist' : 'hidden width ordinal'
1423         },
1424         {
1425             'id' : 'holding_link_id',
1426             'label' : 'Holding Link ID',
1427             'flex' : 1,
1428             'primary' : false,
1429             'hidden' : true,
1430             'render' : function(my) { return my.sitem.issuance().holding_link_id(); },
1431             'persist' : 'hidden width ordinal'
1432         }
1433     ];
1434     for (var i = 0; i < c.length; i++) {
1435         if (modify[ c[i].id ]) {
1436             for (var j in modify[ c[i].id ]) {
1437                 c[i][j] = modify[ c[i].id ][j];
1438             }
1439         }
1440     }
1441     if (params) {
1442         if (params.just_these) {
1443             JSAN.use('util.functional');
1444             var new_c = [];
1445             for (var i = 0; i < params.just_these.length; i++) {
1446                 var x = util.functional.find_list(c,function(d){return(d.id==params.just_these[i]);});
1447                 new_c.push( function(y){ return y; }( x ) );
1448             }
1449             c = new_c;
1450         }
1451         if (params.except_these) {
1452             JSAN.use('util.functional');
1453             var new_c = [];
1454             for (var i = 0; i < c.length; i++) {
1455                 var x = util.functional.find_list(params.except_these,function(d){return(d==c[i].id);});
1456                 if (!x) new_c.push(c[i]);
1457             }
1458             c = new_c;
1459         }
1460     }
1461     //return c.sort( function(a,b) { if (a.label < b.label) return -1; if (a.label > b.label) return 1; return 0; } );
1462     return c;
1463 };
1464
1465 spawn_sitem_editor = function(params) {
1466     try {
1467         if (!params.sitem_ids && !params.sitems) return;
1468         if (params.sitem_ids && params.sitem_ids.length == 0) return;
1469         if (params.sitems && params.sitems.length == 0) return;
1470         if (params.sitem_ids) params.sitem_ids = js2JSON(params.sitem_ids); // legacy
1471         if (!params.caller_handles_update) params.handle_update = 1; // legacy
1472
1473         var obj = {};
1474         JSAN.use('util.network'); obj.network = new util.network();
1475         JSAN.use('util.error'); obj.error = new util.error();
1476
1477         var title = '';
1478         if (params.sitem_ids && params.sitem_ids.length > 1 && params.do_edit == 1)
1479             title = 'Batch Edit Items';
1480         else /* if(params.sitems && params.sitems.length > 1 && params.do_edit == 1)
1481             title = 'Batch View Items';
1482         else if(params.sitem_ids && params.sitem_ids.length == 1) */
1483             title = 'Edit Item';/*
1484         else
1485             title = 'View Item';*/
1486
1487         JSAN.use('util.window'); var win = new util.window();
1488         params.in_modal = true;
1489         var my_xulG = win.open(
1490             (urls.XUL_SERIAL_ITEM_EDITOR),
1491             title,
1492             'chrome,modal,resizable',
1493             params
1494         );
1495         if (my_xulG.sitems && params.do_edit) {
1496             return my_xulG.sitems;
1497         } else {
1498             return [];
1499         }
1500     } catch(E) {
1501         JSAN.use('util.error'); var error = new util.error();
1502         error.standard_unexpected_error_alert('error in spawn_sitem_editor',E);
1503     }
1504 }
1505
1506 dump('exiting manage_items.js\n');