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 = egSerialsCoreSvc.itemMap[i.id];
98 egCore.strings.CONFIRM_CHANGE_ITEMS.delete,
99 egCore.strings.CONFIRM_CHANGE_ITEMS_MESSAGE.delete,
100 {items : list.length}
101 ).result.then(function () {
102 return egCore.net.request(
104 'open-ils.serial.item.fleshed.batch.update',
107 ).then( function(resp) {
108 var evt = egCore.evt.parse(resp);
110 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
112 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
113 return reload($scope.ssubId,_paging_filter);
119 $scope.edit_issuance_holding_code = function (items) {
122 angular.forEach(items.reverse(), function (item) {
123 promises.push( egSerialsCoreSvc.new_holding_code({
124 title : egCore.strings.SERIALS_EDIT_SISS_HC,
125 curr_iss : egCore.idl.fromHash('siss',item.issuance),
126 label : item.issuance.label,
127 type : item.issuance.type ? item.issuance.type : 'basic',
128 can_change_adhoc : true
129 }).then(function(result) {
131 item.issuance.holding_code = JSON.stringify(result.holding_code);
132 item.issuance.holding_type = result.type;
134 item.issuance.label = result.label;
135 item.issuance.holding_type = result.type;
138 item.issuance.date_published = result.date.toISOString();
139 item.issuance.editor = egCore.auth.user();
140 item.issuance.edit_date = 'now';
142 var iss = egCore.idl.fromHash('siss',item.issuance);
143 if (!result.adhoc) { // not an ad hoc issuance, get predicted label
144 return egCore.net.request(
146 'open-ils.serial.make_prediction_values',
148 { ssub_id : $scope.ssubId,
150 include_base_issuance : 1,
153 ).then( function(resp) {
154 var evt = egCore.evt.parse(resp);
156 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
158 iss.label(resp[0].label);
164 return $q.when(edits.push(iss));
168 return $q.all(promises)
169 .finally(function() {
170 if (edits.length) return update_issuances(edits);
175 function update_issuances (list) {
176 if (!angular.isArray(list)) list = [list];
178 return egCore.net.request(
180 'open-ils.serial.issuance.fleshed.batch.update',
185 var evt = egCore.evt.parse(resp);
187 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
189 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
190 return reload($scope.ssubId,_paging_filter);
194 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
200 $scope.following_issuance = function (items) {
201 return egSerialsCoreSvc.new_holding_code({
202 title : egCore.strings.SERIALS_ISSUANCE_ADD,
203 prev_iss : egCore.idl.fromHash('siss',items[0].issuance),
204 can_change_adhoc : true
205 }).then(function(hc) {
207 var new_iss = new egCore.idl.siss();
208 new_iss.creator( egCore.auth.user().id() );
209 new_iss.editor( egCore.auth.user().id() );
210 new_iss.date_published( hc.date.toISOString() );
211 new_iss.subscription( $scope.ssubId );
212 new_iss.label( hc.label );
213 new_iss.holding_type( hc.type );
215 return egCore.pcrud.create(new_iss).then(function(issuance) {
216 var new_item = new egCore.idl.sitem();
217 new_item.creator( egCore.auth.user().id() );
218 new_item.editor( egCore.auth.user().id() );
219 new_item.issuance( issuance.id() );
220 new_item.stream( items[0].stream.id );
221 new_item.date_expected( hc.date.toISOString() ); // XXX do we have interval math?
223 return egCore.pcrud.create(new_item).then(function() {
224 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
225 return reload($scope.ssubId,_paging_filter);
227 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
230 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
234 return egCore.net.request(
236 'open-ils.serial.make_predictions',
238 { ssub_id : $scope.ssubId,
240 base_issuance : egCore.idl.fromHash('siss',items[0].issuance)
244 var evt = egCore.evt.parse(resp);
246 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
248 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
249 return reload($scope.ssubId,_paging_filter);
253 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
259 $scope.add_special_issuance = function() {
260 return egSerialsCoreSvc.new_holding_code({
261 title : egCore.strings.SERIALS_SPECIAL_ISSUANCE_ADD,
262 can_change_adhoc : false,
264 }).then(function(hc) {
266 var new_iss = new egCore.idl.siss();
267 new_iss.creator( egCore.auth.user().id() );
268 new_iss.editor( egCore.auth.user().id() );
269 new_iss.date_published( hc.date.toISOString() );
270 new_iss.subscription( $scope.ssubId );
271 new_iss.label( hc.label );
272 new_iss.holding_type( hc.type );
274 return egCore.pcrud.create(new_iss).then(function(issuance) {
276 var sub = egSerialsCoreSvc.get_ssub($scope.ssubId);
277 angular.forEach(sub.distributions(), function(dist) {
278 angular.forEach(dist.streams(), function(stream) {
279 var new_item = new egCore.idl.sitem();
280 new_item.creator( egCore.auth.user().id() );
281 new_item.editor( egCore.auth.user().id() );
282 new_item.issuance( issuance.id() );
283 new_item.stream( stream.id() );
284 new_item.date_expected( hc.date.toISOString() ); // XXX do we have interval math?
285 new_items.push(new_item);
289 angular.forEach(new_items, function(item) {
290 promises.push(egCore.pcrud.create(item));
293 $q.all(promises).then(function() {
294 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
295 return reload($scope.ssubId,_paging_filter);
297 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
303 $scope.do_print_routing_lists = false;
304 egCore.hatch.getItem('eg.serials.items.do_print_routing_lists').then(function(val) {
305 $scope.do_print_routing_lists = val;
308 $scope.receive_and_barcode = false;
309 egCore.hatch.getItem('eg.serials.items.receive_and_barcode').then(function(val) {
310 $scope.receive_and_barcode = val;
313 $scope.checkbox_handler = function(item) {
314 $scope[item.checkbox] = item.checked;
315 egCore.hatch.setItem('eg.serials.items.'+item.checkbox, item.checked);
318 $scope.receive_next = function () {
320 var next_per_stream = {};
321 angular.forEach(egSerialsCoreSvc.itemTree, function (item) {
322 if (next_per_stream[item.stream().id()]) return;
323 if (item.status() == 'Expected') {
324 next_per_stream[item.stream().id()] = item;
325 list.push(egCore.idl.Clone(item));
329 return egSerialsCoreSvc.process_items('receive', $scope.bibId, list, $scope.receive_and_barcode, false, $scope.do_print_routing_lists, function(){reload($scope.ssubId,_paging_filter)});
332 $scope.receive_selected = function (list) {
333 var items = list.filter(function(i){
334 return i.status == 'Expected';
336 return egSerialsCoreSvc.process_items('receive', $scope.bibId, items.map(function(item) {
337 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
338 }), $scope.receive_and_barcode, false, $scope.do_print_routing_lists, function(){reload($scope.ssubId,_paging_filter)});
341 $scope.reset_selected = function (list) {
342 return egSerialsCoreSvc.process_items('reset', $scope.bibId, list.map(function(item) {
343 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
344 }), false, false, false, function(){reload($scope.ssubId,_paging_filter)});
347 $scope.bind_selected = function (list) {
348 return egSerialsCoreSvc.process_items('bind', $scope.bibId, list.map(function(item) {
349 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
350 }), true, true, $scope.do_print_routing_lists, function(){reload($scope.ssubId,_paging_filter)});
353 $scope.set_selected_as_claimed = function(list) {
354 return egSerialsCoreSvc.set_item_status('Claimed', $scope.bibId, list.map(function(item) {
355 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
356 }), function(){reload($scope.ssubId,_paging_filter)});
358 $scope.set_selected_as_discarded = function(list) {
359 return egSerialsCoreSvc.set_item_status('Discarded', $scope.bibId, list.map(function(item) {
360 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
361 }), function(){reload($scope.ssubId,_paging_filter)});
363 $scope.set_selected_as_not_published = function(list) {
364 return egSerialsCoreSvc.set_item_status('Not Published', $scope.bibId, list.map(function(item) {
365 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
366 }), function(){reload($scope.ssubId,_paging_filter)});
368 $scope.set_selected_as_not_held = function(list) {
369 return egSerialsCoreSvc.set_item_status('Not Held', $scope.bibId, list.map(function(item) {
370 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
371 }), function(){reload($scope.ssubId,_paging_filter)});
374 $scope.menu_print_routing_lists = function (items) {
375 items = items.map(function(item) {
376 return egCore.idl.Clone(egSerialsCoreSvc.itemMap[item.id]);
378 return egSerialsCoreSvc.print_routing_lists($scope.bibId, items, false, true, $scope.do_print_routing_lists);
381 $scope.add_issuances = function () {
382 egSerialsCoreSvc.add_issuances($scope.ssubId).then(function() {
383 return reload($scope.ssubId,_paging_filter);
387 $scope.need_one_selected = function() {
388 var items = $scope.itemGridControls.selectedItems();
389 if (items.length == 1) return false;
393 $scope.need_many_selected = function() {
394 var items = $scope.itemGridControls.selectedItems();
395 if (items.length > 1) return false;
399 $scope.need_expected = function() {
400 var items = $scope.itemGridControls.selectedItems().filter(function(i){
401 return i.status == 'Expected';
403 if (items.length) return false;
407 $scope.item_notes = function(rows) {
408 return $scope.notes('item',rows);
410 // TODO - refactor this, it's duplicated in subscription_manager.js
411 $scope.notes = function(note_type,rows) {
412 if (!rows) { return; }
414 function modal(existing_notes) {
416 templateUrl: './serials/t_notes',
418 controller: 'NotesCtrl',
420 note_type : function() { return note_type; },
425 return existing_notes;
428 windowClass: 'app-modal-window',
431 }).result.then(function(notes) {
432 egCore.pcrud.apply(notes).then(
433 function(a) { ngToast.success(egCore.strings.SERIALS_ITEM_NOTE_SUCCESS_SAVE) },
434 function(a) { ngToast.danger(egCore.strings.SERIALS_ITEM_NOTE_FAIL_SAVE) }
439 if (rows.length == 1) {
441 var search_hash = {};
446 search_hash.subscription = rows[0]['id'];
447 search_opt.order_by = { ssubn : 'create_date' };
451 search_hash.distribution = rows[0]['sdist.id'];
452 search_opt.order_by = { sdistn : 'create_date' };
454 case 'item': default:
456 search_hash.item = rows[0]['id'];
457 search_opt.order_by = { sin : 'create_date' };
460 egCore.pcrud.search(fm_hint, search_hash, search_opt,
462 ).then(function(list) {
466 // support batch creation of notes across selections,
477 // TODO - refactor this; it's duplicated in subscription_manager.js
478 .controller('NotesCtrl',
479 ['$scope','$uibModalInstance','egCore','note_type','rows','notes',
480 function($scope , $uibModalInstance , egCore , note_type , rows , notes ) {
481 $scope.note_type = note_type;
482 $scope.focusNote = true;
484 creator : egCore.auth.user().id(),
491 $scope.note_list = notes;
493 $scope.ok = function(note) {
495 var return_notes = [];
496 if (note.initials) note.value += ' [' + note.initials + ']';
497 if ( (typeof note.title != 'undefined' && note.title != '')
498 || (typeof note.value != 'undefined' && note.value != '')) {
499 angular.forEach(rows, function (r) {
503 n = new egCore.idl.ssubn();
504 n.subscription(r['id']);
507 n = new egCore.idl.sdistn();
508 n.distribution(r['sdist.id']);
512 n = new egCore.idl.sin();
516 n.creator(note.creator);
518 n['alert'](note['alert']);
521 return_notes.push( n );
524 angular.forEach(notes, function(n) {
525 if (n.ischanged() || n.isdeleted()) {
526 return_notes.push( n );
529 $uibModalInstance.close(return_notes);
532 $scope.cancel = function($event) {
533 $uibModalInstance.dismiss();
534 $event.preventDefault();