1 angular.module('egSerialsAppDep')
3 .directive('egItemGrid', function() {
11 templateUrl: './serials/t_view_items_grid',
13 ['$scope','$q','egSerialsCoreSvc','egCore','egGridDataProvider','orderByFilter',
14 '$uibModal','ngToast','egConfirmDialog','egPromptDialog','$timeout',
15 function($scope , $q , egSerialsCoreSvc , egCore , egGridDataProvider , orderByFilter ,
16 $uibModal , ngToast , egConfirmDialog , egPromptDialog , $timeout) {
18 $scope.svc = egSerialsCoreSvc;
21 function reload(ssubId,filter) {
22 _paging_filter = filter;
23 return egSerialsCoreSvc.fetchItemsForSub(ssubId,filter).then(function() {
24 $scope.itemGridProvider.refresh();
28 $scope.filter_items_all = function () { return reload($scope.ssubId) }
29 $scope.filter_items_have = function () { return reload($scope.ssubId,{status:['Received','Bindery','Bound']}) }
30 $scope.filter_items_dont_have = function () { return reload($scope.ssubId,{'-not':{status:['Received','Bindery','Bound']}}) }
31 $scope.filter_items_by_status = function (item,status) { return reload($scope.ssubId,{status:status.name}) }
33 $scope.$watch('ssubId', function(newVal, oldVal) {
34 if (newVal && newVal != oldVal) return reload(newVal);
37 $scope.itemGridControls = {
38 activateItem : function (item) { } // TODO
41 function compileSort(sort) {
42 if (sort && angular.isArray(sort) && sort.length == 1) {
43 if (angular.isObject(sort[0])) {
44 for (key in sort[0]) {
48 direction : sort[0][key]
52 return { 'class': 'sitem', field: sort[0] };
56 var current_sort = [];
57 $scope.itemGridProvider = egGridDataProvider.instance({
58 get : function(offset, count) {
60 if (angular.equals(current_sort, self.sort) && egSerialsCoreSvc.itemList.length >= offset + count) { // if there's anything on the requested page, notify
61 return self.arrayNotifier(egSerialsCoreSvc.itemList, offset, count);
62 } else { // else try to fetch another page
63 if (angular.equals(current_sort, self.sort)) {
64 return egSerialsCoreSvc.fetchItemsForSubPaged(
67 egSerialsCoreSvc.itemList.length,
68 count + offset - egSerialsCoreSvc.itemList.length,
69 compileSort(self.sort)
71 return self.arrayNotifier(egSerialsCoreSvc.itemList, offset, count);
74 current_sort = self.sort;
75 return egSerialsCoreSvc.fetchItemsForSub(
79 compileSort(self.sort)
81 return self.arrayNotifier(egSerialsCoreSvc.itemList, offset, count);
88 $scope.delete_items = function (items) {
91 angular.forEach(items, function (i) {
92 var obj = egCore.idl.fromHash('sitem',i);
94 obj.stream(obj.stream().id); // API wants scalar or FM object
95 obj.issuance(obj.issuance().id);
100 egCore.strings.CONFIRM_CHANGE_ITEMS.delete,
101 egCore.strings.CONFIRM_CHANGE_ITEMS_MESSAGE.delete,
102 {items : list.length}
103 ).result.then(function () {
104 return egCore.net.request(
106 'open-ils.serial.item.fleshed.batch.update',
109 ).then( function(resp) {
110 var evt = egCore.evt.parse(resp);
112 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
114 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
115 return reload($scope.ssubId,_paging_filter);
121 $scope.edit_issuance_holding_code = function (items) {
124 angular.forEach(items.reverse(), function (item) {
125 promises.push( egSerialsCoreSvc.new_holding_code({
126 title : egCore.strings.SERIALS_EDIT_SISS_HC,
127 curr_iss : egCore.idl.fromHash('siss',item.issuance),
128 label : item.issuance.label,
129 type : item.issuance.type ? item.issuance.type : 'basic',
130 can_change_adhoc : true
131 }).then(function(result) {
133 item.issuance.holding_code = JSON.stringify(result.holding_code);
134 item.issuance.holding_type = result.type;
136 item.issuance.label = result.label;
137 item.issuance.holding_type = result.type;
140 item.issuance.date_published = result.date.toISOString();
141 item.issuance.editor = egCore.auth.user();
142 item.issuance.edit_date = 'now';
144 var iss = egCore.idl.fromHash('siss',item.issuance);
145 if (!result.adhoc) { // not an ad hoc issuance, get predicted label
146 return egCore.net.request(
148 'open-ils.serial.make_prediction_values',
150 { ssub_id : $scope.ssubId,
152 include_base_issuance : 1,
155 ).then( function(resp) {
156 var evt = egCore.evt.parse(resp);
158 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
160 iss.label(resp[0].label);
166 return $q.when(edits.push(iss));
170 return $q.all(promises)
171 .finally(function() {
172 if (edits.length) return update_issuances(edits);
177 function update_issuances (list) {
178 if (!angular.isArray(list)) list = [list];
180 return egCore.net.request(
182 'open-ils.serial.issuance.fleshed.batch.update',
187 var evt = egCore.evt.parse(resp);
189 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
191 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
192 return reload($scope.ssubId,_paging_filter);
196 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
202 $scope.following_issuance = function (items) {
203 return egSerialsCoreSvc.new_holding_code({
204 title : egCore.strings.SERIALS_ISSUANCE_ADD,
205 prev_iss : egCore.idl.fromHash('siss',items[0].issuance),
206 can_change_adhoc : true
207 }).then(function(hc) {
209 var new_iss = new egCore.idl.siss();
210 new_iss.creator( egCore.auth.user().id() );
211 new_iss.editor( egCore.auth.user().id() );
212 new_iss.date_published( hc.date.toISOString() );
213 new_iss.subscription( $scope.ssubId );
214 new_iss.label( hc.label );
215 new_iss.holding_type( hc.type );
217 return egCore.pcrud.create(new_iss).then(function(issuance) {
218 var new_item = new egCore.idl.sitem();
219 new_item.creator( egCore.auth.user().id() );
220 new_item.editor( egCore.auth.user().id() );
221 new_item.issuance( issuance.id() );
222 new_item.stream( items[0].stream.id );
223 new_item.date_expected( hc.date.toISOString() ); // XXX do we have interval math?
225 return egCore.pcrud.create(new_item).then(function() {
226 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
227 return reload($scope.ssubId,_paging_filter);
229 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
232 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
236 return egCore.net.request(
238 'open-ils.serial.make_predictions',
240 { ssub_id : $scope.ssubId,
242 base_issuance : egCore.idl.fromHash('siss',items[0].issuance)
246 var evt = egCore.evt.parse(resp);
248 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
250 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
251 return reload($scope.ssubId,_paging_filter);
255 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
261 $scope.add_special_issuance = function() {
262 return egSerialsCoreSvc.new_holding_code({
263 title : egCore.strings.SERIALS_SPECIAL_ISSUANCE_ADD,
264 can_change_adhoc : false,
266 }).then(function(hc) {
268 var new_iss = new egCore.idl.siss();
269 new_iss.creator( egCore.auth.user().id() );
270 new_iss.editor( egCore.auth.user().id() );
271 new_iss.date_published( hc.date.toISOString() );
272 new_iss.subscription( $scope.ssubId );
273 new_iss.label( hc.label );
274 new_iss.holding_type( hc.type );
276 return egCore.pcrud.create(new_iss).then(function(issuance) {
278 var sub = egSerialsCoreSvc.get_ssub($scope.ssubId);
279 angular.forEach(sub.distributions(), function(dist) {
280 angular.forEach(dist.streams(), function(stream) {
281 var new_item = new egCore.idl.sitem();
282 new_item.creator( egCore.auth.user().id() );
283 new_item.editor( egCore.auth.user().id() );
284 new_item.issuance( issuance.id() );
285 new_item.stream( stream.id() );
286 new_item.date_expected( hc.date.toISOString() ); // XXX do we have interval math?
287 new_items.push(new_item);
291 angular.forEach(new_items, function(item) {
292 promises.push(egCore.pcrud.create(item));
295 $q.all(promises).then(function() {
296 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
297 return reload($scope.ssubId,_paging_filter);
299 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
305 $scope.do_print_routing_lists = false;
306 egCore.hatch.getItem('eg.serials.items.do_print_routing_lists').then(function(val) {
307 $scope.do_print_routing_lists = val;
310 $scope.receive_and_barcode = false;
311 egCore.hatch.getItem('eg.serials.items.receive_and_barcode').then(function(val) {
312 $scope.receive_and_barcode = val;
315 $scope.checkbox_handler = function(item) {
316 $scope[item.checkbox] = item.checked;
317 egCore.hatch.setItem('eg.serials.items.'+item.checkbox, item.checked);
320 $scope.receive_next = function () {
322 var next_per_stream = {};
323 angular.forEach(egSerialsCoreSvc.itemTree, function (item) {
324 if (next_per_stream[item.stream().id()]) return;
325 if (item.status() == 'Expected') {
326 next_per_stream[item.stream().id()] = item;
327 list.push(egCore.idl.Clone(item));
331 return egSerialsCoreSvc.process_items('receive', $scope.bibId, list, $scope.receive_and_barcode, false, $scope.do_print_routing_lists, function(){reload($scope.ssubId,_paging_filter)});
334 $scope.receive_selected = function (list) {
335 var items = list.filter(function(i){
336 return i.status == 'Expected';
338 return egSerialsCoreSvc.process_items('receive', $scope.bibId, items.map(function(item) {
339 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
340 }), $scope.receive_and_barcode, false, $scope.do_print_routing_lists, function(){reload($scope.ssubId,_paging_filter)});
343 $scope.reset_selected = function (list) {
344 return egSerialsCoreSvc.process_items('reset', $scope.bibId, list.map(function(item) {
345 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
346 }), false, false, false, function(){reload($scope.ssubId,_paging_filter)});
349 $scope.bind_selected = function (list) {
350 return egSerialsCoreSvc.process_items('bind', $scope.bibId, list.map(function(item) {
351 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
352 }), true, true, $scope.do_print_routing_lists, function(){reload($scope.ssubId,_paging_filter)});
355 $scope.set_selected_as_claimed = function(list) {
356 return egSerialsCoreSvc.set_item_status('Claimed', $scope.bibId, list.map(function(item) {
357 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
358 }), function(){reload($scope.ssubId,_paging_filter)});
360 $scope.set_selected_as_discarded = function(list) {
361 return egSerialsCoreSvc.set_item_status('Discarded', $scope.bibId, list.map(function(item) {
362 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
363 }), function(){reload($scope.ssubId,_paging_filter)});
365 $scope.set_selected_as_not_published = function(list) {
366 return egSerialsCoreSvc.set_item_status('Not Published', $scope.bibId, list.map(function(item) {
367 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
368 }), function(){reload($scope.ssubId,_paging_filter)});
370 $scope.set_selected_as_not_held = function(list) {
371 return egSerialsCoreSvc.set_item_status('Not Held', $scope.bibId, list.map(function(item) {
372 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
373 }), function(){reload($scope.ssubId,_paging_filter)});
376 $scope.menu_print_routing_lists = function (items) {
377 items = items.map(function(item) {
378 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
380 return egSerialsCoreSvc.print_routing_lists($scope.bibId, items, false, true, $scope.do_print_routing_lists);
383 $scope.add_issuances = function () {
384 egSerialsCoreSvc.add_issuances($scope.ssubId).then(function() {
385 return reload($scope.ssubId,_paging_filter);
389 $scope.need_one_selected = function() {
390 var items = $scope.itemGridControls.selectedItems();
391 if (items.length == 1) return false;
395 $scope.need_many_selected = function() {
396 var items = $scope.itemGridControls.selectedItems();
397 if (items.length > 1) return false;
401 $scope.need_expected = function() {
402 var items = $scope.itemGridControls.selectedItems().filter(function(i){
403 return i.status == 'Expected';
405 if (items.length) return false;
409 $scope.item_notes = function(rows) {
410 return $scope.notes('item',rows);
412 // TODO - refactor this, it's duplicated in subscription_manager.js
413 $scope.notes = function(note_type,rows) {
414 if (!rows) { return; }
416 function modal(existing_notes) {
418 templateUrl: './serials/t_notes',
420 controller: 'NotesCtrl',
422 note_type : function() { return note_type; },
427 return existing_notes;
430 windowClass: 'app-modal-window',
433 }).result.then(function(notes) {
434 egCore.pcrud.apply(notes).then(
435 function(a) { ngToast.success(egCore.strings.SERIALS_ITEM_NOTE_SUCCESS_SAVE) },
436 function(a) { ngToast.danger(egCore.strings.SERIALS_ITEM_NOTE_FAIL_SAVE) }
441 if (rows.length == 1) {
443 var search_hash = {};
448 search_hash.subscription = rows[0]['id'];
449 search_opt.order_by = { ssubn : 'create_date' };
453 search_hash.distribution = rows[0]['sdist.id'];
454 search_opt.order_by = { sdistn : 'create_date' };
456 case 'item': default:
458 search_hash.item = rows[0]['id'];
459 search_opt.order_by = { sin : 'create_date' };
462 egCore.pcrud.search(fm_hint, search_hash, search_opt,
464 ).then(function(list) {
468 // support batch creation of notes across selections,
479 // TODO - refactor this; it's duplicated in subscription_manager.js
480 .controller('NotesCtrl',
481 ['$scope','$uibModalInstance','egCore','note_type','rows','notes',
482 function($scope , $uibModalInstance , egCore , note_type , rows , notes ) {
483 $scope.note_type = note_type;
484 $scope.focusNote = true;
486 creator : egCore.auth.user().id(),
493 $scope.require_initials = false;
494 egCore.org.settings([
495 'ui.staff.require_initials.copy_notes'
496 ]).then(function(set) {
497 $scope.require_initials = Boolean(set['ui.staff.require_initials.copy_notes']);
500 $scope.note_list = notes;
502 $scope.ok = function(note) {
504 var return_notes = [];
505 if (note.initials) note.value += ' [' + note.initials + ']';
506 if ( (typeof note.title != 'undefined' && note.title != '')
507 || (typeof note.value != 'undefined' && note.value != '')) {
508 angular.forEach(rows, function (r) {
512 n = new egCore.idl.ssubn();
513 n.subscription(r['id']);
516 n = new egCore.idl.sdistn();
517 n.distribution(r['sdist.id']);
521 n = new egCore.idl.sin();
525 n.creator(note.creator);
527 n['alert'](note['alert']);
530 return_notes.push( n );
533 angular.forEach(notes, function(n) {
534 if (n.ischanged() || n.isdeleted()) {
535 return_notes.push( n );
538 $uibModalInstance.close(return_notes);
541 $scope.cancel = function($event) {
542 $uibModalInstance.dismiss();
543 $event.preventDefault();