1 angular.module('egSerialsMod', ['egCoreMod'])
2 .factory('egSerialsCoreSvc',
3 ['egCore','orderByFilter','$q','$filter','$uibModal','ngToast','egConfirmDialog',
4 function(egCore , orderByFilter , $q , $filter , $uibModal , ngToast , egConfirmDialog) {
13 potentialPatternList : [],
41 d : ['year','month','day'],
42 e : ['year','month','day'],
46 i : ['year','month','day'],
47 j : ['year','month','day'],
48 k : ['year','month','day'],
50 q : ['year','season'],
52 t : ['year','month','day'],
53 w : ['year','month','day'],
54 x : ['year','month','day']
57 year : function(d) { return d.getFullYear() },
58 season: function(d) { return _loose_season(d) },
59 month : function(d) { return ('00' + (d.getMonth() + 1)).slice(-2) },
60 week : function(d) { return $filter('date')(d, 'ww') },
61 day : function(d) { return ('00'+d.getDate()).slice(-2) },
62 hour : function(d) { return ('00'+d.getHours()).slice(-2) }
77 angular.forEach(service.item_status_list, function(status) {
78 service.item_status_i18n.push({
80 label : egCore.strings.SERIALS_ITEM_STATUS[status]
84 function _loose_season(D) {
85 var m = D.getMonth() + 1;
89 (m == 1 || m == 2) || (m == 12 && d >= 21) || (m == 3 && d < 20)
91 return 24; /* MFHD winter */
93 (m == 4 || m == 5) || (m == 3 && d >= 20) || (m == 6 && d < 21)
95 return 21; /* spring */
97 (m == 7 || m == 8) || (m == 6 && d >= 21) || (m == 9 && d < 22)
99 return 22; /* summer */
101 return 23; /* autumn */
105 service.fetch_mfhds = function(bibId, contextOrg) {
106 // TODO filter by contextOrg
107 return egCore.pcrud.search('sre', {
114 'sre' : ['owning_lib']
118 ).then(function(list) {
119 service.bibId = bibId;
120 service.mfhdList = list;
121 update_flat_mfhd_list();
125 service.fetch_patterns_from_bibs_mfhds = function(bibId) {
126 return egCore.net.request(
128 'open-ils.serial.caption_and_pattern.find_legacy_by_bib_record.atomic',
131 ).then(function(list) {
132 service.potentialPatternList = egCore.idl.toTypedHash(list);
133 angular.forEach(service.potentialPatternList, function(pot) {
134 var rec = new MARC21.Record({ marcxml : pot.marc });
135 var pattern_fields = rec.fields.filter(function(f) {
136 return (f.tag == '853' || f.tag == '854' || f.tag == '855');
139 if (pattern_fields.length > 0) {
140 // just take the first one
141 var fld = pattern_fields[0];
142 pot.desc = fld.tag + ' ' + fld.ind1 + fld.ind2 +
143 fld.subfields.map(function(sf) {
144 return '$' + sf[0] + sf[1]
151 // fetch subscription, distributions, streams, captions,
152 // and notes associated with the indicated bib
153 service.fetch = function(bibId, contextOrg) {
155 var filter = { record_entry : bibId };
156 if (contextOrg) filter.owning_lib = egCore.org.descendants(contextOrg, true);
157 return egCore.pcrud.search('ssub', filter,
161 'ssub' : ['owning_lib','distributions', 'scaps', 'notes'],
162 'sdist' : [ 'record_entry','holding_lib',
163 'receive_call_number',
164 'receive_unit_template',
166 'bind_unit_template',
168 'sstr' : ['routing_list_users'],
170 'au' : ['card','home_ou','mailing_address','billing_address']
174 ).then(function(list) {
175 service.bibId = bibId;
176 service.subTree = list;
177 update_flat_sdist_sstr_list();
178 return $q.when(list);
182 // fetch subscription, distributions, streams, captions,
183 // and notes associated with the indicated bib
184 service.fetchLastCallnumber = function(contextOrg) {
185 return egCore.pcrud.search('acn', {
186 record : service.bibId,
187 owning_lib : contextOrg,
190 flesh_fields : {acn : ['prefix','suffix']},
191 order_by : [{class:'acn',field:'create_date',direction:'desc'}],
194 ).then(function(list) {
195 return $q.when(list[0]);
199 service.fetchItemsForSubPaged = function(subId,filter,offset,limit,sort) {
200 return service.fetchItemsForSub(
203 { limit : limit, offset : offset, paging : true },
208 // Creates an inverted tree from item to sub
209 service.fetchItemsForSub = function(subId,filter,options,sort) {
210 var deferred = $q.defer(); // side-effects only, otherwise the grid is wonky
212 if (!filter) filter = {};
213 if (!options) options = { limit : 100 }; // only used during full refresh
215 if (!subId && service.subId) subId = service.subId;
216 if (!subId) return $q.reject('fetchItemsForSub: no subscription id');
218 var sub = service.get_ssub(subId);
219 if (!sub) return $q.reject('fetchItemsForSub: unknown subscription id');
222 angular.forEach(sub.distributions(), function(dist) {
225 function (stream) { return stream.id() }
227 function (sid) { streams.push(sid) }
231 angular.extend(filter, {stream:streams});
232 angular.extend(options, {
233 order_by : [{class:'sitem',field:'date_expected'}], // best aprox of pub date
236 sitem : ['notes','issuance','editor','creator','unit','url']
240 angular.extend(options, {
246 'sitem', filter, options,
248 ).then(function(list) {
249 service.subId = subId;
250 if (!options.paging) { // not paged
251 service.itemTree = list;
252 service.itemMap = {};
254 angular.forEach(list, function (item) {
255 var exists = service.itemTree.filter(function (i) {
256 return i.id() == item.id()
258 if (!exists) service.itemTree.push(item);
262 // map items by stream for faster lookup
264 angular.forEach(list, function(item) {
265 if (!tmp[item.stream()]) tmp[item.stream()] = [];
266 tmp[item.stream()].push(item);
267 service.itemMap[item.id()] = item;
270 angular.forEach(sub.distributions(), function(dist) {
271 angular.forEach(dist.streams(), function(stream) {
272 angular.forEach(tmp[stream.id()], function (item) {
273 var routing_list = egCore.idl.Clone(stream.routing_list_users());
274 var st = egCore.idl.Clone(stream,1);
275 st.routing_list_users(routing_list);
276 var d = egCore.idl.Clone(dist,1);
277 var ss = egCore.idl.Clone(sub,1);
278 ss.distributions([]);
287 var hashList = egCore.idl.toHash(service.itemTree);
288 angular.forEach(hashList, function (item) {
289 item['issuance.date_published'] = item.issuance.date_published;
290 item['stream.distribution.holding_lib.name'] = item.stream.distribution.holding_lib.name;
295 service.itemList = hashList;
297 service.itemList = orderByFilter(hashList, ['"issuance.date_published"', '"stream.distribution.holding_lib.name"', '"id"']);
302 return deferred.promise;
305 service.prep_new_holding_code = function (args) {
307 var type = args.type;
308 var date = args.date;
309 var prev_iss = args.prev_iss;
310 var curr_iss = args.curr_iss;
313 var current_values = {};
315 var sub = service.get_ssub(service.subId);
316 if (!sub) return args;
319 var pattern_changed = false;
320 if (prev_iss && prev_iss.holding_code()) { // we're predicting
321 var old_link_parts = JSON.parse(prev_iss.holding_code())[3].split('.');
322 var olink = old_link_parts[0];
323 var oseq = parseInt(old_link_parts[1]) + 1;
324 link = [olink,oseq].join('.');
326 if (prev_iss.holding_type())
327 type = prev_iss.holding_type();
329 if (prev_iss.caption_and_pattern()) {
330 var tmp = sub.scaps().filter(function (s) {
331 return (s.id() == prev_iss.caption_and_pattern() && s.active() == 't');
333 if (angular.isArray(tmp) && tmp[0]) {
336 // pattern associated with last issue must no longer be active
337 pattern_changed = true;
341 date = new Date(prev_iss.date_published());
342 } else if (curr_iss) { // we're editing
343 if (curr_iss.holding_type())
344 type = curr_iss.holding_type();
346 if (curr_iss.caption_and_pattern()) {
347 var tmp = sub.scaps().filter(function (s) {
348 return (s.id() == curr_iss.caption_and_pattern());
350 if (angular.isArray(tmp) && tmp[0]) scap = tmp[0];
352 if (!curr_iss.holding_code()) {
355 var tmp = JSON.parse(curr_iss.holding_code());
356 for (var i = 2; i < tmp.length; i += 2) {
357 // we're intentionally being a bit sloppy here, as
358 // the only subfields we are about in this context
359 // are the ones that are not repeatable
360 current_values[tmp[i]] = tmp[i + 1];
364 date = new Date(curr_iss.date_published());
366 // starting from scratch, so default the
367 // first publication date to the subscription start date
368 if (!date) date = new Date(sub.start_date());
374 var tmp = sub.scaps().filter(function (s) {
375 return (s.type() == type && s.active() == 't');
377 if (angular.isArray(tmp) && tmp[0]) scap = tmp[0];
380 if (!scap) return args;
382 var others = [], enums = [], chrons = [], freq = '';
383 var pat = JSON.parse(scap.pattern_code()).slice(4); // just the part we care about
385 var freq_index = pat.indexOf('w');
386 if (freq_index > -1) {
387 freq = pat[freq_index + 1];
388 if (prev_iss && !args.pattern_changed) {
390 date.getTime() + service.freq_offset[freq]
395 if (!date) date = new Date();
397 for (var i = 0; i < pat.length; i++) {
407 var chron_part = String(val).replace(/[)(]+/g,'');
408 if (sf in current_values) {
409 pat_part.value = current_values[sf];
412 pat_part.value = service.get_chron_part[chron_part](date);
419 if (sf.match(/[a-f]/)) {
420 enums.push(pat_part);
421 } else if (sf.match(/[i-l]/)) {
422 chrons.push(pat_part);
424 others.push(pat_part);
429 if (enums.length == 0 && chrons.length == 0) {
430 var parts = service.freq_chrons[freq];
432 angular.forEach(parts, function(p, ind) {
433 var sf = !ind ? 'i' : !--ind ? 'j' : 'k';
436 value : service.get_chron_part.year(date)
441 { subfield : 'i', value : service.get_chron_part.year(date) },
442 { subfield : 'j', value : service.get_chron_part.month(date) },
443 { subfield : 'k', value : service.get_chron_part.day(date) }
449 holding_code : ["4","1","8",link],
458 pattern_changed : pattern_changed
462 service.new_holding_code = function (options) {
463 if (options === undefined) options = {};
464 options.count = options.count || 1;
465 options.label = options.label || '';
467 return $uibModal.open({
468 templateUrl: './serials/t_holding_code_dialog',
470 //windowClass: 'eg-wide-modal',
473 ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
474 $scope.focusMe = true;
475 $scope.title = options.title;
476 $scope.request_count = options.request_count;
477 $scope.count = options.count;
478 $scope.label = options.label;
479 $scope.save_label = options.save_label;
480 $scope.pubdate = options.date;
481 $scope.type = options.type || 'basic';
482 $scope.args = { adhoc : false };
483 if (options.adhoc) $scope.args.adhoc = true;
484 $scope.can_change_adhoc = options.can_change_adhoc;
486 function refresh (n,o) {
487 if (n && o && n !== o) {
488 $scope.args = service.prep_new_holding_code({
490 date : $scope.pubdate,
491 prev_iss : options.prev_iss,
492 curr_iss : options.curr_iss,
494 if (!options.can_change_adhoc && options.adhoc) $scope.args.adhoc = true;
496 if ($scope.args.type && $scope.type != $scope.args.type)
497 $scope.type = $scope.args.type;
498 if ($scope.args.date)
499 $scope.pubdate = $scope.args.date;
501 delete options.prev_iss; // only use this once
502 delete options.curr_iss; // only use this once
506 $scope.$watch('count',function (n) {options.count = n});
507 $scope.$watch('label',function (n) {options.label = n});
508 $scope.$watch('type',refresh);
509 $scope.$watch('pubdate',refresh);
511 $scope.ok = function(args) { $uibModalInstance.close(args) }
512 $scope.cancel = function () { $uibModalInstance.dismiss() }
514 refresh(1,2); // force data loading
516 }).result.then(function (args) {
517 if (args.enums && args.chrons) {
519 args.enums.concat(args.chrons),
521 args.holding_code.push(e.subfield);
522 args.holding_code.push(e.value);
526 args.count = options.count;
527 args.label = options.label;
528 return $q.when(args);
532 function update_flat_mfhd_list() {
534 angular.forEach(service.mfhdList, function(sre) {
535 var mfhdHash = egCore.idl.toHash(sre);
536 var rec = new MARC21.Record({ marcxml : mfhdHash.marc });
539 'owning_lib.name' : mfhdHash.owning_lib.name,
540 'owning_lib.id' : mfhdHash.owning_lib.id,
541 'marc' : rec.toBreaker(),
542 'marc_xml' : mfhdHash.marc,
544 'basic_holdings' : null,
545 'index_holdings' : null,
546 'supplement_holdings' : null
551 'open-ils.search.serial.record.mfhd.retrieve',
553 ).then(function(svr) {
554 _mfhd.svr = egCore.idl.toTypedHash(svr);
555 _mfhd.basic_holdings = _mfhd.svr.basic_holdings.join("; ");
556 _mfhd.index_holdings = _mfhd.svr.index_holdings.join("; ");
557 _mfhd.supplement_holdings = _mfhd.svr.supplement_holdings.join("; ");
560 service.flatMfhdList.length = 0;
561 angular.extend(service.flatMfhdList, list);
564 // create/update a flat version of the subscription/distribution/stream
565 // tree for feeding to the distribution and stream grid
566 function update_flat_sdist_sstr_list() {
568 // flatten the structure...
570 angular.forEach(service.subTree, function(ssub) {
571 var ssubHash = egCore.idl.toHash(ssub);
575 'owning_lib.name' : ssubHash.owning_lib.name,
576 'owning_lib.id' : ssubHash.owning_lib.id,
577 'start_date' : ssubHash.start_date,
578 'end_date' : ssubHash.end_date,
579 'expected_date_offset' : ssubHash.expected_date_offset
581 // insert and escape if we have no distributions
582 if (ssubHash.distributions.length == 0) {
587 angular.forEach(ssubHash.distributions, function(sdist) {
598 _sdist['sdist.' + fld] = sdist[fld];
600 _sdist['sdist.holding_lib.name'] = sdist.holding_lib.name;
601 _sdist['sdist.holding_lib.id'] = sdist.holding_lib.id;
602 _sdist['sdist.receive_call_number.label'] =
603 sdist.receive_call_number ? sdist.receive_call_number.label : null;
604 _sdist['sdist.receive_unit_template.name'] =
605 sdist.receive_unit_template ? sdist.receive_unit_template.name : null;
606 _sdist['sdist.bind_call_number.label'] =
607 sdist.bind_call_number ? sdist.bind_call_number.label : null;
608 _sdist['sdist.bind_unit_template.name'] =
609 sdist.bind_unit_template ? sdist.bind_unit_template.name : null;
610 // if we have no streams, add to the list and escape
611 if (sdist.streams.length == 0) {
613 angular.extend(row, _ssub, _sdist);
618 angular.forEach(sdist.streams, function(sstr) {
621 'sstr.routing_label' : sstr.routing_label,
622 'sstr.additional_routing' : ((sstr.routing_list_users.length > 0) ? true : false)
625 angular.extend(row, _ssub, _sdist, _sstr);
632 service.subList.length = 0;
633 angular.extend(service.subList,
634 orderByFilter(list, ['"owning_lib.name"', '"start_date"', '"end_date"',
635 '"holding_lib.name"', '"sdist.id"', '"sstr.id"'])
638 // ... then remove duplication of owning library, distribution library,
639 // and distribution labels
642 var dist_label = null;
644 angular.forEach(service.subList, function(row) {
645 row['index'] = index++;
646 if (sub_lib == row['owning_lib.name']) {
647 row['owning_lib.name'] = null;
649 sub_lib = row['owning_lib.name'];
650 dist_lib = row['sdist.holding_lib.name'];
651 dist_label = row['sdist.label'];
654 if (dist_lib == row['sdist.holding_lib.name']) {
655 row['sdist.holding_lib.name'] = null;
657 dist_lib = row['sdist.holding_lib.name'];
659 if (dist_label == row['sdist.label']) {
660 row['sdist.label'] = null;
662 dist_label = row['sdist.label'];
667 // verify that a subscription ID and bib ID are actually
668 // associated with each other
669 service.verify_subscription_id = function(bibId, ssubId) {
670 var deferred = $q.defer();
671 egCore.pcrud.search('ssub', {
672 record_entry : bibId,
674 }, {}, { atomic : true, idlist : true }
675 ).then(function(list) {
676 if (list.length == 1) {
677 deferred.resolve(true);
679 deferred.resolve(false);
682 return deferred.promise;
685 service.get_ssub = function(ssubId) {
687 for (var i = 0; i <= service.subTree.length; i++) {
688 if (service.subTree[i].id() == ssubId) {
689 return service.subTree[i];
694 service.fetch_spt = function() {
695 return egCore.net.request(
697 'open-ils.serial.pattern_template.retrieve.at.atomic',
699 egCore.auth.user().ws_ou()
700 ).then(function(list) {
701 service.sptList.length = 0;
702 angular.extend(service.sptList, list);
706 // return a hash keyed by the supplied OU IDs of
707 // of the list of copy templates owned by the full OU path
709 service.fetch_templates = function(orgs) {
710 var deferred = $q.defer();
711 var _x = angular.isArray(orgs) ? orgs : [ orgs ];
712 var _orgs = _x.map(function(o) {
713 return egCore.org.get(o);
716 var _relevant_orgs = [];
717 angular.forEach(_orgs, function(o) {
718 var _fp = egCore.org.fullPath(o, true);
720 angular.forEach(_fp, function (o2) {
721 if (_relevant_orgs.indexOf(o2) === -1) {
722 _relevant_orgs.push(o2);
726 egCore.pcrud.search('act',
727 {owning_lib : _relevant_orgs},
728 {order_by : { act : 'name' }}, {atomic : true}
729 ).then(function(list) {
731 angular.forEach(_orgs, function(o) {
732 _tmpls[o.id()] = list.filter(function(x) {
733 return _fps[o.id()].indexOf(x.owning_lib()) > -1;
735 return egCore.idl.toTypedHash(x);
738 deferred.resolve(_tmpls);
740 return deferred.promise;
743 service.print_routing_lists = function (bibId, items, check, force, print_rl) {
744 if (!check && !print_rl && !force) return $q.when();
746 return egCore.net.request(
748 'open-ils.search.biblio.record.mods_slim.retrieve',
750 ).then(function(mvr) {
752 var by_issuance = {};
753 angular.forEach(items, function (i) {
754 if (check && !i._print_routing_list) return;
755 if (!by_issuance[i.issuance().id()])
756 by_issuance[i.issuance().id()] = [];
757 by_issuance[i.issuance().id()].push(i);
760 var issuance_matrix = [];
761 angular.forEach(by_issuance, function (list) {
762 issuance_matrix.push(list);
765 var deferred = $q.defer();
766 var promise = deferred.promise;
768 angular.forEach(issuance_matrix, function(item_list, index) {
770 promise = promise.then(function(){
771 return $uibModal.open({
772 templateUrl: './serials/t_print_routing_list',
774 windowClass: 'eg-wide-modal',
777 ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
779 var all_streams = [];
781 angular.forEach(item_list, function(i){
782 all_streams.push(i.stream());
783 all_users = all_users.concat(i.stream().routing_list_users());
787 show_print_button: true,
789 streams : all_streams,
791 issuance: item_list[0].issuance(),
792 users : orderByFilter(all_users, 'pos')
796 $scope.url = '/eg/serial/print_routing_list_users?ses=' + egCore.auth.token();
797 $scope.last = index == issuance_matrix.length - 1 ? true : false;
798 $scope.ok = function() { $uibModalInstance.close() }
805 return deferred.resolve();
810 service.set_item_status = function(newStatus, bibId, list, callback) {
811 if (!callback) callback = function () { return $q.when() }
812 if (!list.length) return $q.reject();
814 return egConfirmDialog.open(
815 egCore.strings.CONFIRM_CHANGE_ITEMS.status,
816 egCore.strings.CONFIRM_CHANGE_ITEMS_MESSAGE.status,
817 {items : list.length}
818 ).result.then(function () {
819 var promises = [$q.when()];
820 angular.forEach(list, function(item) {
821 item.status(newStatus);
825 'open-ils.serial.item.update',
828 ).then(function(res) {
833 $q.all(promises).then(function() {
839 service.process_items = function (mode, bibId, list, do_barcode, bind, print_rl, callback) {
840 if (!callback) callback = function () { return $q.when() }
841 if (!list.length) return $q.reject();
843 // deal with locations and circ mods for *NEW* units
844 var copy_locations = {};
847 // deal with barcodes and call numbers for *NEW* units
849 var call_numbers = {};
850 var call_numbers_by_siss_and_sdist = {};
852 var deferred = $q.defer();
853 var current_promise = deferred.promise;
856 var sitem_alerts = [];
857 var sdist_alerts = [];
858 var ssub_alerts = list[0].stream().distribution().subscription().notes().filter(function(n){
859 return n.alert() == 't';
863 angular.forEach(list, function(i) {
864 sitem_alerts = sitem_alerts.concat(
865 i.notes().filter(function(n){
866 return n.alert() == 't';
869 var sdist = '_'+i.stream().distribution().id();
870 if (!dist_seen[sdist]) {
871 dist_seen[sdist] = 1;
872 sdist_alerts = sdist_alerts.concat(
873 i.stream().distribution().notes().filter(function(n){
874 return n.alert() == 't';
880 if (do_barcode || bind) {
882 last_promise = current_promise.then(function(){ return $uibModal.open({
883 templateUrl: './serials/t_batch_receive',
885 windowClass: 'eg-wide-modal',
888 ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
890 $scope.print_routing_lists = print_rl;
891 $scope.barcode_items = do_barcode;
892 $scope.force_bind = bind;
895 $scope.ssub_alerts = ssub_alerts;
896 $scope.sdist_alerts = sdist_alerts;
897 $scope.sitem_alerts = sitem_alerts;
898 $scope.acn_list = [];
899 $scope.acnp_labels = [];
900 $scope.acns_labels = [];
901 $scope.acpl_list = [];
903 $scope.cannot_print = function (index) {
904 return $scope.items[index].stream().routing_list_users().length == 0 || ($scope.bind && index > 0);
907 $scope.bind_or_none = function (index) {
908 return !$scope.barcode_items || ($scope.bind && index > 0);
911 $scope.focus_next_barcode = function (index) {
913 $('#item_barcode_'+index).focus().select();
916 $scope.fullCNLabel = function (cn) {
917 var label = [cn.prefix.label,cn.label,cn.suffix.label].join(' ');
921 $scope.apply_template_overrides = function (e) {
922 if ($scope.selected_call_number) {
923 angular.forEach($scope.items, function (i) {
924 i._call_number = $scope.selected_call_number.label;
925 i._cn_prefix = $scope.selected_call_number.prefix.label;
926 i._cn_suffix = $scope.selected_call_number.suffix.label;
929 if ($scope.selected_circ_mod) {
930 angular.forEach($scope.items, function (i) {
931 i._circ_mod = $scope.selected_circ_mod;
934 if ($scope.selected_copy_location) {
935 angular.forEach($scope.items, function (i) {
936 i._copy_location = $scope.selected_copy_location;
941 $scope.ok = function(items) { $uibModalInstance.close(items) }
942 $scope.cancel = function () { $uibModalInstance.dismiss() }
945 var pile_o_promises = [$q.when()];
947 // let's gather what we need...
948 angular.forEach(list, function (i, index) {
949 var dlib = i.stream().distribution().holding_lib().id();
950 dist_libs[dlib] = egCore.org.fullPath(dlib, true);
952 i._barcode = i.unit().barcode();
953 pile_o_promises.push(
954 egCore.pcrud.retrieve(
955 'acn', i.unit().call_number(),
956 {flesh : 1, flesh_fields : {acn : ['prefix','suffix']}}
958 if (cn.deleted() == 'f') {
959 i._call_number = cn.label();
960 i._cn_prefix = cn.prefix().label();
961 i._cn_suffix = cn.suffix().label();
966 if (i.stream().distribution()[mode + '_call_number']() &&
967 i.stream().distribution()[mode + '_call_number']().deleted() == 'f'
969 i._call_number = i.stream().distribution()[mode + '_call_number']().label();
971 pile_o_promises.push(
972 service.fetchLastCallnumber(
973 i.stream().distribution().holding_lib().id()
976 i._call_number = cn.label();
977 i._cn_prefix = cn.prefix().label();
978 i._cn_suffix = cn.suffix().label();
985 if (i.stream().distribution()[mode + '_unit_template']()) {
986 i._copy_location = i.stream().distribution()[mode + '_unit_template']().location();
987 i._circ_mod = i.stream().distribution()[mode + '_unit_template']().circ_modifier();
990 if ($scope.print_routing_lists && !$scope.cannot_print(index))
991 i._print_routing_list = true;
996 // build unique list of orgs from distribution.holding_lib fullPaths
997 var dist_lib_list = [];
998 angular.forEach(dist_libs, function (l) {
999 dist_lib_list = dist_lib_list.concat(l);
1001 dist_lib_list = dist_lib_list.filter(function(v,i,s){
1002 return s.indexOf(v) == i;
1005 // Copy locations only come from the workstation location, same as XUL
1006 pile_o_promises.push(egCore.pcrud.search(
1008 {owning_lib : egCore.org.fullPath(egCore.auth.user().ws_ou(), true)},
1009 {},{ atomic : true }
1010 ).then(function (list) {
1011 $scope.acpl_list = list.map(function(i){return egCore.idl.toHash(i)});
1015 // Call numbers, however, come from anywhere the distributions might live
1016 pile_o_promises.push(egCore.pcrud.search(
1018 {deleted : 'f', record : bibId, owning_lib : dist_lib_list},
1019 {flesh : 1, flesh_fields : {acn : ['prefix','suffix']}},{ atomic : true }
1020 ).then(function (list) {
1021 $scope.acn_list = list.map(function(i){return egCore.idl.toHash(i)});
1025 // Likewise for prefix and suffix, for combo box
1026 angular.forEach(['acnp','acns'], function (cl) {
1027 pile_o_promises.push(egCore.pcrud.search(
1029 {owning_lib : dist_lib_list},
1030 {},{ atomic : true }
1031 ).then(function (list) {
1032 $scope[cl+'_labels'] = list.map(function(i){return i.label()});
1037 pile_o_promises.push(egCore.pcrud.retrieveAll(
1038 'ccm', {}, { atomic : true }
1039 ).then(function (list) {
1040 $scope.ccm_list = list.map(function(i){return egCore.idl.toHash(i)});
1044 $q.all(pile_o_promises).then(function() {
1045 console.log('receive data collected');
1048 $scope.$watch('barcode_items', function (n,o) {
1049 if (n === undefined || n == o) return;
1053 $scope.$watch('bind', function (n,o) {
1054 if (n === undefined || n == o) return;
1057 angular.forEach($scope.items, function (i,index) {
1058 if (index > 0) i._print_routing_list = false;
1063 $scope.$watch('auto_barcodes', function (n,o) {
1064 if (n === undefined || n == o) return;
1069 angular.forEach($scope.items, function (i) {
1070 if (!i.stream().distribution().receive_unit_template()) return;
1071 var _barcode = i._barcode;
1072 i._barcode = bc || i._old_barcode;
1073 i._old_barcode = _barcode;
1077 $scope.$watch('print_routing_lists', function (n,o) {
1078 if (n === undefined || n == o) return;
1080 angular.forEach($scope.items, function(i, index) {
1081 if (!$scope.cannot_print(index)) {
1082 i._print_routing_list = n;
1084 i._print_routing_list = false;
1091 last_promise = current_promise.then(function(){ return $uibModal.open({
1092 templateUrl: './serials/t_receive_alerts',
1095 ['$scope', '$uibModalInstance', function($scope, $uibModalInstance) {
1096 $scope.title = egCore.strings.CONFIRM_CHANGE_ITEMS[mode];
1097 $scope.items = list.length;
1100 $scope.ssub_alerts = ssub_alerts;
1101 $scope.sdist_alerts = sdist_alerts;
1102 $scope.sitem_alerts = sitem_alerts;
1104 $scope.ok = function(items) { $uibModalInstance.close(items) }
1105 $scope.cancel = function () { $uibModalInstance.dismiss() }
1109 angular.forEach(list, function (i, index) {
1112 return $q.when(list);
1117 last_promise.then(function (items) {
1120 if (mode == 'receive') {
1121 method = 'open-ils.serial.receive_items';
1122 items = items.filter(function(i){return i._receive});
1123 } else if ( mode == 'bind') {
1124 method = 'open-ils.serial.bind_items';
1125 items = items.filter(function(i){return i._receive});
1126 } else if ( mode == 'reset') {
1127 method = 'open-ils.serial.reset_items';
1130 if (!items.length) return $q.reject();
1132 var donor_unit_ids = {};
1133 angular.forEach(items, function(i, index) {
1134 if (i.unit()) donor_unit_ids[i.unit().id()] = 1;
1135 if (do_barcode) i.unit(-1);
1136 if (bind) i.unit(-2);
1137 copy_locations[i.id()] = i._copy_location;
1138 circ_mods[i.id()] = i._circ_mod;
1139 call_numbers[i.id()] = [i._cn_prefix, i._call_number, i._cn_suffix] || 'DEFAULT';
1140 barcodes[i.id()] = i._barcode || '@@AUTO';
1141 if (bind && index > 0) barcodes[i.id()] = items[0]._barcode;
1144 return egCore.net.request(
1145 'open-ils.serial', method,
1146 egCore.auth.token(), items, barcodes, call_numbers, donor_unit_ids,
1147 {circ_mods:circ_mods, copy_locations : copy_locations}
1150 var evt = egCore.evt.parse(resp);
1152 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
1154 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
1155 return service.print_routing_lists(bibId, items, do_barcode || bind, false, print_rl)
1160 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
1165 return deferred.resolve();
1168 service.add_issuances = function (mySsubId) {
1169 if (!mySsubId && service.subId) mySsubId = service.subId;
1170 if (!mySsubId) return $q.reject('fetchItemsForSub: no subscription id');
1172 var sub = service.get_ssub(mySsubId);
1173 if (!sub) return $q.reject('fetchItemsForSub: unknown subscription id');
1176 angular.forEach(sub.distributions(), function(dist) {
1179 function (stream) { return stream.id() }
1181 function (sid) { streams.push(sid) }
1186 order_by : [{class:'sitem',field:'date_expected',direction:'desc'}], // best aprox of pub date
1189 flesh_fields : { sitem : ['issuance'] }
1192 return egCore.pcrud.search(
1193 'sitem', {stream:streams},
1194 { order_by : [{class:'sitem',field:'date_expected',direction:'desc'}], // best aprox of pub date
1197 flesh_fields : { sitem : ['issuance'] }
1200 ).then(function(list) {
1201 var lastItem = list[0];
1203 if (lastItem) lastItem = lastItem.issuance();
1205 return service.new_holding_code({
1206 title : egCore.strings.SERIALS_ISSUANCE_PREDICT,
1207 request_count : true,
1208 prev_iss : lastItem,
1210 }).then(function(hc) {
1213 var include_base_iss = 0;
1214 if (!lastItem || hc.pattern_changed) {
1215 include_base_iss = 1;
1216 base_iss = new egCore.idl.siss();
1217 base_iss.creator( egCore.auth.user().id() );
1218 base_iss.editor( egCore.auth.user().id() );
1219 base_iss.date_published( hc.date.toISOString() );
1220 base_iss.subscription( mySsubId );
1221 base_iss.caption_and_pattern( hc.scap );
1222 base_iss.holding_code( JSON.stringify(hc.holding_code) );
1223 base_iss.holding_type( hc.type );
1226 // if we're predicting without a preexisting holding, reduce the count
1227 if (!lastItem) hc.count--;
1229 return egCore.net.request(
1231 'open-ils.serial.make_predictions',
1232 egCore.auth.token(),
1233 { ssub_id : mySsubId,
1234 include_base_issuance : include_base_iss,
1235 num_to_predict : hc.count,
1236 base_issuance : base_iss || lastItem
1240 var evt = egCore.evt.parse(resp);
1242 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);
1244 ngToast.success(egCore.strings.SERIALS_ISSUANCE_SUCCESS_SAVE);
1248 ngToast.danger(egCore.strings.SERIALS_ISSUANCE_FAIL_SAVE);