[% INCLUDE 'staff/circ/share/hold_strings.tt2' %]
<script src="[% ctx.media_prefix %]/js/ui/default/staff/cat/services/record.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/app.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/regctl.js"></script>
<!-- load the rest on demand? -->
%]
[% BLOCK APP_JS %]
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/eframe.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/register.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/circ/patron/regctl.js"></script>
<link rel="stylesheet" href="[% ctx.base_path %]/staff/css/circ.css" />
[% END %]
-<eg-embed-frame url="patron_edit_url" handlers="funcs"></eg-embed-frame>
+[% DOC_IMG = '/images/question-mark.png' %]
+
+<div class="strong-text-2">[% l('Patron Edit') %]</div>
+
+<!-- IDL field documentation window -->
+<div id="reg-control-actions">
+ <div class="pad-all-min">
+ <button type="button" class="btn btn-default">[% l('Save') %]</button>
+ <button type="button" class="btn btn-default">[% l('Save & Clone') %]</button>
+ </div>
+ <div class="pad-all-min" ng-show="!display_required_fields">
+ <a href>[% l('Show Only Required Fields') %]</a>
+ </div>
+ <div class="pad-all-min" ng-show="!display_suggested_fields">
+ <a href>[% l('Show Suggested Fields') %]</a>
+ </div>
+ <div class="pad-all-min" ng-show="!display_all_fields">
+ <a href>[% l('Show All Fields') %]</a>
+ </div>
+ <fieldset id="reg-field-doc" ng-show="selected_field_doc">
+ <legend>
+ {{idl_fields[selected_field_doc.fm_class()][selected_field_doc.field()].label}}
+ </legend>
+ <div>{{selected_field_doc.string()}}</div>
+ </fieldset>
+</div>
+
+[% MACRO formfield(cls, field, path, input_type) BLOCK;
+
+ # input field generator for common text/number/checkbox fields
+
+ IF NOT input_type; input_type = 'text'; END %]
+
+<div class="row pad-all-min2 form-group">
+
+ <div class="col-md-3 reg-field-label"> <!-- field label -->
+
+ <label>{{idl_fields.[% cls %].[% field %].label}}</label>
+
+ <!-- field documentation img/link -->
+ <img ng-show="field_doc.[% cls %].[% field %]"
+ ng-click="selected_field_doc=field_doc.[% cls %].[% field %]"
+ src='[% DOC_IMG %]'></img>
+ </div>
+
+ <div class="col-md-3 reg-field-input"> <!-- field form input -->
+
+ [%
+ model = path ? 'patron.' _ path _ '.' _ field : 'patron.' _ field;
+ IF input_type == 'checkbox' %]
+
+ <div class='checkbox'>
+ <input type='checkbox' ng-model='[% model %]'/>
+ </div>
+
+ [% ELSE %]
+ <!-- text / number input -->
+
+ <input type="[% input_type %]"
+ class="form-control" ng-model="[% model %]"/>
+ [% END %]
+ </div>
+
+ <div class="col-md-3 patron-reg-example">
+
+ [% IF field == 'barcode' %]
+
+ <button class="btn btn-default">[% l('Replace Barcode') %]</button>
+ <button class="btn btn-default">[% l('See All') %]</button>
+
+ [% ELSIF field == 'password' %]
+
+ <button class="btn btn-default">[% l('Generate Password') %]</button>
+
+ [% ELSE %]
+
+ <!-- example strings -->
+
+ [% set_str = "org_settings['ui.patron.edit." _
+ cls _ "." _ field _ ".example']"; %]
+
+ <span ng-if="[% set_str %]">
+ [% l('Example: [_1]', "{{" _ set_str _ "}}") %]
+ </span>
+
+ [% IF field.match('phone') %]
+ <!-- phones have a fall-through example option -->
+ <span ng-if="![% set_str %]">
+ [% l('Example: [_1]',
+ "{{org_settings['ui.patron.edit.phone.example']}}") %]
+ </span>
+ [% END %]
+ [% END %]
+
+ </div>
+</div>
+[% END %]
+
+[% formfield('ac', 'barcode', 'card') %]
+[% formfield('au', 'usrname') %]
+[% formfield('au', 'passwd') %]
+[% formfield('au', 'prefix') %]
+[% formfield('au', 'first_given_name') %]
+[% formfield('au', 'second_given_name') %]
+[% formfield('au', 'family_name') %]
+[% formfield('au', 'suffix') %]
+[% formfield('au', 'alias') %]
+
+<div class="row pad-all-min form-group">
+ <div class="col-md-3 reg-field-label">
+ <label>{{idl_fields.au.dob.label}}</label>
+ <img ng-show="field_doc.au.dob"
+ ng-click="selected_field_doc=field_doc.au.dob"
+ src='[% DOC_IMG %]'></img>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <input eg-date-input
+ class="form-control" ng-model="patron.dob"/>
+ </div>
+</div>
+
+[% formfield('au', 'juvenile', '', 'checkbox') %]
+
+<!-- ident_type -->
+
+<div class="row pad-all-min form-group">
+ <div class="col-md-3 reg-field-label">
+ <label>{{idl_fields.au.ident_type.label}}</label>
+ <img ng-show="field_doc.au.ident_type"
+ ng-click="selected_field_doc=field_doc.au.ident_type"
+ src='[% DOC_IMG %]'></img>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <div class="btn-group" dropdown>
+ <button type="button" class="btn btn-default dropdown-toggle">
+ <span style="padding-right: 5px;">
+ {{patron.ident_type.name() || "[% l('Primary Ident Type') %]"}}
+ </span>
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+ <li ng-repeat="type in ident_types">
+ <a href ng-click="patron.ident_type = type">{{type.name()}}</a>
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+
+
+[% formfield('au', 'ident_value') %]
+[% formfield('au', 'ident_value2') %]
+[% formfield('au', 'email', '', 'email') %]
+[% formfield('au', 'day_phone') %]
+[% formfield('au', 'evening_phone') %]
+[% formfield('au', 'other_phone') %]
+
+<!-- home org unit selector -->
+
+<div class="row pad-all-min form-group">
+ <div class="col-md-3 reg-field-label">
+ <label>{{idl_fields.au.home_ou.label}}</label>
+ <img ng-show="field_doc.au.home_ou"
+ ng-click="selected_field_doc=field_doc.au.home_ou"
+ src='[% DOC_IMG %]'></img>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <eg-org-selector selected="patron.home_ou" onchange="">
+ </eg-org-selector>
+ </div>
+</div>
+
+<!-- profile selector -->
+
+<div class="row pad-all-min form-group">
+ <div class="col-md-3 reg-field-label">
+ <label>{{idl_fields.au.profile.label}}</label>
+ <img ng-show="field_doc.au.profile"
+ ng-click="selected_field_doc=field_doc.au.profile"
+ src='[% DOC_IMG %]'></img>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <div class="btn-group" dropdown>
+ <button type="button" class="btn btn-default dropdown-toggle">
+ <span style="padding-right: 5px;">
+ {{patron.profile.name() || "[% l('Profile Group') %]"}}
+ </span>
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+ <li ng-repeat="grp in profiles">
+ <a href
+ style="padding-left: {{pgt_depth(grp) * 10 + 5}}px"
+ ng-click="patron.profile = grp">{{grp.name()}}</a>
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+
+<div class="row pad-all-min form-group">
+ <div class="col-md-3 reg-field-label">
+ <label>{{idl_fields.au.expire_date.label}}</label>
+ <img ng-show="field_doc.au.expire_date"
+ ng-click="selected_field_doc=field_doc.au.expire_date"
+ src='[% DOC_IMG %]'></img>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <input eg-date-input
+ class="form-control" ng-model="patron.expire_date"/>
+ </div>
+ <div class="col-md-3">
+ <button class="btn btn-default">[% l('Update Expire Date') %]</button>
+ </div>
+</div>
+
+<!-- net_access_level -->
+
+<div class="row pad-all-min form-group">
+ <div class="col-md-3 reg-field-label">
+ <label>{{idl_fields.au.net_access_level.label}}</label>
+ <img ng-show="field_doc.au.net_access_level"
+ ng-click="selected_field_doc=field_doc.au.net_access_level"
+ src='[% DOC_IMG %]'></img>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <div class="btn-group" dropdown>
+ <button type="button" class="btn btn-default dropdown-toggle">
+ <span style="padding-right: 5px;">
+ {{patron.net_access_level.name() || "[% l('Net Access Level') %]"}}
+ </span>
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+ <li ng-repeat="level in net_access_levels">
+ <a href
+ ng-click="patron.net_access_level = level">{{level.name()}}</a>
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+
+[% formfield('au', 'active', '', 'checkbox') %]
+[% formfield('au', 'barred', '', 'checkbox') %]
+[% formfield('au', 'master_account', '', 'checkbox') %]
+[% formfield('au', 'claims_returned_count', '', 'number') %]
+[% formfield('au', 'claims_never_checked_out_count', '', 'number') %]
+[% formfield('au', 'alert_message') %]
+
+<div class="alert alert-success row" role="alert">
+ <div class="col-md-6">[% l('User Settings') %]</div>
+</div>
+
+<div class="row pad-all-min form-group">
+ <div class="col-md-3 reg-field-label">
+ <label>{{user_setting_types['opac.default_phone'].label()}}</label>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <input type='text' ng-model="user_settings['opac.default_phone']"/>
+ </div>
+</div>
+
+<div class="row pad-all-min form-group">
+ <div class="col-md-3 reg-field-label">
+ <label>{{user_setting_types['opac.default_pickup_location'].label()}}</label>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <eg-org-selector selected="patron.home_ou" onchange=""></eg-org-selector>
+ </div>
+</div>
+
+<div class="row pad-all-min form-group">
+ <div class="col-md-3 reg-field-label">
+ <label>{{user_setting_types['circ.holds_behind_desk'].label()}}</label>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <div class='checkbox'>
+ <input type='checkbox' ng-model="user_settings['circ.holds_behind_desk']"/>
+ </div>
+ </div>
+</div>
+
+<div class="row pad-all-min form-group">
+ <div class="col-md-3 reg-field-label">
+ <label>[% l('Holds Notices') %]</label>
+ </div>
+ <div class="col-md-3 reg-field-input flex-row">
+ <div class='flex-cell'>
+ <input type='checkbox' ng-model="hold_notify_phone"/>
+ [% l('Phone') %]
+ </div>
+ <div class='flex-cell'>
+ <input type='checkbox' ng-model="hold_notify_email"/>
+ [% l('Email') %]
+ </div>
+ <div class='flex-cell'>
+ <input type='checkbox' ng-model="hold_notify_sms"/>
+ [% l('SMS') %]
+ </div>
+ </div>
+</div>
+
+<div class="row pad-all-min form-group" ng-if="org_settings['sms.enable']">
+ <div class="col-md-3 reg-field-label">
+ <label>[% l('Default SMS/Text Number') %]</label>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <input type='text'/>
+ </div>
+</div>
+
+<div class="row pad-all-min form-group" ng-if="org_settings['sms.enable']">
+ <div class="col-md-3 reg-field-label">
+ <label>[% l('Default SMS Carrier') %]</label>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <div class="btn-group" dropdown>
+ <button type="button" class="btn btn-default dropdown-toggle">
+ <span style="padding-right: 5px;"></span>
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+ <li ng-repeat="carrier in sms_carriers">
+ <a href
+ ng-click="user_settings['opac.default_sms_carrier'] = carrier">
+ {{carrier.name()}}
+ </a>
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+
+<div class="alert alert-success row" role="alert">
+ <div class="col-md-3">[% l('Address') %]</div>
+ <div class="col-md-3">
+ <span class='pad-all-min'>
+ [% l('Mailing') %] <input type='checkbox'/>
+ </span>
+ <span class='pad-all-min'>
+ [% l('Billing') %] <input type='checkbox'/>
+ </span>
+ <span class='pad-all-min'>
+ <button type="button" class="btn btn-danger">[% l('X') %]</button>
+ </span>
+ </div>
+</div>
+
+<!-- addresses -->
+
+[% formfield('aua', 'address_type', 'mailing_address') %]
+[% formfield('aua', 'post_code', 'mailing_address') %]
+[% formfield('aua', 'street1', 'mailing_address') %]
+[% formfield('aua', 'street2', 'mailing_address') %]
+[% formfield('aua', 'city', 'mailing_address') %]
+[% formfield('aua', 'county', 'mailing_address') %]
+[% formfield('aua', 'state', 'mailing_address') %]
+[% formfield('aua', 'country', 'mailing_address') %]
+[% formfield('aua', 'valid', 'mailing_address', 'checkbox') %]
+[% formfield('aua', 'within_city_limits', 'mailing_address', 'checkbox') %]
+
+<div class="row">
+ <button type="button" class="btn btn-success">[% l('New Address') %]</button>
+</div>
+
+<!-- pending address -->
+
+<div class="alert alert-success row" role="alert" ng-if="stat_cats.length > 0">
+ <div class="col-md-6">[% l('Statistical Categories') %]</div>
+</div>
+
+<div class="row pad-all-min form-group" ng-repeat="cat in stat_cats">
+ <div class="col-md-3 reg-field-label">
+ <label>{{cat.name()}}</label>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <div ng-if="cat.entries().length == 0">
+ <input type="text" class="form-control"/>
+ </div>
+ <div ng-if="cat.entries().length != 0">
+ <div class="btn-group" dropdown>
+ <button type="button" class="btn btn-default dropdown-toggle">
+ <span style="padding-right: 5px;"></span>
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+ <li ng-repeat="entry in cat.entries()">
+ <a href ng-click=""> {{entry.value()}} </a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+</div>
+
+<!-- surveys -->
+
+<div class="alert alert-success row" role="alert" ng-if="surveys.length > 0">
+ <div class="col-md-6">[% l('Surveys') %]</div>
+</div>
+
+<div class="row pad-all-min form-group" ng-repeat="survey in surveys">
+ <div class="col-md-3 reg-field-label">
+ <label>{{survey.name()}}</label>
+ </div>
+ <div class="col-md-3 reg-field-input">
+ <div class="btn-group" dropdown>
+ <button type="button" class="btn btn-default dropdown-toggle">
+ <span style="padding-right: 5px;"></span>
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+ <li ng-repeat="question in survey.questions()">
+ <a href ng-click=""> {{question.question()}} </a>
+ </li>
+ </ul>
+ </div>
+ </div>
+</div>
+
+
border-bottom: 1px solid #CCC;
}
+/* -- patron registration -- */
+
+/* make all input widgets the same width, i.e. fill their column */
+
+.reg-field-input input:not([type="checkbox"]) { width: 100%; }
+
+/* selector contents float left to allow depth-based left-padding */
+.reg-field-input .eg-org-selector,
+.reg-field-input .btn-group {
+ width: 100%;
+ text-align: left;
+}
+
+/* selector button labels float right */
+.reg-field-input .eg-org-selector button,
+.reg-field-input .btn-group > button {
+ width: 100%;
+ text-align: right;
+}
+
+
+/* floating div along top-right with field documentation */
+#reg-control-actions {
+ position: fixed;
+ top:160px;
+ right:30px;
+ width:300px;
+ border:2px dashed #d9e8f9;
+ -moz-border-radius: 10px;
+ font-weight: bold;
+ padding: 20px;
+ margin-top: 20px;
+}
+
+#reg-field-doc {
+ border:2px dashed #d9e8f9;
+ -moz-border-radius: 10px;
+ font-weight: bold;
+ padding: 20px;
+ margin-top: 20px;
+}
+
+#reg-field-doc legend {
+ /* otherwise the font size is quite large */
+ font-size: 100%;
+}
+
+/* -- end patron registration -- */
[%#
vim: ft=css
.pad-left {padding-left: 10px;}
.pad-right {padding-right: 10px;}
.pad-all-min {padding : 5px; }
+.pad-all-min2 {padding : 2px; }
.pad-all {padding : 10px; }
#print-div { display: none; }
$routeProvider.when('/circ/patron/:id/edit', {
templateUrl: './circ/patron/t_edit',
- controller: 'PatronEditCtrl',
+ controller: 'PatronRegCtrl',
resolve : resolver
});
/**
- * Link to patron edit UI
- */
-.controller('PatronEditCtrl',
- ['$scope','$routeParams','$location','egCore','patronSvc',
-function($scope, $routeParams, $location , egCore , patronSvc) {
- $scope.initTab('edit', $routeParams.id);
-
- var url = $location.absUrl().replace(/\/staff.*/, '/actor/user/register');
- url += '?usr=' + encodeURIComponent($routeParams.id);
-
- $scope.funcs = {
- on_save : function() {
- patronSvc.refreshPrimary();
- }
- }
-
- $scope.patron_edit_url = url;
-}])
-
-/**
* Credentials tester
*/
.controller('PatronVerifyCredentialsCtrl',
--- /dev/null
+
+angular.module('egCoreMod')
+// toss tihs onto egCoreMod since the page app may vary
+
+.factory('patronRegSvc', ['$q', 'egCore', function($q, egCore) {
+
+ var service = {
+ field_doc : {}, // config.idl_field_doc
+ profiles : [], // permission groups
+ sms_carriers : [],
+ user_settings : {}, // applied user settings
+ user_setting_types : {}, // config.usr_setting_type
+ modified_user_settings : {} // settings modifed this session
+ };
+
+ // launch a series of parallel data retrieval calls
+ service.init = function(scope) {
+ return $q.all([
+ service.get_field_doc(),
+ service.get_perm_groups(),
+ service.get_ident_types(),
+ service.get_user_settings(),
+ service.get_org_settings(),
+ service.get_stat_cats(),
+ service.get_surveys(),
+ service.get_net_access_levels()
+ ]);
+ };
+
+ service.get_surveys = function() {
+ var org_ids = egCore.org.ancestors(egCore.auth.user().ws_ou(), true);
+
+ return egCore.pcrud.search('asv',
+ {owner : org_ids},
+ {flesh : 1, flesh_fields : {asv : ['questions']}},
+ {atomic : true}
+ ).then(function(surveys) {
+ service.surveys = surveys;
+ });
+ }
+
+ service.get_stat_cats = function() {
+ return egCore.net.request(
+ 'open-ils.circ',
+ 'open-ils.circ.stat_cat.actor.retrieve.all',
+ egCore.auth.token(), egCore.auth.user().ws_ou()
+ ).then(function(cats) {
+ service.stat_cats = cats;
+ });
+ };
+
+ service.get_org_settings = function() {
+ return egCore.org.settings([
+ 'global.password_regex',
+ 'global.juvenile_age_threshold',
+ 'patron.password.use_phone',
+ 'ui.patron.default_inet_access_level',
+ 'ui.patron.default_ident_type',
+ 'ui.patron.default_country',
+ 'ui.patron.registration.require_address',
+ 'circ.holds.behind_desk_pickup_supported',
+ 'circ.patron_edit.clone.copy_address',
+ 'ui.patron.edit.au.prefix.require',
+ 'ui.patron.edit.au.prefix.show',
+ 'ui.patron.edit.au.prefix.suggest',
+ 'ui.patron.edit.ac.barcode.regex',
+ 'ui.patron.edit.au.second_given_name.show',
+ 'ui.patron.edit.au.second_given_name.suggest',
+ 'ui.patron.edit.au.suffix.show',
+ 'ui.patron.edit.au.suffix.suggest',
+ 'ui.patron.edit.au.alias.show',
+ 'ui.patron.edit.au.alias.suggest',
+ 'ui.patron.edit.au.dob.require',
+ 'ui.patron.edit.au.dob.show',
+ 'ui.patron.edit.au.dob.suggest',
+ 'ui.patron.edit.au.dob.calendar',
+ 'ui.patron.edit.au.juvenile.show',
+ 'ui.patron.edit.au.juvenile.suggest',
+ 'ui.patron.edit.au.ident_value.show',
+ 'ui.patron.edit.au.ident_value.suggest',
+ 'ui.patron.edit.au.ident_value2.show',
+ 'ui.patron.edit.au.ident_value2.suggest',
+ 'ui.patron.edit.au.email.require',
+ 'ui.patron.edit.au.email.show',
+ 'ui.patron.edit.au.email.suggest',
+ 'ui.patron.edit.au.email.regex',
+ 'ui.patron.edit.au.email.example',
+ 'ui.patron.edit.au.day_phone.require',
+ 'ui.patron.edit.au.day_phone.show',
+ 'ui.patron.edit.au.day_phone.suggest',
+ 'ui.patron.edit.au.day_phone.regex',
+ 'ui.patron.edit.au.day_phone.example',
+ 'ui.patron.edit.au.evening_phone.require',
+ 'ui.patron.edit.au.evening_phone.show',
+ 'ui.patron.edit.au.evening_phone.suggest',
+ 'ui.patron.edit.au.evening_phone.regex',
+ 'ui.patron.edit.au.evening_phone.example',
+ 'ui.patron.edit.au.other_phone.require',
+ 'ui.patron.edit.au.other_phone.show',
+ 'ui.patron.edit.au.other_phone.suggest',
+ 'ui.patron.edit.au.other_phone.regex',
+ 'ui.patron.edit.au.other_phone.example',
+ 'ui.patron.edit.phone.regex',
+ 'ui.patron.edit.phone.example',
+ 'ui.patron.edit.au.active.show',
+ 'ui.patron.edit.au.active.suggest',
+ 'ui.patron.edit.au.barred.show',
+ 'ui.patron.edit.au.barred.suggest',
+ 'ui.patron.edit.au.master_account.show',
+ 'ui.patron.edit.au.master_account.suggest',
+ 'ui.patron.edit.au.claims_returned_count.show',
+ 'ui.patron.edit.au.claims_returned_count.suggest',
+ 'ui.patron.edit.au.claims_never_checked_out_count.show',
+ 'ui.patron.edit.au.claims_never_checked_out_count.suggest',
+ 'ui.patron.edit.au.alert_message.show',
+ 'ui.patron.edit.au.alert_message.suggest',
+ 'ui.patron.edit.aua.post_code.regex',
+ 'ui.patron.edit.aua.post_code.example',
+ 'ui.patron.edit.aua.county.require',
+ 'format.date',
+ 'ui.patron.edit.default_suggested',
+ 'opac.barcode_regex',
+ 'opac.username_regex',
+ 'sms.enable',
+ 'ui.patron.edit.aua.state.require',
+ 'ui.patron.edit.aua.state.suggest',
+ 'ui.patron.edit.aua.state.show'
+ ]).then(function(settings) {
+ service.org_settings = settings;
+ return service.process_org_settings(settings);
+ });
+ };
+
+ // some org settings require the retrieval of additional data
+ service.process_org_settings = function(settings) {
+
+ if (!settings['sms.enable']) {
+ return $q.when();
+ }
+
+ return egCore.pcrud.search('csc',
+ {active: 'true'},
+ {'order_by':[
+ {'class':'csc', 'field':'name'},
+ {'class':'csc', 'field':'region'}
+ ]},
+ {atomic : true}
+ ).then(function(carriers) {
+ service.sms_carriers = carriers;
+ });
+ };
+
+ service.get_ident_types = function() {
+ return egCore.pcrud.retrieveAll('cit', {}, {atomic : true})
+ .then(function(types) { service.ident_types = types });
+ };
+
+ service.get_net_access_levels = function() {
+ return egCore.pcrud.retrieveAll('cnal', {}, {atomic : true})
+ .then(function(levels) { service.net_access_levels = levels });
+ }
+
+ service.get_perm_groups = function() {
+ if (egCore.env.pgt) {
+ service.profiles = egCore.env.pgt.list;
+ return $q.when();
+ } else {
+ return egCore.pcrud.search('pgt', {parent : null},
+ {flesh : -1, flesh_fields : {pgt : ['children']}}
+ ).then(
+ function(tree) {
+ egCore.env.absorbTree(tree, 'pgt')
+ service.profiles = egCore.env.pgt.list;
+ }
+ );
+ }
+ }
+
+ service.get_field_doc = function() {
+
+ return egCore.pcrud.search('fdoc', {
+ fm_class: ['au', 'ac', 'aua', 'actsc', 'asv', 'asvq', 'asva']})
+ .then(null, null, function(doc) {
+ if (!service.field_doc[doc.fm_class()]) {
+ service.field_doc[doc.fm_class()] = {};
+ }
+ service.field_doc[doc.fm_class()][doc.field()] = doc;
+ });
+ };
+
+ service.get_user_settings = function() {
+ var org_ids = egCore.org.ancestors(egCore.auth.user().ws_ou(), true);
+
+ return egCore.pcrud.search('cust', {
+ '-or' : [
+ {name : [ // common user settings
+ 'circ.holds_behind_desk',
+ 'circ.collections.exempt',
+ 'opac.hold_notify',
+ 'opac.default_phone',
+ 'opac.default_pickup_location',
+ 'opac.default_sms_carrier',
+ 'opac.default_sms_notify']},
+ {name : { // opt-in notification user settings
+ 'in': {
+ select : {atevdef : ['opt_in_setting']},
+ from : 'atevdef',
+ // we only care about opt-in settings for
+ // event_defs our users encounter
+ where : {'+atevdef' : {owner : org_ids}}
+ }
+ }}
+ ]
+ }, {}, {atomic : true}).then(function(setting_types) {
+
+ angular.forEach(setting_types, function(stype) {
+ service.user_setting_types[stype.name()] = stype;
+ });
+
+ if(service.patron_id) {
+ // retrieve applied values for the current user
+ // for the setting types we care about.
+
+ var setting_names =
+ setting_types.map(function(obj) { return obj.name() });
+
+ return egCore.net.request(
+ 'open-ils.actor',
+ 'open-ils.actor.patron.settings.retrieve.authoritative',
+ egCore.auth.token(),
+ service.patron_id,
+ setting_names
+ ).then(function(settings) {
+ service.user_settings = settings;
+ });
+ }
+
+ // apply default user setting values
+ angular.forEach(setting_types, function(stype, index) {
+ if (stype.reg_default() != undefined) {
+ service.modified_user_settings[setting.name()] =
+ service.user_settings[setting.name()] =
+ setting.reg_default();
+ }
+ });
+ });
+ }
+
+ service.init_patron = function(current) {
+
+ if (!current)
+ return service.init_new_patron();
+
+ service.patron = current;
+ return service.init_existing_patron(current)
+ }
+
+ /*
+ * Existing patron objects reqire some data munging before insertion
+ * into the scope.
+ *
+ * 1. Turn everything into a hash
+ * 2. ... Except certain fields (selectors) whose widgets require objects
+ * 3. Bools must be Boolean, not t/f.
+ */
+ service.init_existing_patron = function(current) {
+
+ var patron = egCore.idl.toHash(current);
+
+ patron.home_ou = egCore.org.get(patron.home_ou.id);
+ patron.expire_date = new Date(Date.parse(patron.expire_date));
+ patron.dob = new Date(Date.parse(patron.dob));
+ patron.profile = current.profile(); // pre-hash version
+ patron.net_access_level = current.net_access_level();
+ patron.ident_type = current.ident_type();
+
+ angular.forEach(
+ ['juvenile', 'barred', 'active', 'master_account'],
+ function(field) { patron[field] = patron[field] == 't'; }
+ );
+
+ angular.forEach(patron.addresses, function(addr) {
+ addr.valid = addr.valid == 't';
+ addr.within_city_limits = addr.within_city_limits == 't';
+ });
+
+ return patron;
+ }
+
+ service.init_new_patron = function() {
+
+ var addr = {
+ valid : true,
+ within_city_limits : true
+ // default state, etc.
+ };
+
+ return {
+ isnew : true,
+ active : true,
+ card : {},
+ home_ou : egCore.org.get(egCore.auth.user().ws_ou()),
+ // TODO default profile group?
+ mailing_address : addr,
+ addresses : [addr]
+ };
+ }
+
+ return service;
+}]);
+
+
+function PatronRegCtrl($scope, $routeParams,
+ $q, egCore, patronSvc, patronRegSvc) {
+
+ $scope.clone_id = $routeParams.clone_id;
+ $scope.stage_username = $routeParams.stage_username;
+ $scope.patron_id =
+ patronRegSvc.patron_id = $routeParams.edit_id || $routeParams.id;
+
+ $q.all([
+
+ $scope.initTab ? // initTab comes from patron app
+ $scope.initTab('edit', $routeParams.id) : $q.when(),
+
+ patronRegSvc.init()
+
+ ]).then(function() {
+ // called after initTab and patronRegSvc.init have completed
+
+ var prs = patronRegSvc; // brevity
+ // in standalone mode, we have no patronSvc
+ $scope.patron = prs.init_patron(patronSvc ? patronSvc.current : null);
+ $scope.field_doc = prs.field_doc;
+ $scope.profiles = prs.profiles;
+ $scope.ident_types = prs.ident_types;
+ $scope.net_access_levels = prs.net_access_levels;
+ $scope.user_settings = prs.user_settings;
+ $scope.user_setting_types = prs.user_setting_types;
+ $scope.modified_user_settings = prs.modified_user_settings;
+ $scope.org_settings = prs.org_settings;
+ $scope.sms_carriers = prs.sms_carriers;
+ $scope.stat_cats = prs.stat_cats;
+ $scope.surveys = prs.surveys;
+ });
+
+ // returns the tree depth of the selected profile group tree node.
+ $scope.pgt_depth = function(grp) {
+ var d = 0;
+ while (grp = egCore.env.pgt.map[grp.parent()]) d++;
+ return d;
+ }
+
+ // IDL fields used for labels in the UI.
+ $scope.idl_fields = {
+ au : egCore.idl.classes.au.field_map,
+ ac : egCore.idl.classes.ac.field_map,
+ aua : egCore.idl.classes.aua.field_map
+ };
+
+}
+
+
+// TODO: $inject controller params
* Search, checkout, items out, holds, bills, edit, etc.
*/
-angular.module('egPatronRegApp', ['ui.bootstrap','ngRoute','egCoreMod'])
+angular.module('egPatronRegApp', ['ui.bootstrap','ngRoute','egCoreMod', 'egUiMod'])
.config(function($routeProvider, $locationProvider, $compileProvider) {
['egStartup', function(egStartup) {return egStartup.go()}]}
$routeProvider.when('/circ/patron/register', {
- template: '<eg-embed-frame url="reg_url"></eg-embed-frame>',
+ templateUrl: './circ/patron/t_edit',
controller: 'PatronRegCtrl',
resolve : resolver
});
$routeProvider.when('/circ/patron/register/stage/:stage_username', {
- template: '<eg-embed-frame url="reg_url"></eg-embed-frame>',
+ templateUrl: './circ/patron/t_edit',
controller: 'PatronRegCtrl',
resolve : resolver
});
$routeProvider.when('/circ/patron/register/edit/:edit_id', {
- template: '<eg-embed-frame url="reg_url"></eg-embed-frame>',
+ templateUrl: './circ/patron/t_edit',
controller: 'PatronRegCtrl',
resolve : resolver
});
$routeProvider.when('/circ/patron/register/clone/:clone_id', {
- template: '<eg-embed-frame url="reg_url"></eg-embed-frame>',
+ templateUrl: './circ/patron/t_edit',
controller: 'PatronRegCtrl',
resolve : resolver
});
$routeProvider.otherwise({redirectTo : '/circ/patron/register'});
})
+// dummy service so standalone patron editor can reference it
+.factory('patronSvc', function() {});
-/**
- * */
-.controller('PatronRegCtrl',
- ['$scope','$routeParams','$location','egCore',
-function($scope , $routeParams , $location , egCore) {
-
-
- var url = $location.absUrl().replace(/\/staff.*/, '/actor/user/register');
-
- // since we don't store auth cookies, pass the cookie via URL
- url += '?ses=' + egCore.auth.token();
-
- if ($routeParams.stage_username) {
- url += '&stage=' + encodeURIComponent($routeParams.stage_username);
- }
-
- if ($routeParams.edit_id) {
- url += '&usr=' + encodeURIComponent($routeParams.edit_id);
- }
-
- if ($routeParams.clone_id) {
- url += '&clone=' + encodeURIComponent($routeParams.clone_id);
- }
- // pass the reg URL into the scope, thus into the
- $scope.reg_url = url;
-}])
-