}
})
+.config(['ngToastProvider', function(ngToastProvider) {
+ ngToastProvider.configure({
+ verticalPosition: 'bottom',
+ animation: 'fade'
+ });
+}])
+
.config(function($routeProvider, $locationProvider, $compileProvider) {
$locationProvider.html5Mode(true);
- $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|blob):/); // grid export
-
+ $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|mailto|blob):/); // grid export
+
var resolver = {
delay : ['egStartup', function(egStartup) { return egStartup.go(); }]
};
+ $routeProvider.when('/cat/volcopy/edit_templates', {
+ templateUrl: './cat/volcopy/t_view',
+ controller: 'EditCtrl',
+ resolve : resolver
+ });
+
$routeProvider.when('/cat/volcopy/:dataKey', {
templateUrl: './cat/volcopy/t_view',
controller: 'EditCtrl',
);
};
- service.get_locations = function(orgs) {
+ service.get_copy_alert_types = function(orgs) {
+ return egCore.pcrud.search('ccat',
+ { active : 't' },
+ {},
+ { atomic : true }
+ );
+ };
+
+ service.get_copy_alerts = function(copy_id) {
+ return egCore.pcrud.search('aca', { copy : copy_id, ack_time : null },
+ { flesh : 1, flesh_fields : { aca : ['alert_type'] } },
+ { atomic : true }
+ );
+ };
+
+ service.get_locations_by_org = function(orgs) {
return egCore.pcrud.search('acpl',
- {owning_lib : orgs},
- {order_by : { acpl : 'name' }}, {atomic : true}
+ {owning_lib : orgs, deleted : 'f'},
+ {
+ flesh : 1,
+ flesh_fields : {
+ acpl : ['owning_lib']
+ },
+ order_by : { acpl : 'name' }
+ },
+ {atomic : true}
+ );
+ };
+
+ service.fetch_locations = function(locs) {
+ return egCore.pcrud.search('acpl',
+ {id : locs},
+ {
+ flesh : 1,
+ flesh_fields : {
+ acpl : ['owning_lib']
+ },
+ order_by : { acpl : 'name' }
+ },
+ {atomic : true}
);
};
};
+ service.get_magic_statuses = function() {
+ /* TODO: make these more configurable per lp1616170 */
+ return $q.when([
+ 1 /* Checked out */
+ ,3 /* Lost */
+ ,6 /* In transit */
+ ,8 /* On holds shelf */
+ ,16 /* Long overdue */
+ ,18 /* Canceled Transit */
+ ]);
+ }
+
service.get_statuses = function() {
if (egCore.env.ccs)
return $q.when(egCore.env.ccs.list);
};
+ service.get_acp_templates = function() {
+ // Already downloaded for this user? Return local copy. Changing users or logging out causes another download
+ // so users always have their own templates, and any changes made on other machines appear as expected.
+ if (egCore.hatch.getSessionItem('cat.copy.templates.usr') == egCore.auth.user().id()) {
+ return egCore.hatch.getItem('cat.copy.templates').then(function(templ) {
+ return templ;
+ });
+ } else {
+ // this can be disabled for debugging to force a re-download and translation of test templates
+ egCore.hatch.setSessionItem('cat.copy.templates.usr', egCore.auth.user().id());
+ return service.load_remote_acp_templates();
+ }
+
+ };
+
+ service.save_acp_templates = function(t) {
+ egCore.hatch.setItem('cat.copy.templates', t);
+ egCore.net.request('open-ils.actor', 'open-ils.actor.patron.settings.update',
+ egCore.auth.token(), egCore.auth.user().id(), { "webstaff.cat.copy.templates": t });
+ // console.warn('Saved ' + JSON.stringify({"webstaff.cat.copy.templates": t}));
+ };
+
+ service.load_remote_acp_templates = function() {
+ // After the XUL Client is completely removed everything related
+ // to staff_client.copy_editor.templates and convert_xul_templates
+ // can be thrown away.
+ return egCore.net.request('open-ils.actor', 'open-ils.actor.patron.settings.retrieve.authoritative',
+ egCore.auth.token(), egCore.auth.user().id(),
+ ['webstaff.cat.copy.templates','staff_client.copy_editor.templates']).then(function(settings) {
+ if (settings['webstaff.cat.copy.templates']) {
+ egCore.hatch.setItem('cat.copy.templates', settings['webstaff.cat.copy.templates']);
+ return settings['webstaff.cat.copy.templates'];
+ } else {
+ if (settings['staff_client.copy_editor.templates']) {
+ var new_templ = service.convert_xul_templates(settings['staff_client.copy_editor.templates']);
+ egCore.hatch.setItem('cat.copy.templates', new_templ);
+ // console.warn('Saving: ' + JSON.stringify({'webstaff.cat.copy.templates' : new_templ}));
+ egCore.net.request('open-ils.actor', 'open-ils.actor.patron.settings.update',
+ egCore.auth.token(), egCore.auth.user().id(), {'webstaff.cat.copy.templates' : new_templ});
+ return new_templ;
+ }
+ }
+ return {};
+ });
+ };
+
+ service.convert_xul_templates = function(xultempl) {
+ var conv_templ = {};
+ var templ_names = Object.keys(xultempl);
+ var name;
+ var xul_t;
+ var curr_templ;
+ var stat_cats;
+ var fields;
+ var curr_field;
+ var tmp_val;
+ var i, j;
+
+ if (templ_names) {
+ for (i=0; i < templ_names.length; i++) {
+ name = templ_names[i];
+ curr_templ = {};
+ stat_cats = {};
+ xul_t = xultempl[name];
+ fields = Object.keys(xul_t);
+
+ if (fields.length > 0) {
+ for (j=0; j < fields.length; j++) {
+ curr_field = xul_t[fields[j]];
+ var field_name = curr_field["field"];
+
+ if ( field_name == null ) { continue; }
+ if ( curr_field["value"] == "<HACK:KLUDGE:NULL>" ) { continue; }
+
+ // floating changed from a boolean to an integer at one point;
+ // take this opportunity to remove the boolean from any old templates
+ if ( curr_field["type"] === "attribute" && field_name === "floating" ) {
+ if ( curr_field["value"].match(/[tf]/) ) { continue; }
+ }
+
+ if ( curr_field["type"] === "stat_cat" ) {
+ stat_cats[field_name] = parseInt(curr_field["value"]);
+ } else {
+ tmp_val = curr_field['value'];
+ if ( tmp_val.toString().match(/^[-0-9.]+$/)) {
+ tmp_val = parseFloat(tmp_val);
+ }
+
+ if (field_name.match(/^batch_.*_menulist$/)) {
+ // special handling for volume fields
+ if (!("callnumber" in curr_templ)) curr_templ["callnumber"] = {};
+ if (field_name === "batch_class_menulist") curr_templ["callnumber"]["classification"] = tmp_val;
+ if (field_name === "batch_prefix_menulist") curr_templ["callnumber"]["prefix"] = tmp_val;
+ if (field_name === "batch_suffix_menulist") curr_templ["callnumber"]["suffix"] = tmp_val;
+ } else {
+ curr_templ[field_name] = tmp_val;
+ }
+ }
+ }
+
+ if ( (Object.keys(stat_cats)).length > 0 ) {
+ curr_templ["statcats"] = stat_cats;
+ }
+
+ conv_templ[name] = curr_templ;
+ }
+ }
+ }
+ return conv_templ;
+ };
+
service.flesh = {
flesh : 3,
flesh_fields : {
- acp : ['call_number','parts','stat_cat_entries', 'notes'],
- acn : ['label_class','prefix','suffix']
+ acp : ['call_number','parts','stat_cat_entries', 'notes', 'tags'],
+ acn : ['label_class','prefix','suffix'],
+ acptcm : ['tag']
}
}
if (!cp.parts()) cp.parts([]); // just in case...
+ service.get_copy_alerts(cp.id()).then(function(aca) {
+ cp.copy_alerts(aca);
+ });
+
var lib = cp.call_number().owning_lib();
var cn = cp.call_number().id();
service.copies.push(cp);
}
+ service.checkDuplicateBarcode = function(bc, id) {
+ var final = false;
+ return egCore.pcrud.search('acp', { deleted : 'f', 'barcode' : bc, id : { '!=' : id } })
+ .then(
+ function () { return final },
+ function () { return final },
+ function () { final = true; }
+ );
+ }
+
service.fetchIds = function(idList) {
service.tree = {}; // clear the tree on fetch
service.copies = []; // clear the copy list on fetch
);
}
+ // create a new acp object with default values
+ // (both hard-coded and coming from OU settings)
+ service.generateNewCopy = function(callNumber, owningLib, isFastAdd, isNew) {
+ var cp = new egCore.idl.acp();
+ cp.id( --service.new_cp_id );
+ if (isNew) {
+ cp.isnew( true );
+ }
+ cp.circ_lib( owningLib );
+ cp.call_number( callNumber );
+ cp.deposit(0);
+ cp.price(0);
+ cp.deposit_amount(0);
+ cp.fine_level(2); // Normal
+ cp.loan_duration(2); // Normal
+ cp.location(1); // Stacks
+ cp.circulate('t');
+ cp.holdable('t');
+ cp.opac_visible('t');
+ cp.ref('f');
+ cp.mint_condition('t');
+ cp.empty_barcode = true;
+
+ var status_setting = isFastAdd ?
+ 'cat.default_copy_status_fast' :
+ 'cat.default_copy_status_normal';
+ egCore.org.settings(
+ [status_setting],
+ owningLib
+ ).then(function(set) {
+ var default_ccs = parseInt(set[status_setting]);
+ if (isNaN(default_ccs))
+ default_ccs = (isFastAdd ? 0 : 5); // 0 is Available, 5 is In Process
+ cp.status(default_ccs);
+ });
+
+ return cp;
+ }
+
return service;
}])
'<input id="{{callNumber.id()}}_{{copy.id()}}"'+
' eg-enter="nextBarcode(copy.id())" class="form-control"'+
' type="text" ng-model="barcode" ng-change="updateBarcode()"/>'+
+ '<div class="label label-danger" ng-if="duplicate_barcode">{{duplicate_barcode_string}}</div>'+
+ '<div class="label label-danger" ng-if="empty_barcode">{{empty_barcode_string}}</div>'+
'</div>'+
- '<div class="col-xs-3"><input class="form-control" type="number" ng-model="copy_number" ng-change="updateCopyNo()"/></div>'+
- '<div class="col-xs-4"><eg-basic-combo-box eg-disabled="record == 0" list="parts" selected="part"></eg-basic-combo-box></div>'+
+ '<div class="col-xs-3"><input class="form-control" type="number" min="1" ng-model="copy_number" ng-change="updateCopyNo()"/></div>'+
+ '<div class="col-xs-3"><eg-basic-combo-box list="parts" selected="part"></eg-basic-combo-box></div>'+
'</div>',
scope: { focusNext: "=", copy: "=", callNumber: "=", index: "@", record: "@" },
function ( $scope , itemSvc , egCore ) {
$scope.new_part_id = 0;
$scope.barcode_has_error = false;
+ $scope.duplicate_barcode = false;
+ $scope.empty_barcode = false;
+ $scope.duplicate_barcode_string = window.duplicate_barcode_string;
+ $scope.empty_barcode_string = window.empty_barcode_string;
+
+ if (!$scope.copy.barcode()) $scope.copy.empty_barcode = true;
$scope.nextBarcode = function (i) {
$scope.focusNext(i, $scope.barcode);
}
$scope.updateBarcode = function () {
- if ($scope.barcode != '')
+ if ($scope.barcode != '') {
+ $scope.copy.empty_barcode = $scope.empty_barcode = false;
$scope.barcode_has_error = !Boolean(itemSvc.checkBarcode($scope.barcode));
+ itemSvc.checkDuplicateBarcode($scope.barcode, $scope.copy.id())
+ .then(function (state) { $scope.copy.duplicate_barcode = $scope.duplicate_barcode = state });
+ } else {
+ $scope.copy.empty_barcode = $scope.empty_barcode = true;
+ }
+
$scope.copy.barcode($scope.barcode);
$scope.copy.ischanged(1);
if (itemSvc.currently_generating)
} else {
$scope.copy.parts([]);
}
+ $scope.copy.ischanged(1);
}
- $scope.$watch('part', $scope.updatePart);
-
- $scope.barcode = $scope.copy.barcode();
- $scope.copy_number = $scope.copy.copy_number();
-
- if ($scope.copy.parts()) {
- $scope.part = $scope.copy.parts()[0];
- if ($scope.part) $scope.part = $scope.part.label();
- };
$scope.parts = [];
$scope.part_list = [];
- itemSvc.get_parts($scope.callNumber.record()).then(function(list){
+ itemSvc.get_parts($scope.callNumber.record())
+ .then(function(list){
$scope.part_list = list;
angular.forEach(list, function(p){ $scope.parts.push(p.label()) });
$scope.parts = angular.copy($scope.parts);
+
+ $scope.$watch('part', $scope.updatePart);
+ if ($scope.copy.parts()) {
+ var the_part = $scope.copy.parts()[0];
+ if (the_part) $scope.part = the_part.label();
+ };
});
+ $scope.barcode = $scope.copy.barcode();
+ $scope.copy_number = $scope.copy.copy_number();
+
}
]
template:
'<div class="row">'+
'<div class="col-xs-2">'+
- '<select ng-disabled="record == 0" class="form-control" ng-model="classification" ng-change="updateClassification()" ng-options="cl.name() for cl in classification_list"/>'+
+ '<button aria-label="Delete" style="margin:-5px -15px; float:left;" ng-hide="callNumber.not_ephemeral" type="button" class="close" ng-click="removeCN()">×</button>' +
+ '<select class="form-control" ng-model="classification" ng-change="updateClassification()" ng-options="cl.name() for cl in classification_list"/>'+
'</div>'+
'<div class="col-xs-1">'+
- '<select ng-disabled="record == 0" class="form-control" ng-model="prefix" ng-change="updatePrefix()" ng-options="p.label() for p in prefix_list"/>'+
+ '<select class="form-control" ng-model="prefix" ng-change="updatePrefix()" ng-options="p.label() for p in prefix_list"/>'+
+ '</div>'+
+ '<div class="col-xs-2">'+
+ '<input class="form-control" type="text" ng-change="updateLabel()" ng-model="label"/>'+
+ '<div class="label label-danger" ng-if="empty_label">{{empty_label_string}}</div>'+
'</div>'+
- '<div class="col-xs-2"><input ng-disabled="record == 0" class="form-control" type="text" ng-change="updateLabel()" ng-model="label"/></div>'+
'<div class="col-xs-1">'+
- '<select ng-disabled="record == 0" class="form-control" ng-model="suffix" ng-change="updateSuffix()" ng-options="s.label() for s in suffix_list"/>'+
+ '<select class="form-control" ng-model="suffix" ng-change="updateSuffix()" ng-options="s.label() for s in suffix_list"/>'+
'</div>'+
- '<div ng-hide="onlyVols" class="col-xs-1"><input ng-disabled="record == 0" class="form-control" type="number" ng-model="copy_count" min="{{orig_copy_count}}" ng-change="changeCPCount()"></div>'+
+ '<div ng-hide="onlyVols" class="col-xs-1"><input class="form-control" type="number" ng-model="copy_count" min="{{orig_copy_count}}" ng-change="changeCPCount()"></div>'+
'<div ng-hide="onlyVols" class="col-xs-5">'+
'<eg-vol-copy-edit record="{{record}}" ng-repeat="cp in copies track by idTracker(cp)" focus-next="focusNextBarcode" copy="cp" call-number="callNumber"></eg-vol-copy-edit>'+
'</div>'+
'</div>',
- scope: {focusNext: "=", allcopies: "=", copies: "=", onlyVols: "=", record: "@" },
+ scope: {focusNext: "=", allcopies: "=", copies: "=", onlyVols: "=", record: "@", struct:"=" },
controller : ['$scope','itemSvc','egCore',
function ( $scope , itemSvc , egCore ) {
$scope.callNumber = $scope.copies[0].call_number();
+ if (!$scope.callNumber.label()) $scope.callNumber.empty_label = true;
+
+ $scope.empty_label = false;
+ $scope.empty_label_string = window.empty_label_string;
$scope.idTracker = function (x) { if (x && x.id) return x.id() };
$scope.$watch('callNumber.label()', function (v) {
$scope.label = v;
+ if ($scope.label == '') {
+ $scope.callNumber.empty_label = $scope.empty_label = true;
+ } else {
+ $scope.callNumber.empty_label = $scope.empty_label = false;
+ }
});
$scope.prefix = $scope.callNumber.prefix();
$scope.copy_count = $scope.copies.length;
$scope.orig_copy_count = $scope.copy_count;
+ $scope.removeCN = function(){
+ var cn = $scope.callNumber;
+ if (cn.not_ephemeral) return; // can't delete existing volumes
+
+ angular.forEach(Object.keys($scope.struct), function(k){
+ angular.forEach($scope.struct[k], function(cp){
+ var struct_cn = cp.call_number();
+ if (struct_cn.id() == cn.id()){
+ console.log("X'ed CN id" + cn.id() + " and struct CN id match!");
+ // remove any copies in $scope.struct[k]
+ angular.forEach($scope.copies, function(c){
+ var idx = $scope.allcopies.indexOf(c);
+ $scope.allcopies.splice(idx, 1);
+ });
+
+ $scope.copies = [];
+ // remove added vol:
+ delete $scope.struct[k];
+ }
+ });
+ });
+
+ // manually decrease cn_count numeric input
+ var cn_spinner = $("input[name='cn_count_lib"+ cn.owning_lib() +"']");
+ if (cn_spinner.val() > 0) cn_spinner.val(parseInt(cn_spinner.val()) - 1);
+ cn_spinner.trigger("change");
+
+ }
+
$scope.changeCPCount = function () {
while ($scope.copy_count > $scope.copies.length) {
- var cp = new egCore.idl.acp();
- cp.id( --itemSvc.new_cp_id );
- cp.isnew( true );
- cp.circ_lib( $scope.callNumber.owning_lib() );
- cp.call_number( $scope.callNumber );
- cp.deposit(0);
- cp.price(0);
- cp.deposit_amount(0);
- cp.fine_level(2); // Normal
- cp.loan_duration(2); // Normal
- cp.location(1); // Stacks
- cp.circulate('t');
- cp.holdable('t');
- cp.opac_visible('t');
- cp.ref('f');
- cp.mint_condition('t');
+ var cp = itemSvc.generateNewCopy(
+ $scope.callNumber,
+ $scope.callNumber.owning_lib(),
+ $scope.fast_add,
+ true
+ );
$scope.copies.push( cp );
$scope.allcopies.push( cp );
replace: true,
template:
'<div class="row">'+
- '<div class="col-xs-1"><eg-org-selector alldisabled="{{record == 0}}" selected="owning_lib" disable-test="cant_have_vols"></eg-org-selector></div>'+
- '<div class="col-xs-1"><input ng-disabled="record == 0" class="form-control" type="number" min="{{orig_cn_count}}" ng-model="cn_count" ng-change="changeCNCount()"/></div>'+
+ '<div class="col-xs-1"><eg-org-selector selected="owning_lib" disable-test="cant_have_vols"></eg-org-selector></div>'+
+ '<div class="col-xs-1"><input class="form-control" type="number" min="{{orig_cn_count}}" ng-model="cn_count" ng-change="changeCNCount()"/></div>'+
'<div class="col-xs-10">'+
'<eg-vol-row only-vols="onlyVols" record="{{record}}"'+
- 'ng-repeat="(cn,copies) in struct | orderBy:cn track by cn" '+
- 'focus-next="focusNextFirst" copies="copies" allcopies="allcopies">'+
+ 'ng-repeat="(cn,copies) in struct" '+
+ 'focus-next="focusNextFirst" copies="copies" allcopies="allcopies" struct="struct">'+
'</eg-vol-row>'+
'</div>'+
'</div>',
cn.owning_lib( $scope.owning_lib.id() );
cn.record( $scope.full_cn.record() );
- var cp = new egCore.idl.acp();
- cp.call_number( cn );
- cp.id( --itemSvc.new_cp_id );
- cp.isnew( true );
-
- cp.deposit(0);
- cp.price(0);
- cp.deposit_amount(0);
- cp.fine_level(2); // Normal
- cp.loan_duration(2); // Normal
- cp.location(1); // Stacks
- cp.circulate('t');
- cp.holdable('t');
- cp.opac_visible('t');
- cp.ref('f');
- cp.mint_condition('t');
-
- cp.circ_lib( $scope.owning_lib.id() );
- cp.call_number( cn );
+ var cp = itemSvc.generateNewCopy(
+ cn,
+ $scope.owning_lib.id(),
+ $scope.fast_add,
+ true
+ );
$scope.struct[cn.id()] = [cp];
$scope.allcopies.push(cp);
+ if (!$scope.defaults.classification) {
+ egCore.org.settings(
+ ['cat.default_classification_scheme'],
+ cn.owning_lib()
+ ).then(function (val) {
+ cn.label_class(val['cat.default_classification_scheme']);
+ });
+ }
}
} else if (n < o && n >= $scope.orig_cn_count) { // removing
var how_many = o - n;
* Edit controller!
*/
.controller('EditCtrl',
- ['$scope','$q','$window','$routeParams','$location','$timeout','egCore','egNet','egGridDataProvider','itemSvc','$modal',
-function($scope , $q , $window , $routeParams , $location , $timeout , egCore , egNet , egGridDataProvider , itemSvc , $modal) {
+ ['$scope','$q','$window','$routeParams','$location','$timeout','egCore','egNet','egGridDataProvider','itemSvc','$uibModal',
+function($scope , $q , $window , $routeParams , $location , $timeout , egCore , egNet , egGridDataProvider , itemSvc , $uibModal) {
+
+ $scope.forms = {}; // Accessed by t_attr_edit.tt2
+ $scope.i18n = egCore.i18n;
$scope.defaults = { // If defaults are not set at all, allow everything
barcode_checkdigit : false,
auto_gen_barcode : false,
statcats : true,
copy_notes : true,
+ copy_tags : true,
attributes : {
status : true,
loan_duration : true,
location : true,
holdable : true,
age_protect : true,
- floating : true
+ floating : true,
+ alerts : true
}
};
+ $scope.new_lib_to_add = egCore.org.get(egCore.auth.user().ws_ou());
+ $scope.changeNewLib = function (org) {
+ $scope.new_lib_to_add = org;
+ }
+ $scope.addLibToStruct = function () {
+ var newLib = $scope.new_lib_to_add;
+ var cn = new egCore.idl.acn();
+ cn.id( --itemSvc.new_cn_id );
+ cn.isnew( true );
+ cn.prefix( $scope.defaults.prefix || -1 );
+ cn.suffix( $scope.defaults.suffix || -1 );
+ cn.label_class( $scope.defaults.classification || 1 );
+ cn.owning_lib( newLib.id() );
+ cn.record( $scope.record_id );
+
+ var cp = itemSvc.generateNewCopy(
+ cn,
+ newLib.id(),
+ $scope.fast_add,
+ true
+ );
+
+ $scope.data.addCopy(cp);
+
+ // manually increase cn_count numeric input
+ var cn_spinner = $("input[name='cn_count_lib"+ newLib.id() +"']");
+ cn_spinner.val(parseInt(cn_spinner.val()) + 1);
+ cn_spinner.trigger("change");
+
+ if (!$scope.defaults.classification) {
+ egCore.org.settings(
+ ['cat.default_classification_scheme'],
+ cn.owning_lib()
+ ).then(function (val) {
+ cn.label_class(val['cat.default_classification_scheme']);
+ });
+ }
+ }
+
$scope.embedded = ($routeParams.mode && $routeParams.mode == 'embedded') ? true : false;
+ $scope.edit_templates = ($location.path().match(/edit_template/)) ? true : false;
$scope.saveDefaults = function () {
egCore.hatch.setItem('cat.copy.defaults', $scope.defaults);
$scope.batch.prefix = $scope.defaults.prefix;
$scope.batch.suffix = $scope.defaults.suffix;
$scope.working.statcat_filter = $scope.defaults.statcat_filter;
+ if (
+ typeof $scope.defaults.statcat_filter == 'object' &&
+ Object.keys($scope.defaults.statcat_filter).length > 0
+ ) {
+ // want fieldmapper object here...
+ $scope.defaults.statcat_filter =
+ egCore.idl.Clone($scope.defaults.statcat_filter);
+ // ... and ID here
+ $scope.working.statcat_filter = $scope.defaults.statcat_filter.id();
+ }
if ($scope.defaults.always_volumes) $scope.show_vols = true;
if ($scope.defaults.barcode_checkdigit) itemSvc.barcode_checkdigit = true;
if ($scope.defaults.auto_gen_barcode) itemSvc.auto_gen_barcode = true;
}
$scope.fetchDefaults();
+ $scope.$watch('defaults.statcat_filter', function() {
+ $scope.saveDefaults();
+ });
$scope.$watch('defaults.auto_gen_barcode', function (n,o) {
itemSvc.auto_gen_barcode = n
});
return true;
}
- createSimpleUpdateWatcher = function (field) {
+ createSimpleUpdateWatcher = function (field,exclude_copies_with_one_of_these_values) {
return $scope.$watch('working.' + field, function () {
var newval = $scope.working[field];
if (typeof newval != 'undefined') {
+ delete $scope.working.MultiMap[field];
if (angular.isObject(newval)) { // we'll use the pkey
if (newval.id) newval = newval.id();
else if (newval.code) newval = newval.code();
angular.forEach(
$scope.workingGridControls.selectedItems(),
function (cp) {
+ if (exclude_copies_with_one_of_these_values
+ && exclude_copies_with_one_of_these_values.indexOf(cp[field](),0) > -1) {
+ return;
+ }
if (cp[field]() !== newval) {
cp[field](newval);
cp.ischanged(1);
}
$scope.working = {
+ MultiMap: {},
statcats: {},
+ statcats_multi: {},
statcat_filter: undefined
};
+ // Returns true if we are editing multiple copies and at least
+ // one field contains multiple values.
+ $scope.hasMulti = function() {
+ var keys = Object.keys($scope.working.MultiMap);
+ // for-loop for shortcut exit
+ for (var i = 0; i < keys.length; i++) {
+ if ($scope.working.MultiMap[keys[i]].length > 1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ $scope.copyAlertUpdate = function (alerts) {
+ if (!$scope.in_item_select &&
+ $scope.workingGridControls &&
+ $scope.workingGridControls.selectedItems) {
+ itemSvc.get_copy_alert_types().then(function(ccat) {
+ var ccat_map = {};
+ $scope.alert_types = ccat;
+ angular.forEach(ccat, function(t) {
+ ccat_map[t.id()] = t;
+ });
+ angular.forEach(
+ $scope.workingGridControls.selectedItems(),
+ function (cp) {
+ $scope.dirty = true;
+ angular.forEach(alerts, function(alrt) {
+ var a = egCore.idl.fromHash('aca', alrt);
+ a.isnew(1);
+ a.create_staff(egCore.auth.user().id());
+ a.alert_type(ccat_map[a.alert_type()]);
+ a.ack_time(null);
+ a.copy(cp.id());
+ cp.copy_alerts().push( a );
+ });
+ cp.ischanged(1);
+ }
+ );
+ });
+ }
+ };
+
+ $scope.copyNoteUpdate = function (notes) {
+ if (!$scope.in_item_select &&
+ $scope.workingGridControls &&
+ $scope.workingGridControls.selectedItems) {
+ angular.forEach(
+ $scope.workingGridControls.selectedItems(),
+ function (cp) {
+ $scope.dirty = true;
+ angular.forEach(notes, function(note) {
+ var n = egCore.idl.fromHash('acpn', note);
+ n.isnew(1);
+ n.creator(egCore.auth.user().id());
+ n.owning_copy(cp.id());
+ cp.notes().push( n );
+ });
+ cp.ischanged(1);
+ }
+ );
+
+ }
+ }
+
$scope.statcatUpdate = function (id) {
var newval = $scope.working.statcats[id];
);
if (newval) {
- var e = new egCore.idl.ascecm();
+ var e = new egCore.idl.asce();
e.isnew( 1 );
- e.owning_copy( cp.id() );
e.stat_cat( id );
- e.stat_cat_entry( newval );
+ e.id(newval);
cp.stat_cat_entries(
- cp.stat_cat_entries().concat([ e ])
+ cp.stat_cat_entries() ?
+ cp.stat_cat_entries().concat([ e ]) :
+ [ e ]
);
}
- cp.stat_cat_entries( // trim out ephemeral deleted ones
+ // trim out all deleted ones; the API used to
+ // do the update doesn't actually consult
+ // isdeleted for stat cat entries
+ cp.stat_cat_entries(
cp.stat_cat_entries().filter(function (e) {
- if (Boolean(e.isnew())) {
- if (Boolean(e.isdeleted())) {
- return false;
- }
- }
- return true;
+ return !Boolean(e.isdeleted());
})
);
var dataKey = $routeParams.dataKey;
console.debug('dataKey: ' + dataKey);
- if (dataKey && dataKey.length > 0) {
+ if ((dataKey && dataKey.length > 0) || $scope.edit_templates) {
$scope.templates = {};
$scope.template_name = '';
$scope.template_name_list = [];
$scope.fetchTemplates = function () {
- egCore.hatch.getItem('cat.copy.templates').then(function(t) {
+ itemSvc.get_acp_templates().then(function(t) {
if (t) {
$scope.templates = t;
- $scope.template_name_list = Object.keys(t);
+ $scope.template_name_list = Object.keys(t).sort();
}
});
egCore.hatch.getItem('cat.copy.last_template').then(function(t) {
angular.forEach($scope.templates[n], function (v,k) {
if (k == 'circ_lib') {
$scope.working[k] = egCore.org.get(v);
+ } else if (k == 'copy_notes' && v.length) {
+ $scope.copyNoteUpdate(v);
+ } else if (k == 'copy_alerts' && v.length) {
+ $scope.copyAlertUpdate(v);
} else if (!angular.isObject(v)) {
$scope.working[k] = angular.copy(v);
} else {
}
});
}
+ delete $scope.working.MultiMap[k];
});
egCore.hatch.setItem('cat.copy.last_template', n);
}
$scope.add_vols_copies = false;
$scope.is_fast_add = false;
+ // Generate some functions for selecting items by column value in the working grid
+ angular.forEach(
+ ['circulate','status','circ_lib','ref','location','opac_visible','circ_modifier','price',
+ 'loan_duration','cost','circ_as_type','deposit','holdable','deposit_amount','age_protect',
+ 'mint_condition','fine_level','floating'],
+ function (field) {
+ $scope['select_by_' + field] = function (x) {
+ $scope.workingGridControls.selectItemsByValue(field,x);
+ }
+ }
+ );
+
+ var truthy = /^t|1/;
+ $scope.labelYesNo = function (x) {
+ return truthy.test(x) ? egCore.strings.YES : egCore.strings.NO;
+ }
+
+ $scope.orgShortname = function (x) {
+ return egCore.org.get(x).shortname();
+ }
+
+ $scope.statusName = function (x) {
+ var s = $scope.status_list.filter(function(y) {
+ return y.id() == x;
+ });
+
+ return s[0].name();
+ }
+
+ $scope.locationName = function (x) {
+ var s = $scope.location_list.filter(function(y) {
+ return y.id() == x;
+ });
+
+ return $scope.i18n.ou_qualified_location_name(s[0]);
+ }
+
+ $scope.durationLabel = function (x) {
+ return [egCore.strings.SHORT, egCore.strings.NORMAL, egCore.strings.EXTENDED][-1 + x]
+ }
+
+ $scope.fineLabel = function (x) {
+ return [egCore.strings.LOW, egCore.strings.NORMAL, egCore.strings.HIGH][-1 + x]
+ }
+
+ $scope.circTypeValue = function (x) {
+ if (x === null) return egCore.strings.UNSET;
+ var s = $scope.circ_type_list.filter(function(y) {
+ return y.code() == x;
+ });
+
+ return s[0].value();
+ }
+
+ $scope.ageprotectName = function (x) {
+ if (x === null) return egCore.strings.UNSET;
+ var s = $scope.age_protect_list.filter(function(y) {
+ return y.id() == x;
+ });
+
+ return s[0].name();
+ }
+
+ $scope.floatingName = function (x) {
+ if (x === null) return egCore.strings.UNSET;
+ var s = $scope.floating_list.filter(function(y) {
+ return y.id() == x;
+ });
+
+ return s[0].name();
+ }
+
+ $scope.circmodName = function (x) {
+ if (x === null) return egCore.strings.UNSET;
+ var s = $scope.circ_modifier_list.filter(function(y) {
+ return y.code() == x;
+ });
+
+ return s[0].name();
+ }
+
egNet.request(
'open-ils.actor',
'open-ils.actor.anon_cache.get_value',
/* data.raw data structure looks like this:
* [{
* callnumber : $cn_id, // optional, to add a copy to a cn
- * owner : $org, // optional, defaults to ws_ou
+ * owner : $org, // optional, defaults to cn.owning_lib or ws_ou
* label : $cn_label, // optional, to supply a label on a new cn
* barcode : $cp_barcode // optional, to supply a barcode on a new cp
* fast_add : boolean // optional, to specify whether this came
* All can be left out and a completely empty vol/copy combo will be vivicated.
*/
+ var promises = [];
angular.forEach(
data.raw,
function (proto) {
if (proto.fast_add) $scope.is_fast_add = true;
if (proto.callnumber) {
- return egCore.pcrud.retrieve('acn', proto.callnumber)
+ promises.push(egCore.pcrud.retrieve('acn', proto.callnumber)
.then(function(cn) {
- var cp = new egCore.idl.acp();
- cp.call_number( cn );
- cp.id( --itemSvc.new_cp_id );
- if (!$scope.only_vols) cp.isnew( true );
- cp.circ_lib( proto.owner || egCore.auth.user().ws_ou() );
-
- cp.deposit(0);
- cp.price(0);
- cp.deposit_amount(0);
- cp.fine_level(2); // Normal
- cp.loan_duration(2); // Normal
- cp.location(1); // Stacks
- cp.circulate('t');
- cp.holdable('t');
- cp.opac_visible('t');
- cp.ref('f');
- cp.mint_condition('t');
-
- if (proto.barcode) cp.barcode( proto.barcode );
+ var cp = new itemSvc.generateNewCopy(
+ cn,
+ proto.owner || cn.owning_lib(),
+ $scope.is_fast_add,
+ ((!$scope.only_vols) ? true : false)
+ );
+
+ if (proto.barcode) {
+ cp.barcode( proto.barcode );
+ cp.empty_barcode = false;
+ }
itemSvc.addCopy(cp)
- });
+ }));
} else {
var cn = new egCore.idl.acn();
cn.id( --itemSvc.new_cn_id );
cn.isnew( true );
cn.prefix( $scope.defaults.prefix || -1 );
cn.suffix( $scope.defaults.suffix || -1 );
- cn.label_class( $scope.defaults.classification || 1 );
cn.owning_lib( proto.owner || egCore.auth.user().ws_ou() );
cn.record( $scope.record_id );
- if (proto.label) cn.label( proto.label );
-
- var cp = new egCore.idl.acp();
- cp.call_number( cn );
- cp.id( --itemSvc.new_cp_id );
- cp.isnew( true );
-
- cp.deposit(0);
- cp.price(0);
- cp.deposit_amount(0);
- cp.fine_level(2); // Normal
- cp.loan_duration(2); // Normal
- cp.location(1); // Stacks
- cp.circulate('t');
- cp.holdable('t');
- cp.opac_visible('t');
- cp.ref('f');
- cp.mint_condition('t');
-
- cp.circ_lib( proto.owner || egCore.auth.user().ws_ou() );
- if (proto.barcode) cp.barcode( proto.barcode );
+ egCore.org.settings(
+ ['cat.default_classification_scheme'],
+ cn.owning_lib()
+ ).then(function (val) {
+ cn.label_class(
+ $scope.defaults.classification ||
+ val['cat.default_classification_scheme'] ||
+ 1
+ );
+ if (proto.label) {
+ cn.label( proto.label );
+ } else {
+ egCore.net.request(
+ 'open-ils.cat',
+ 'open-ils.cat.biblio.record.marc_cn.retrieve',
+ $scope.record_id,
+ cn.label_class()
+ ).then(function(cn_array) {
+ if (cn_array.length > 0) {
+ for (var field in cn_array[0]) {
+ cn.label( cn_array[0][field] );
+ break;
+ }
+ }
+ });
+ }
+ });
+
+ // If we are adding an empty vol,
+ // this is ultimately just a placeholder copy
+ // which gets removed before saving.
+ // TODO: consider ways to remove this
+ // requirement
+ var cp = new itemSvc.generateNewCopy(
+ cn,
+ proto.owner || cn.owning_lib(),
+ $scope.is_fast_add,
+ true
+ );
+
+ if (proto.barcode) {
+ cp.barcode( proto.barcode );
+ cp.empty_barcode = false;
+ }
itemSvc.addCopy(cp)
}
-
}
);
- return itemSvc.copies;
+ angular.forEach(itemSvc.copies, function(c){
+ var cn = c.call_number();
+ var copy_id = c.id();
+ if (copy_id > 0){
+ cn.not_ephemeral = true;
+ }
+ });
+
+ return $q.all(promises);
}
if (data.copies && data.copies.length)
}
}).then( function() {
- $scope.data = itemSvc;
- if ($scope.add_vols_copies) {
- var status_setting = $scope.is_fast_add ?
- 'cat.default_copy_status_fast' :
- 'cat.default_copy_status_normal';
- egCore.org.settings([
- status_setting
- ]).then(function(set) {
- $scope.default_ccs = set[status_setting] ||
- ($scope.is_fast_add ? 0 : 5); // 0 is Available, 5 is In Process
- angular.forEach($scope.data.copies, function (cp) {
- cp.status($scope.default_ccs);
- });
- $scope.workingGridDataProvider.refresh();
- });
- }
+
+ return itemSvc.fetch_locations(
+ itemSvc.copies.map(function(cp){
+ return cp.location();
+ }).filter(function(e,i,a){
+ return a.lastIndexOf(e) === i;
+ })
+ ).then(function(list){
+ $scope.data = itemSvc;
+ $scope.location_list = list;
+ $scope.workingGridDataProvider.refresh();
+ });
+
});
+ $scope.can_save = false;
+ function check_saveable () {
+ var can_save = true;
+
+ angular.forEach(
+ itemSvc.copies,
+ function (i) {
+ if (!$scope.only_vols) {
+ if (i.duplicate_barcode || i.empty_barcode || i.call_number().empty_label) {
+ can_save = false;
+ }
+ } else if (i.call_number().empty_label) {
+ can_save = false;
+ }
+ }
+ );
+
+ if (!$scope.only_vols && $scope.forms.myForm && $scope.forms.myForm.$invalid) {
+ can_save = false;
+ }
+
+ $scope.can_save = can_save;
+ }
+
+ $scope.disableSave = function () {
+ check_saveable();
+ return !$scope.can_save;
+ }
+
$scope.focusNextFirst = function(prev_lib,prev_bc) {
var n;
var yep = false;
angular.forEach(Object.keys($scope.defaults.attributes), function (attr) {
var value_hash = {};
+ var value_list = [];
angular.forEach(item_list, function (item) {
if (item[attr]) {
var v = item[attr]()
if (v.id) v = v.id();
else if (v.code) v = v.code();
}
+ value_list.push(v);
value_hash[v] = 1;
}
});
+ $scope.working.MultiMap[attr] = value_list;
+
if (Object.keys(value_hash).length == 1) {
if (attr == 'circ_lib') {
$scope.working[attr] = egCore.org.get(item_list[0][attr]());
});
if (right_sc.length > 0) {
- value_hash[right_sc[0].stat_cat_entry()] = right_sc[0].stat_cat_entry();
+ value_hash[right_sc[0].id()] = right_sc[0].id();
} else {
none = true;
}
+ } else {
+ none = true;
}
} else {
none = true;
if (!none && Object.keys(value_hash).length == 1) {
$scope.working.statcats[sc.id()] = value_hash[Object.keys(value_hash)[0]];
+ $scope.working.statcats_multi[sc.id()] = false;
+ } else if (item_list.length > 1 && Object.keys(value_hash).length > 0) {
+ $scope.working.statcats[sc.id()] = undefined;
+ $scope.working.statcats_multi[sc.id()] = true;
} else {
$scope.working.statcats[sc.id()] = undefined;
+ $scope.working.statcats_multi[sc.id()] = false;
}
+
});
} else {
$scope.$watch('data.copies.length', function () {
if ($scope.data.copies) {
var base_orgs = $scope.data.copies.map(function(cp){
- return cp.circ_lib()
+ if (isNaN(cp.circ_lib())) return Number(cp.circ_lib().id());
+ return Number(cp.circ_lib());
}).concat(
$scope.data.copies.map(function(cp){
- return cp.call_number().owning_lib()
+ if (isNaN(cp.call_number().owning_lib())) return Number(cp.call_number().owning_lib().id());
+ return Number(cp.call_number().owning_lib());
})
).concat(
[egCore.auth.user().ws_ou()]
var final_orgs = all_orgs.filter(function(e,i,a){
return a.lastIndexOf(e) === i;
- }).sort(function(a, b){return parseInt(a)-parseInt(b)});
+ }).sort(function(a, b){return a-b});
if ($scope.location_orgs.toString() != final_orgs.toString()) {
$scope.location_orgs = final_orgs;
if ($scope.location_orgs.length) {
- itemSvc.get_locations($scope.location_orgs).then(function(list){
+ itemSvc.get_locations_by_org($scope.location_orgs).then(function(list){
angular.forEach(list, function(l) {
$scope.location_cache[ ''+l.id() ] = l;
});
$scope.location_list = list;
- });
-
- $scope.statcat_filter_list = [];
- angular.forEach($scope.location_orgs, function (o) {
- $scope.statcat_filter_list.push(egCore.org.get(o));
- });
+ }).then(function() {
+ $scope.statcat_filter_list = [];
+ angular.forEach($scope.location_orgs, function (o) {
+ $scope.statcat_filter_list.push(egCore.org.get(o));
+ });
- itemSvc.get_statcats($scope.location_orgs).then(function(list){
- $scope.statcats = list;
- angular.forEach($scope.statcats, function (s) {
+ itemSvc.get_statcats($scope.location_orgs).then(function(list){
+ $scope.statcats = list;
+ angular.forEach($scope.statcats, function (s) {
- if (!$scope.working)
- $scope.working = { statcats: {}, statcat_filter: undefined};
- if (!$scope.working.statcats)
- $scope.working.statcats = {};
+ if (!$scope.working)
+ $scope.working = { statcats_multi: {}, statcats: {}, statcat_filter: undefined};
+ if (!$scope.working.statcats_multi)
+ $scope.working.statcats_multi = {};
+ if (!$scope.working.statcats)
+ $scope.working.statcats = {};
- if (!$scope.in_item_select) {
- $scope.working.statcats[s.id()] = undefined;
- }
- createStatcatUpdateWatcher(s.id());
+ if (!$scope.in_item_select) {
+ $scope.working.statcats[s.id()] = undefined;
+ }
+ createStatcatUpdateWatcher(s.id());
+ });
+ $scope.in_item_select = false;
+ // do a refresh here to work around a race
+ // condition that can result in stat cats
+ // not being selected.
+ $scope.workingGridDataProvider.refresh();
});
- $scope.in_item_select = false;
});
}
+ } else {
+ $scope.workingGridDataProvider.refresh();
}
}
-
- $scope.workingGridDataProvider.refresh();
});
$scope.statcat_visible = function (sc_owner) {
var visible = typeof $scope.working.statcat_filter === 'undefined' || !$scope.working.statcat_filter;
- angular.forEach(egCore.org.ancestors(sc_owner), function (anscestor_org) {
- if ($scope.working.statcat_filter == anscestor_org.id())
+ angular.forEach(egCore.org.ancestors(sc_owner), function (ancestor_org) {
+ if ($scope.working.statcat_filter == ancestor_org.id())
visible = true;
});
return visible;
});
$scope.location_list = [];
- itemSvc.get_locations().then(function(list){
- $scope.location_list = list;
- });
createSimpleUpdateWatcher('location');
$scope.status_list = [];
+ itemSvc.get_magic_statuses().then(function(list){
+ $scope.magic_status_list = list;
+ createSimpleUpdateWatcher('status',$scope.magic_status_list);
+ });
itemSvc.get_statuses().then(function(list){
$scope.status_list = list;
});
- createSimpleUpdateWatcher('status');
$scope.circ_modifier_list = [];
itemSvc.get_circ_mods().then(function(list){
cnHash[cn_id].suffix(cnHash[cn_id].suffix().id()); // un-object-ize some fields
});
- angular.forEach(perCnCopies, function (v, k) {
- cnHash[k].copies(v);
- });
+ if ($scope.only_vols) { // strip off copies when we're in vol-only mode
+ angular.forEach(cnHash, function (v, k) {
+ cnHash[k].copies([]);
+ });
+ } else {
+ angular.forEach(perCnCopies, function (v, k) {
+ cnHash[k].copies(v);
+ });
+ }
cnList = [];
angular.forEach(cnHash, function (v, k) {
egNet.request(
'open-ils.cat',
'open-ils.cat.asset.volume.fleshed.batch.update.override',
- egCore.auth.token(), cnList, 1, { auto_merge_vols : 1, create_parts : 1 }
- ).then(function(update_count) {
+ egCore.auth.token(), cnList, 1, { auto_merge_vols : 1, create_parts : 1, return_copy_ids : 1 }
+ ).then(function(copy_ids) {
if (and_exit) {
$scope.dirty = false;
- $timeout(function(){$window.close()});
+ if ($scope.defaults.print_item_labels) {
+ egCore.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.anon_cache.set_value',
+ null, 'print-labels-these-copies', {
+ copies : copy_ids
+ }
+ ).then(function(key) {
+ if (key) {
+ var url = egCore.env.basePath + 'cat/printlabels/' + key;
+ $timeout(function() { $window.open(url, '_blank') }).then(
+ function() { $timeout(function(){$window.close()}); }
+ );
+ } else {
+ alert('Could not create anonymous cache key!');
+ }
+ });
+ } else {
+ $timeout(function(){
+ if (typeof BroadcastChannel != 'undefined') {
+ var bChannel = new BroadcastChannel("eg.holdings.update");
+ var bre_ids = cnList && cnList.length > 0 ? cnList.map(function(cn){ return Number(cn.record()) }) : [];
+ var cn_ids = cnList && cnList.length > 0 ? cnList.map(function(cn){ return cn.id() }) : [];
+ bChannel.postMessage({
+ copies : copy_ids,
+ volumes: cn_ids,
+ records: bre_ids
+ });
+ }
+
+ $window.close();
+ });
+ }
}
});
}
var default_pub = Boolean($scope.defaults.copy_notes_pub);
if (!angular.isArray(copy_list)) copy_list = [copy_list];
- return $modal.open({
+ return $uibModal.open({
templateUrl: './cat/volcopy/t_copy_notes',
+ backdrop: 'static',
animation: true,
controller:
- ['$scope','$modalInstance',
- function($scope , $modalInstance) {
+ ['$scope','$uibModalInstance',
+ function($scope , $uibModalInstance) {
$scope.focusNote = true;
$scope.note = {
creator : egCore.auth.user().id(),
egCore.org.settings([
'ui.staff.require_initials.copy_notes'
]).then(function(set) {
- $scope.require_initials = Boolean(set['ui.staff.require_initials.copy_notes']);
+ $scope.require_initials_ous = Boolean(set['ui.staff.require_initials.copy_notes']);
});
+ $scope.are_initials_required = function() {
+ $scope.require_initials = $scope.require_initials_ous && ($scope.note.value.length > 0 || $scope.note.title.length > 0);
+ };
+
+ $scope.$watch('note.value.length', $scope.are_initials_required);
+ $scope.$watch('note.title.length', $scope.are_initials_required);
+
$scope.note_list = [];
if (copy_list.length == 1) {
$scope.note_list = copy_list[0].notes();
$scope.ok = function(note) {
- if (note.initials) note.value += ' [' + note.initials + ']';
+ if (note.value.length > 0 || note.title.length > 0) {
+ if ($scope.initials) {
+ note.value = egCore.strings.$replace(
+ egCore.strings.COPY_NOTE_INITIALS, {
+ value : note.value,
+ initials : $scope.initials,
+ ws_ou : egCore.org.get(
+ egCore.auth.user().ws_ou()).shortname()
+ });
+ }
+
+ angular.forEach(copy_list, function (cp) {
+ if (!angular.isArray(cp.notes())) cp.notes([]);
+ var n = new egCore.idl.acpn();
+ n.isnew(1);
+ n.creator(note.creator);
+ n.pub(note.pub ? 't' : 'f');
+ n.title(note.title);
+ n.value(note.value);
+ n.owning_copy(cp.id());
+ cp.notes().push( n );
+ });
+ }
+
+ $uibModalInstance.close();
+ }
+
+ $scope.cancel = function($event) {
+ $uibModalInstance.dismiss();
+ $event.preventDefault();
+ }
+ }]
+ });
+ }
+
+ $scope.copy_tags_dialog = function(copy_list) {
+ if (!angular.isArray(copy_list)) copy_list = [copy_list];
+
+ return $uibModal.open({
+ templateUrl: './cat/volcopy/t_copy_tags',
+ backdrop: 'static',
+ animation: true,
+ controller:
+ ['$scope','$uibModalInstance',
+ function($scope , $uibModalInstance) {
+
+ $scope.tag_map = [];
+ var tag_hash = {};
+ var shared_tags = {};
+ angular.forEach(copy_list, function (cp) {
+ angular.forEach(cp.tags(), function(tag) {
+ if (!(tag.tag().id() in shared_tags)) {
+ shared_tags[tag.tag().id()] = 1;
+ } else {
+ shared_tags[tag.tag().id()]++;
+ }
+ if (!(tag.tag().id() in tag_hash)) {
+ tag_hash[tag.tag().id()] = tag;
+ }
+ });
+ });
+ angular.forEach(tag_hash, function(value, key) {
+ if (shared_tags[key] == copy_list.length) {
+ $scope.tag_map.push(value);
+ }
+ });
+
+ $scope.tag_types = [];
+ egCore.pcrud.retrieveAll('cctt', {order_by : { cctt : 'label' }}, {atomic : true}).then(function(list) {
+ $scope.tag_types = list;
+ $scope.tag_type = $scope.tag_types[0].code(); // just pick a default
+ });
+
+ $scope.getTags = function(val) {
+ return egCore.pcrud.search('acpt',
+ {
+ owner : egCore.org.fullPath(egCore.auth.user().ws_ou(), true),
+ label : { 'startwith' : {
+ transform: 'evergreen.lowercase',
+ value : [ 'evergreen.lowercase', val ]
+ }},
+ tag_type : $scope.tag_type
+ },
+ { order_by : { 'acpt' : ['label'] } }, { atomic: true }
+ ).then(function(list) {
+ return list.map(function(item) {
+ return item.label() + " (" + egCore.org.get(item.owner()).shortname() + ")";
+ });
+ });
+ }
+
+ $scope.addTag = function() {
+ var tagLabel = $scope.selectedLabel;
+ // clear the typeahead
+ $scope.selectedLabel = "";
+
+ // first, check tags already associated with the copy
+ var foundMatch = false;
+ angular.forEach($scope.tag_map, function(tag) {
+ if (tag.tag().label() == tagLabel && tag.tag().tag_type() == $scope.tag_type) {
+ foundMatch = true;
+ if (tag.isdeleted()) tag.isdeleted(0); // just deleting the mapping
+ }
+ });
+ if (!foundMatch) {
+ egCore.pcrud.search('acpt',
+ {
+ owner : egCore.org.fullPath(egCore.auth.user().ws_ou(), true),
+ label : tagLabel,
+ tag_type : $scope.tag_type
+ },
+ { order_by : { 'acpt' : ['label'] } }, { atomic: true }
+ ).then(function(list) {
+ if (list.length > 0) {
+ var newMap = new egCore.idl.acptcm();
+ newMap.isnew(1);
+ newMap.copy(copy_list[0].id());
+ newMap.tag(egCore.idl.Clone(list[0]));
+ $scope.tag_map.push(newMap);
+ } else {
+ var newTag = new egCore.idl.acpt();
+ newTag.isnew(1);
+ newTag.owner(egCore.auth.user().ws_ou());
+ newTag.label(tagLabel);
+ newTag.pub('t');
+ newTag.tag_type($scope.tag_type);
+
+ var newMap = new egCore.idl.acptcm();
+ newMap.isnew(1);
+ newMap.copy(copy_list[0].id());
+ newMap.tag(newTag);
+ $scope.tag_map.push(newMap);
+ }
+ });
+ }
+ }
+
+ $scope.ok = function(note) {
+ // in the multi-item case, this works OK for
+ // adding new maps to existing tags, but doesn't handle
+ // all possibilities
angular.forEach(copy_list, function (cp) {
- if (!angular.isArray(cp.notes())) cp.notes([]);
- var n = new egCore.idl.acpn();
- n.isnew(1);
- n.creator(note.creator);
- n.pub(note.pub);
- n.title(note.title);
- n.value(note.value);
- n.owning_copy(cp.id());
- cp.notes().push( n );
+ cp.tags($scope.tag_map);
});
+ $uibModalInstance.close();
+ }
+
+ $scope.cancel = function($event) {
+ $uibModalInstance.dismiss();
+ $event.preventDefault();
+ }
+ }]
+ });
+ }
+
+ $scope.copy_alerts_dialog = function(copy_list) {
+ if (!angular.isArray(copy_list)) copy_list = [copy_list];
+
+ return $uibModal.open({
+ templateUrl: './cat/volcopy/t_copy_alerts',
+ animation: true,
+ controller:
+ ['$scope','$uibModalInstance',
+ function($scope , $uibModalInstance) {
+
+ itemSvc.get_copy_alert_types().then(function(ccat) {
+ $scope.alert_types = ccat;
+ });
- $modalInstance.close();
+ $scope.focusNote = true;
+ $scope.copy_alert = {
+ create_staff : egCore.auth.user().id(),
+ note : '',
+ temp : false
+ };
+
+ egCore.hatch.getItem('cat.copy.alerts.last_type').then(function(t) {
+ if (t) $scope.copy_alert.alert_type = t;
+ });
+
+ if (copy_list.length == 1) {
+ $scope.copy_alert_list = copy_list[0].copy_alerts();
+ }
+
+ $scope.ok = function(copy_alert) {
+
+ if (typeof(copy_alert.note) != 'undefined' &&
+ copy_alert.note != '') {
+ angular.forEach(copy_list, function (cp) {
+ var a = new egCore.idl.aca();
+ a.isnew(1);
+ a.create_staff(copy_alert.create_staff);
+ a.note(copy_alert.note);
+ a.temp(copy_alert.temp ? 't' : 'f');
+ a.copy(cp.id());
+ a.ack_time(null);
+ a.alert_type(
+ $scope.alert_types.filter(function(at) {
+ return at.id() == copy_alert.alert_type;
+ })[0]
+ );
+ cp.copy_alerts().push( a );
+ });
+
+ if (copy_alert.alert_type) {
+ egCore.hatch.setItem(
+ 'cat.copy.alerts.last_type',
+ copy_alert.alert_type
+ );
+ }
+
+ }
+
+ $uibModalInstance.close();
}
$scope.cancel = function($event) {
- $modalInstance.dismiss();
+ $uibModalInstance.dismiss();
$event.preventDefault();
}
}]
restrict: 'E',
replace: true,
template: '<div ng-include="'+"'/eg/staff/cat/volcopy/t_attr_edit'"+'"></div>',
- scope: { },
- controller : ['$scope','$window','itemSvc','egCore',
- function ( $scope , $window , itemSvc , egCore ) {
+ scope: {
+ editTemplates: '=',
+ },
+ controller : ['$scope','$window','itemSvc','egCore','ngToast','$uibModal',
+ function ( $scope , $window , itemSvc , egCore , ngToast , $uibModal) {
+
+ $scope.i18n = egCore.i18n;
$scope.defaults = { // If defaults are not set at all, allow everything
barcode_checkdigit : false,
auto_gen_barcode : false,
statcats : true,
copy_notes : true,
+ copy_tags : true,
+ copy_alerts : true,
attributes : {
status : true,
loan_duration : true,
if (t) {
$scope.defaults = t;
$scope.working.statcat_filter = $scope.defaults.statcat_filter;
+ if (
+ typeof $scope.defaults.statcat_filter == 'object' &&
+ Object.keys($scope.defaults.statcat_filter).length > 0
+ ) {
+ // want fieldmapper object here...
+ $scope.defaults.statcat_filter =
+ egCore.idl.Clone($scope.defaults.statcat_filter);
+ // ... and ID here
+ $scope.working.statcat_filter = $scope.defaults.statcat_filter.id();
+ }
}
});
}
$scope.template_controls = true;
$scope.fetchTemplates = function () {
- egCore.hatch.getItem('cat.copy.templates').then(function(t) {
+ itemSvc.get_acp_templates().then(function(t) {
if (t) {
$scope.templates = t;
- $scope.template_name_list = Object.keys(t);
+ $scope.template_name_list = Object.keys(t).sort();
}
});
}
angular.forEach($scope.templates[n], function (v,k) {
if (k == 'circ_lib') {
$scope.working[k] = egCore.org.get(v);
- } else if (!angular.isObject(v)) {
+ } else if (angular.isArray(v) || !angular.isObject(v)) {
$scope.working[k] = angular.copy(v);
} else {
angular.forEach(v, function (sv,sk) {
+ if (!(k in $scope.working))
+ $scope.working[k] = {};
$scope.working[k][sk] = angular.copy(sv);
});
}
$scope.deleteTemplate = function (n) {
if (n) {
delete $scope.templates[n]
- $scope.template_name_list = Object.keys($scope.templates);
+ $scope.template_name_list = Object.keys($scope.templates).sort();
$scope.template_name = '';
- egCore.hatch.setItem('cat.copy.templates', $scope.templates);
+ itemSvc.save_acp_templates($scope.templates);
$scope.$parent.fetchTemplates();
+ ngToast.create(egCore.strings.VOL_COPY_TEMPLATE_SUCCESS_DELETE);
}
}
if (angular.isObject(v)) { // we'll use the pkey
if (v.id) v = v.id();
else if (v.code) v = v.code();
+ else v = angular.copy(v); // Should only be statcats and callnumbers currently
}
tmpl[k] = v;
});
$scope.templates[n] = tmpl;
- $scope.template_name_list = Object.keys($scope.templates);
+ $scope.template_name_list = Object.keys($scope.templates).sort();
- egCore.hatch.setItem('cat.copy.templates', $scope.templates);
+ itemSvc.save_acp_templates($scope.templates);
$scope.$parent.fetchTemplates();
$scope.dirty = false;
+ } else {
+ // save all templates, as we might do after an import
+ itemSvc.save_acp_templates($scope.templates);
+ $scope.$parent.fetchTemplates();
}
+ ngToast.create(egCore.strings.VOL_COPY_TEMPLATE_SUCCESS_SAVE);
}
-
+
$scope.templates = {};
$scope.imported_templates = { data : '' };
$scope.template_name = '';
try {
var newTemplates = JSON.parse(newVal);
if (!Object.keys(newTemplates).length) return;
- $scope.templates = newTemplates;
- $scope.template_name_list = Object.keys(newTemplates);
- $scope.template_name = '';
+ angular.forEach(Object.keys(newTemplates), function (k) {
+ $scope.templates[k] = newTemplates[k];
+ });
+ itemSvc.save_acp_templates($scope.templates);
+ $scope.fetchTemplates();
} catch (E) {
console.log('tried to import an invalid copy template file');
}
}
$scope.working = {
+ copy_notes: [],
+ copy_alerts: [],
statcats: {},
statcat_filter: undefined
};
+ $scope.statcat_visible = function (sc_owner) {
+ var visible = typeof $scope.working.statcat_filter === 'undefined' || !$scope.working.statcat_filter;
+ angular.forEach(egCore.org.ancestors(sc_owner), function (ancestor_org) {
+ if ($scope.working.statcat_filter == ancestor_org.id())
+ visible = true;
+ });
+ return visible;
+ }
+
createStatcatUpdateWatcher = function (id) {
return $scope.$watch('working.statcats[' + id + ']', function () {
if ($scope.working.statcats) {
$scope.clearWorking = function () {
angular.forEach($scope.working, function (v,k,o) {
+ $scope.working.MultiMap[k] = [];
if (!angular.isObject(v)) {
if (typeof v != 'undefined')
$scope.working[k] = undefined;
$scope.location_cache = {};
$scope.location_list = [];
- itemSvc.get_locations(
+ itemSvc.get_locations_by_org(
egCore.org.fullPath( egCore.auth.user().ws_ou(), true )
).then(function(list){
$scope.location_list = list;
createStatcatUpdateWatcher(s.id());
});
});
+
+ $scope.copy_notes_dialog = function() {
+ var default_pub = Boolean($scope.defaults.copy_notes_pub);
+ var working = $scope.working;
+ return $uibModal.open({
+ templateUrl: './cat/volcopy/t_copy_notes',
+ animation: true,
+ controller:
+ ['$scope','$uibModalInstance',
+ function($scope , $uibModalInstance) {
+ $scope.focusNote = true;
+ $scope.note = {
+ title : '',
+ value : '',
+ pub : default_pub,
+ };
+
+ $scope.require_initials = false;
+ egCore.org.settings([
+ 'ui.staff.require_initials.copy_notes'
+ ]).then(function(set) {
+ $scope.require_initials = Boolean(set['ui.staff.require_initials.copy_notes']);
+ });
+
+ $scope.note_list = [];
+ angular.forEach(working.copy_notes, function(note) {
+ var acpn = egCore.idl.fromHash('acpn', note);
+ $scope.note_list.push(acpn);
+ });
+
+ $scope.ok = function(note) {
+
+ if (!working.copy_notes) {
+ working.copy_notes = [];
+ }
+
+ // clear slate
+ working.copy_notes.length = 0;
+ angular.forEach($scope.note_list, function(existing_note) {
+ if (!existing_note.isdeleted()) {
+ working.copy_notes.push({
+ pub : existing_note.pub() ? 't' : 'f',
+ title : existing_note.title(),
+ value : existing_note.value()
+ });
+ }
+ });
+
+ // add new note, if any
+ if (note.initials) note.value += ' [' + note.initials + ']';
+ note.pub = note.pub ? 't' : 'f';
+ if (note.title.length && note.value.length) {
+ working.copy_notes.push(note);
+ }
+
+ $uibModalInstance.close();
+ }
+
+ $scope.cancel = function($event) {
+ $uibModalInstance.dismiss();
+ $event.preventDefault();
+ }
+ }]
+ });
+ }
+
+ $scope.copy_alerts_dialog = function() {
+ var working = $scope.working;
+
+ return $uibModal.open({
+ templateUrl: './cat/volcopy/t_copy_alerts',
+ animation: true,
+ controller:
+ ['$scope','$uibModalInstance',
+ function($scope , $uibModalInstance) {
+
+ itemSvc.get_copy_alert_types().then(function(ccat) {
+ var ccat_map = {};
+ $scope.alert_types = ccat;
+ angular.forEach(ccat, function(t) {
+ ccat_map[t.id()] = t;
+ });
+ $scope.copy_alert_list = [];
+ angular.forEach(working.copy_alerts, function (alrt) {
+ var aca = egCore.idl.fromHash('aca', alrt);
+ aca.alert_type(ccat_map[alrt.alert_type]);
+ aca.ack_time(null);
+ $scope.copy_alert_list.push(aca);
+ });
+ });
+
+ $scope.focusNote = true;
+ $scope.copy_alert = {
+ note : '',
+ temp : false
+ };
+
+ $scope.ok = function(copy_alert) {
+
+ if (!working.copy_alerts) {
+ working.copy_alerts = [];
+ }
+ // clear slate
+ working.copy_alerts.length = 0;
+
+ angular.forEach($scope.copy_alert_list, function(alrt) {
+ if (alrt.ack_time() == null) {
+ working.copy_alerts.push({
+ note : alrt.note(),
+ temp : alrt.temp(),
+ alert_type : alrt.alert_type().id()
+ });
+ }
+ });
+
+ if (typeof(copy_alert.note) != 'undefined' &&
+ copy_alert.note != '') {
+ working.copy_alerts.push({
+ note : copy_alert.note,
+ temp : copy_alert.temp ? 't' : 'f',
+ alert_type : copy_alert.alert_type
+ });
+ }
+
+ $uibModalInstance.close();
+ }
+
+ $scope.cancel = function($event) {
+ $uibModalInstance.dismiss();
+ $event.preventDefault();
+ }
+ }]
+ });
+ }
+
$scope.status_list = [];
+ itemSvc.get_magic_statuses().then(function(list){
+ $scope.magic_status_list = list;
+ });
itemSvc.get_statuses().then(function(list){
$scope.status_list = list;
});
$scope.age_protect_list = list;
});
createSimpleUpdateWatcher('age_protect');
-
+
+ $scope.floating_list = [];
+ itemSvc.get_floating_groups().then(function(list){
+ $scope.floating_list = list;
+ });
+ createSimpleUpdateWatcher('floating');
+
createSimpleUpdateWatcher('circulate');
createSimpleUpdateWatcher('holdable');
createSimpleUpdateWatcher('fine_level');