}
__PACKAGE__->register_method(
+ method => "retrieve_holds_by_usr_notify_value_staff",
+ api_name => "open-ils.circ.holds.retrieve_by_notify_staff",
+ signature => {
+ desc => "Retrieve the hold, for the specified user using the notify value. $ses_is_req_note",
+ params => [
+ { desc => 'Authentication token', type => 'string' },
+ { desc => 'User ID', type => 'number' },
+ { desc => 'notify value', type => 'string' },
+ { desc => 'notify_type', type => 'string' }
+ ],
+ return => {
+ desc => 'Hold objects with transits attached, event on error',
+ }
+ }
+);
+
+sub retrieve_holds_by_usr_notify_value_staff {
+
+ my($self, $conn, $auth, $usr_id, $contact, $cType) = @_;
+
+ my $e = new_editor(authtoken=>$auth);
+ $e->checkauth or return $e->event;
+
+ if ($e->requestor->id != $usr_id){
+ $e->allowed('VIEW_HOLD') or return $e->event;
+ }
+
+ my $q = {
+ "select" => { "ahr" => ["id", "sms_notify", "phone_notify", "email_notify", "sms_carrier"]},
+ "from" => "ahr",
+ "where" => {
+ "usr" => $usr_id,
+ "capture_time" => undef,
+ "cancel_time" => undef,
+ "fulfillment_time" => undef,
+ }
+ };
+
+ if ($cType eq "day_phone" or $cType eq "evening_phone" or
+ $cType eq "other_phone" or $cType eq "default_phone"){
+ $q->{where}->{"-not"} = [
+ { "phone_notify" => { "=" => $contact} },
+ { "phone_notify" => { "<>" => undef } }
+ ];
+ }
+
+
+ if ($cType eq "default_sms") {
+ $q->{where}->{"-not"} = [
+ { "sms_notify" => { "=" => $contact} },
+ { "sms_notify" => { "<>" => undef } }
+ ];
+ }
+
+ if ($cType eq "default_sms_carrier_id") {
+ $q->{where}->{"-not"} = [
+ { "sms_carrier" => { "=" => int($contact)} },
+ { "sms_carrier" => { "<>" => undef } }
+ ];
+ }
+
+ if ($cType =~ /notify/){
+ # this is was notification pref change
+ # we find all unfulfilled holds that match have that pref
+ my $optr = $contact == 1 ? "<>" : "="; # unless it's email, true val means we want to query for not null
+ my $conj = $optr eq '=' ? '-or' : '-and';
+ if ($cType =~ /sms/) {
+ $q->{where}->{$conj} = [ { sms_notify => { $optr => undef } }, { sms_notify => { $optr => '' } } ];
+ }
+ if ($cType =~ /phone/) {
+ $q->{where}->{$conj} = [ { phone_notify => { $optr => undef } }, { phone_notify => { $optr => '' } } ];
+ }
+ if ($cType =~ /email/) {
+ if ($contact) {
+ $q->{where}->{'+ahr'} = 'email_notify';
+ } else {
+ $q->{where}->{'-not'} = {'+ahr' => 'email_notify'};
+ }
+ }
+ }
+
+ my $holds = $e->json_query($q);
+ #$hold_ids = [ map { $_->{id} } @$hold_ids ];
+
+ return $holds;
+}
+
+__PACKAGE__->register_method(
+ method => "batch_update_holds_by_value_staff",
+ api_name => "open-ils.circ.holds.batch_update_holds_by_notify_staff",
+ signature => {
+ desc => "Update a user's specified holds, affected by the contact/notify value change. $ses_is_req_note",
+ params => [
+ { desc => 'Authentication token', type => 'string' },
+ { desc => 'User ID', type => 'number' },
+ { desc => 'Hold IDs', type => 'array' },
+ { desc => 'old notify value', type => 'string' },
+ { desc => 'new notify value', type => 'string' },
+ { desc => 'field name', type => 'string' },
+ { desc => 'SMS carrier ID', type => 'number' }
+
+ ],
+ return => {
+ desc => 'Hold objects with transits attached, event on error',
+ }
+ }
+);
+
+sub batch_update_holds_by_value_staff {
+ my($self, $conn, $auth, $usr_id, $hold_ids, $oldval, $newval, $cType, $carrierId) = @_;
+
+ my $e = new_editor(authtoken=>$auth, xact=>1);
+ $e->checkauth or return $e->event;
+ if ($e->requestor->id != $usr_id){
+ $e->allowed('UPDATE_HOLD') or return $e->event;
+ }
+
+ my @success;
+ for my $id (@$hold_ids) {
+
+ my $hold = $e->retrieve_action_hold_request($id);
+
+ if ($cType eq "day_phone" or $cType eq "evening_phone" or
+ $cType eq "other_phone" or $cType eq "default_phone") {
+
+ if ($newval eq '') {
+ $hold->clear_phone_notify();
+ }
+ else {
+ $hold->phone_notify($newval);
+ }
+ }
+
+ if ($cType eq "default_sms"){
+ if ($newval eq '') {
+ $hold->clear_sms_notify();
+ $hold->clear_sms_carrier(); # TODO: prevent orphan sms_carrier, via db trigger
+ }
+ else {
+ $hold->sms_notify($newval);
+ $hold->sms_carrier($carrierId);
+ }
+
+ }
+
+ if ($cType eq "default_sms_carrier_id") {
+ $hold->sms_carrier($newval);
+ }
+
+ if ($cType =~ /notify/){
+ # this is a notification pref change
+ if ($cType =~ /email/) { $hold->email_notify($newval); }
+ if ($cType =~ /sms/ and !$newval) { $hold->clear_sms_notify(); }
+ if ($cType =~ /phone/ and !$newval) { $hold->clear_phone_notify(); }
+ # the other case, where x_notify is changed to true,
+ # is covered by an actual value being assigned
+ }
+
+ $e->update_action_hold_request($hold) or return $e->die_event;
+ push @success, $id;
+ }
+
+ #$e->disconnect;
+ $e->commit; #unless $U->event_code($res);
+ return \@success;
+
+}
+
+
+__PACKAGE__->register_method(
+ method => "retrieve_holds_by_usr_with_notify",
+ api_name => "open-ils.circ.holds.retrieve.by_usr.with_notify",
+ signature => {
+ desc => "Retrieve the hold, for the specified user using the notify value. $ses_is_req_note",
+ params => [
+ { desc => 'Authentication token', type => 'string' },
+ { desc => 'User ID', type => 'number' },
+ ],
+ return => {
+ desc => 'Lists of holds with notification values, event on error',
+ }
+ }
+);
+
+sub retrieve_holds_by_usr_with_notify {
+
+ my($self, $conn, $auth, $usr_id) = @_;
+
+ my $e = new_editor(authtoken=>$auth);
+ $e->checkauth or return $e->event;
+
+ if ($e->requestor->id != $usr_id){
+ $e->allowed('VIEW_HOLD') or return $e->event;
+ }
+
+ my $q = {
+ "select" => { "ahr" => ["id", "phone_notify", "email_notify", "sms_carrier", "sms_notify"]},
+ "from" => "ahr",
+ "where" => {
+ "usr" => $usr_id,
+ "capture_time" => undef,
+ "cancel_time" => undef,
+ "fulfillment_time" => undef,
+ }
+ };
+
+ my $holds = $e->json_query($q);
+ return $holds;
+}
+
+__PACKAGE__->register_method(
+ method => "batch_update_holds_by_value",
+ api_name => "open-ils.circ.holds.batch_update_holds_by_notify",
+ signature => {
+ desc => "Update a user's specified holds, affected by the contact/notify value change. $ses_is_req_note",
+ params => [
+ { desc => 'Authentication token', type => 'string' },
+ { desc => 'User ID', type => 'number' },
+ { desc => 'Hold IDs', type => 'array' },
+ { desc => 'old notify value', type => 'string' },
+ { desc => 'new notify value', type => 'string' },
+ { desc => 'notify_type', type => 'string' }
+ ],
+ return => {
+ desc => 'Hold objects with transits attached, event on error',
+ }
+ }
+);
+
+sub batch_update_holds_by_value {
+ my($self, $conn, $auth, $usr_id, $hold_ids, $oldval, $newval, $cType) = @_;
+
+ my $e = new_editor(authtoken=>$auth, xact=>1);
+ $e->checkauth or return $e->event;
+ if ($e->requestor->id != $usr_id){
+ $e->allowed('UPDATE_HOLD') or return $e->event;
+ }
+
+ my @success;
+ for my $id (@$hold_ids) {
+
+ my $hold = $e->retrieve_action_hold_request(int($id));
+
+ if ($cType eq "day_phone" or $cType eq "evening_phone" or
+ $cType eq "other_phone" or $cType eq "default_phone") {
+ # change phone number value on hold
+ $hold->phone_notify($newval);
+ }
+ if ($cType eq "default_sms") {
+ # change SMS number value on hold
+ $hold->sms_notify($newval);
+ }
+
+ if ($cType eq "default_sms_carrier_id") {
+ $hold->sms_carrier(int($newval));
+ }
+
+ if ($cType =~ /notify/){
+ # this is a notification pref change
+ if ($cType =~ /email/) { $hold->email_notify($newval); }
+ if ($cType =~ /sms/ and !$newval) { $hold->clear_sms_notify(); }
+ if ($cType =~ /phone/ and !$newval) { $hold->clear_phone_notify(); }
+ # the other case, where x_notify is changed to true,
+ # is covered by an actual value being assigned
+ }
+
+ $e->update_action_hold_request($hold) or return $e->die_event;
+ push @success, $id;
+ }
+
+ #$e->disconnect;
+ $e->commit; #unless $U->event_code($res);
+ return \@success;
+}
+
+__PACKAGE__->register_method(
method => "hold_metadata",
api_name => "open-ils.circ.hold.get_metadata",
authoritative => 1,
}
);
+
sub hold_metadata {
my ($self, $client, $hold_type, $hold_targets, $org_id) = @_;
return $self->load_myopac_circ_history_export if $path =~ m|opac/myopac/circ_history/export|;
return $self->load_myopac_circ_history if $path =~ m|opac/myopac/circ_history|;
return $self->load_myopac_hold_history if $path =~ m|opac/myopac/hold_history|;
+ return $self->load_myopac_prefs_notify_changed_holds if $path =~ m|opac/myopac/prefs_notify_changed_holds|;
return $self->load_myopac_prefs_notify if $path =~ m|opac/myopac/prefs_notify|;
return $self->load_myopac_prefs_settings if $path =~ m|opac/myopac/prefs_settings|;
return $self->load_myopac_prefs_my_lists if $path =~ m|opac/myopac/prefs_my_lists|;
# re-fetch user prefs
$self->ctx->{updated_user_settings} = \%settings;
+
+ # update holds: check if any changes affect any holds
+ my @llchgs = $self->_parse_prefs_notify_hold_related();
+ my @ffectedChgs;
+
+ if ( $self->cgi->param('hasHoldsChanges') ) {
+ # propagate pref_notify changes to holds
+ for my $chset (@llchgs){
+ # FIXME is this still needed?
+ }
+
+ }
+ else {
+ my $holds = $U->simplereq('open-ils.circ', 'open-ils.circ.holds.retrieve.by_usr.with_notify',
+ $e->authtoken, $e->requestor->id);
+
+ if (@$holds > 0) {
+
+ my $default_phone_changes = {};
+ my $sms_changes = {};
+ my $new_phone;
+ my $new_carrier;
+ my $new_sms;
+ for my $chset (@llchgs) {
+ next if scalar(@$chset) < 3;
+ my ($old, $new, $field) = @$chset;
+
+ my $bool = $field =~ /_notify/ ? 1 : 0;
+
+ # find holds that would change
+ my $affected = [];
+ foreach my $hold (@$holds) {
+ if ($field eq 'email_notify') {
+ my $curr = $hold->{$field} eq 't' ? 'true' : 'false';
+ push @$affected, $hold if $curr ne $new;
+ } elsif ($field eq 'default_phone') {
+ my $old_phone = $hold->{phone_notify} // '';
+ $new_phone = $new // '';
+ push @{ $default_phone_changes->{ $old_phone } }, $hold->{id}
+ if $old_phone ne $new_phone;
+ } elsif ($field eq 'phone_notify') {
+ my $curr = ($hold->{$field} // '' ne '') ? 'true' : 'false';
+ push @$affected, $hold if $curr ne $new;
+ } elsif ($field eq 'sms_notify') {
+ my $curr = ($hold->{$field} // '' ne '') ? 'true' : 'false';
+ push @$affected, $hold if $curr ne $new;
+ } elsif ($field eq 'sms_info') {
+ my $old_carrier = $hold->{'sms_carrier'} // '';
+ my $old_sms = $hold->{'sms_notify'} // '';
+ $new_carrier = $new->{carrier} // '';
+ $new_sms = $new->{sms} // '';
+ if (!($old_carrier eq $new_carrier && $old_sms eq $new_sms)) {
+ push @{ $sms_changes->{ join("\t", $old_carrier, $old_sms) } }, $hold->{id};
+ }
+ }
+ }
+
+ # append affected array to chset
+ if (scalar(@$affected) > 0){
+ push(@$chset, [ map { $_->{id} } @$affected ]);
+ push(@ffectedChgs, $chset);
+ }
+ }
+
+
+ foreach my $old_phone (keys %$default_phone_changes) {
+ push(@ffectedChgs, [ $old_phone, $new_phone, 'default_phone', $default_phone_changes->{$old_phone} ]);
+ }
+ foreach my $old_sms_info (keys %$sms_changes) {
+ my ($old_carrier, $old_sms) = split /\t/, $old_sms_info;
+ push(@ffectedChgs, [
+ { carrier => $old_carrier, sms => $old_sms },
+ { carrier => $new_carrier, sms => $new_sms },
+ 'sms_info',
+ $sms_changes->{$old_sms_info}
+ ]);
+ }
+
+ if ( scalar(@ffectedChgs) ){
+ $self->ctx->{affectedChgs} = \@ffectedChgs;
+ }
+ }
+ }
+
return $self->_load_user_with_prefs || Apache2::Const::OK;
}
+sub _parse_prefs_notify_hold_related {
+
+ my $self = shift;
+ my $for_update = shift;
+
+ # create an array of change arrays
+ my @chgs;
+
+ my @phone_notify = $self->cgi->multi_param('phone_notify[]');
+ push(@chgs, \@phone_notify) if scalar(@phone_notify);
+
+ my $turning_on_phone_notify = !$for_update &&
+ scalar(@phone_notify) &&
+ $phone_notify[1] eq 'true';
+ my $turning_off_phone_notify = !$for_update &&
+ scalar(@phone_notify) &&
+ $phone_notify[1] eq 'false';
+
+ my $changing_default_phone = 0;
+ if (!$turning_off_phone_notify) {
+ my @default_phone = $self->cgi->multi_param('default_phone[]');
+ if ($for_update) {
+ while (scalar(@default_phone) > 0) {
+ my $chg = [ splice(@default_phone, 0, 4) ];
+ if (scalar(@default_phone) > 0 && $default_phone[0] eq 'on') {
+ push @$chg, shift(@default_phone);
+ push(@chgs, $chg);
+ $changing_default_phone = 1;
+ }
+ }
+ } else {
+ if (scalar(@default_phone)) {
+ push @chgs, \@default_phone;
+ $changing_default_phone = 1;
+ }
+ }
+ }
+
+ if ($turning_on_phone_notify && $changing_default_phone) {
+ # we don't need to have both the phone_notify and default_phone
+ # changes; the latter will suffice
+ @chgs = grep { $_->[2] ne 'phone_notify' } @chgs;
+ } elsif ($turning_on_phone_notify && !$changing_default_phone) {
+ # replace the phone_notify change with a default_phone change
+ @chgs = grep { $_->[2] ne 'phone_notify' } @chgs;
+ my $default_phone = $self->cgi->param('opac.default_phone'); # we assume this is set
+ push @chgs, [ '', $default_phone, 'default_phone' ];
+ }
+
+ # on to SMS
+ # ... since both carrier and number are needed to send an SMS notifcation,
+ # we need to treat the pair as a unit
+ my @sms_notify = $self->cgi->multi_param('sms_notify[]');
+ push(@chgs, \@sms_notify) if scalar(@sms_notify);
+
+ my $turning_on_sms_notify = !$for_update &&
+ scalar(@sms_notify) &&
+ $sms_notify[1] eq 'true';
+ my $turning_off_sms_notify = !$for_update &&
+ scalar(@sms_notify) &&
+ $sms_notify[1] eq 'false';
+
+ my $changing_sms_info = 0;
+ if (!$turning_off_sms_notify) {
+ my @sms_carrier = $self->cgi->multi_param('default_sms_carrier_id[]');
+ my @sms = $self->cgi->multi_param('default_sms[]');
+
+ if (scalar(@sms) || scalar(@sms_carrier)) {
+ my $new_carrier = scalar(@sms_carrier) ? $sms_carrier[1] : $self->cgi->param('sms_carrier');
+ my $new_sms = scalar(@sms) ? $sms[1] : $self->cgi->param('opac.default_sms_notify');
+ push @chgs, [
+ { carrier => '', sms => '' },
+ { carrier => $new_carrier, sms => $new_sms },
+ 'sms_info'
+ ];
+ $changing_sms_info = 1;
+ }
+ }
+
+ my @sms_info = $self->cgi->multi_param('sms_info[]'); # only sent by confirmation page
+ if (scalar(@sms_info)) {
+ while (scalar(@sms_info) > 0) {
+ my $chg = [ splice(@sms_info, 0, 4) ];
+ if (scalar(@sms_info) > 0 && $sms_info[0] eq 'on') {
+ push @$chg, shift(@sms_info);
+ my ($carrier, $sms) = split /,/, $chg->[0], -1;
+ $chg->[0] = { carrier => $carrier, sms => $sms };
+ ($carrier, $sms) = split /,/, $chg->[1], -1;
+ $chg->[1] = { carrier => $carrier, sms => $sms };
+ push(@chgs, $chg);
+ $changing_sms_info = 1;
+ }
+ }
+ }
+
+ if ($turning_on_sms_notify && $changing_sms_info) {
+ # we don't need to have both the sms_notify and sms_info
+ # changes; the latter will suffice
+ @chgs = grep { $_->[2] ne 'sms_notify' } @chgs;
+ } elsif ($turning_on_sms_notify && !$changing_sms_info) {
+ # replace the sms_notify change with a sms_info change
+ @chgs = grep { $_->[2] ne 'sms_notify' } @chgs;
+ my $sms_info = {
+ carrier => $self->cgi->param('sms_carrier'),
+ sms => $self->cgi->param('opac.default_sms_notify'),
+ };
+ push @chgs, [ { carrier => '', sms => ''}, $sms_info, 'sms_info' ];
+ }
+
+ my @email_notify = $self->cgi->multi_param('email_notify[]');
+ push(@chgs, \@email_notify) if scalar(@email_notify);
+
+ if ($for_update) {
+ # if we're updating, keep only the ones that have been
+ # explicitly checked by the user
+ @chgs = grep { scalar(@$_) == 5 && $_->[4] eq 'on' } @chgs;
+ }
+ return @chgs;
+}
+
+sub load_myopac_prefs_notify_changed_holds {
+ my $self = shift;
+ my $e = $self->editor;
+
+ my $hasChanges = $self->cgi->param('hasHoldsChanges');
+
+ return $self->_load_user_with_prefs || Apache2::Const::OK unless $hasChanges;
+
+ my @ll = $self->_parse_prefs_notify_hold_related(1);
+
+ my @updates;
+ for my $chset (@ll){
+ my ($old, $new, $type, $holdids, $doit) = @$chset;
+ next if $doit ne 'on';
+
+ # parse string list into array list
+ my @holdids = split(',', $holdids);
+
+ if ($type =~ /_notify/){
+ # translate true/false string into 1/0
+ $old = $old eq 'true' ? 1 : 0;
+ $new = $new eq 'true' ? 1 : 0;
+ }
+
+ my $update;
+ if ($type eq 'sms_info') {
+ if ($new->{carrier} eq '' && $new->{sms} eq '') {
+ # clear SMS number first to avoid check contrainst issue
+ $update = $U->simplereq('open-ils.circ', "open-ils.circ.holds.batch_update_holds_by_notify",
+ $e->authtoken, $e->requestor->id, [@holdids], $old->{sms}, $new->{sms}, 'default_sms');
+ push (@updates, $update) if (scalar(@$update) > 0);
+ $update = $U->simplereq('open-ils.circ', "open-ils.circ.holds.batch_update_holds_by_notify",
+ $e->authtoken, $e->requestor->id, [@holdids], $old->{carrier}, $new->{carrier}, 'default_sms_carrier_id');
+ push (@updates, $update) if (scalar(@$update) > 0);
+ } else {
+ $update = $U->simplereq('open-ils.circ', "open-ils.circ.holds.batch_update_holds_by_notify",
+ $e->authtoken, $e->requestor->id, [@holdids], $old->{carrier}, $new->{carrier}, 'default_sms_carrier_id');
+ push (@updates, $update) if (scalar(@$update) > 0);
+ $update = $U->simplereq('open-ils.circ', "open-ils.circ.holds.batch_update_holds_by_notify",
+ $e->authtoken, $e->requestor->id, [@holdids], $old->{sms}, $new->{sms}, 'default_sms');
+ push (@updates, $update) if (scalar(@$update) > 0);
+ }
+ } else {
+ $update = $U->simplereq('open-ils.circ', "open-ils.circ.holds.batch_update_holds_by_notify",
+ $e->authtoken, $e->requestor->id, [@holdids], $old, $new, $type);
+
+ # append affected array to chset
+ if (scalar(@$update) > 0){
+ push(@updates, $update);
+ }
+ }
+ }
+
+ $self->ctx->{'updated'} = \@updates;
+
+ return $self->_load_user_with_prefs || Apache2::Const::OK;
+
+}
+
sub fetch_optin_prefs {
my $self = shift;
my $e = $self->editor;
my $val = {"id" => $_};
$val->{"frozen"} = $self->cgi->param("frozen");
$val->{"pickup_lib"} = $self->cgi->param("pickup_lib");
+ $val->{"email_notify"} = $self->cgi->param("email_notify") ? 1 : 0;
+ $val->{"phone_notify"} = $self->cgi->param("phone_notify");
+ $val->{"sms_notify"} = $self->cgi->param("sms_notify");
+ $val->{"sms_carrier"} = int($self->cgi->param("sms_carrier")) if $val->{"sms_notify"};
for my $field (qw/expire_time thaw_date/) {
# XXX TODO make this support other date formats, not just
[% PROCESS "opac/parts/header.tt2";
PROCESS "opac/parts/misc_util.tt2";
PROCESS "opac/parts/hold_status.tt2";
+ PROCESS "opac/parts/hold_notify.tt2";
PROCESS "opac/parts/myopac/column_sort_support.tt2";
WRAPPER "opac/parts/myopac/base.tt2";
myopac_page = "holds";
<th>[% l('Pickup Location') %]</th>
<th>[% l('Cancel if not filled by') %]</th>
<th>[% l('Status') %]</th>
+ <th>[% l('Notify Method') %]</th>
<th>[% l('Notes') %]</th>
</tr>
</thead>
[% PROCESS get_hold_status hold=hold; %]
</div>
</td>
+ <td>
+ <div name="acct_holds_notify">
+ [% PROCESS get_hold_notify h=ahr; %]
+ </div>
+ </td>
<td class="hold_notes">
[%- FOREACH pubnote IN ahr.notes;
IF pubnote.pub == 't';
<em>[% l('Enter date in MM/DD/YYYY format') %]</em>
</td>
</tr>
+ <tr>
+ <td>[% l('Email Notification') %]</td>
+ <td><input type="checkbox" name="email_notify"
+ [% IF ahr.email_notify == 't' %] checked [% END %] />
+ </td>
+ </tr>
+ <tr>
+ <td>[% l('Phone Notification') %]</td>
+ <td><input type="text" name="phone_notify"
+ value="[% ahr.phone_notify | html %]" /></td>
+ </tr>
+ <tr>
+ <td>[% l('SMS Notification') %]</td>
+ <td><input onblur="check_sms_carrier(event)" type="text" name="sms_notify"
+ value="[% ahr.sms_notify | html %]" /></td>
+ </tr>
+ <tr>
+ <td>[% l('Default Mobile Carrier') %]</td>
+ <td>[% INCLUDE "opac/parts/sms_carrier_selector.tt2" ahr, sms_carrier_hide_warning="true", sms_carrier_hide_label="true" %]</td>
+ </tr>
[% END %]
<tr><td colspan='4'>
prefs_page = 'prefs_notify' %]
<h3 class="sr-only">[% l('Notification Preferences') %]</h3>
-<form method='post'>
- [% setting = 'opac.hold_notify' %]
- <input name='[% setting %]' type="hidden"
- [% IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/>
+ [% IF ctx.affectedChgs %]
- <table class="full-width data_grid" id="acct_search_main"
- title="[% l('Notification Preferences') %]">
- <tbody>
-
- [% IF ctx.updated_user_settings %]
- <tr><td colspan='2'>
- <div class='renew-summary'>
- [% l('Account Successfully Updated') %]
- </div>
- </td></tr>
- [% END %]
+ [% # get hash of sms carriers keyed by id:
+ temp = ctx.search_csc('active','t');
+ tcos = { '0' => 'None' };
+ FOR o IN temp;
+ id = o.id;
+ tcos.$id = o;
+ END;
+ %]
+ <h4 class="">[% l('You have updated notification preferences. Those changes only affect future holds. Would you like to update existing holds to use the new information?') %]</h4>
+ <form id="hold_updates_form" name="hold_updates_form" method='post' action="./prefs_notify_changed_holds" onsubmit='return updateHoldsCheck()'>
+ <table class="full-width data_grid" id="acct_search_main"
+ title="[% l('Notification Preferences') %]">
+ <tbody>
+ [% SET blnk = l('Blank') %]
+ [% FOR c IN ctx.affectedChgs %]
+ <tr>
+ <td>
+ [% IF c.2 == 'sms_info' %]
+ <input type='hidden' name="[% c.2 %][]" value="[% c.0.carrier _ ',' _ c.0.sms | html %]" />
+ <input type='hidden' name="[% c.2 %][]" value="[% c.1.carrier _ ',' _ c.1.sms | html %]" />
+ [% ELSE %]
+ <input type='hidden' name="[% c.2 %][]" value="[% c.0 %]" />
+ <input type='hidden' name="[% c.2 %][]" value="[% c.1 %]" />
+ [% END %]
+ <input type='hidden' name="[% c.2 %][]" value="[% c.2 %]" />
+ <input type='hidden' name="[% c.2 %][]" value="[% FOREACH i IN c.3 %][% i %],[% END %]" />
+ <input id="[% c %]" type="checkbox" onchange="canSubmit(event)" name="[% c.2 %][]"/>
+ [% IF c.2 == 'sms_info' %]
+ [% SET disp_name = l('SMS carrier/number') %]
+ <label for="[% c %]">[% c.3.size %] hold(s) currently with [% disp_name %] set to '[% old = c.0.carrier; tcos.$old.name() ? tcos.$old.name() : blnk | html %]/[% c.0.sms ? c.0.sms : blnk | html %]'. Update to '[% new = c.1.carrier; tcos.$new.name() ? tcos.$new.name() : blnk | html %]/[% c.1.sms ? c.1.sms : blnk | html %]'?</label>
+ [% ELSIF c.2.match('_notify') %]
+ [% SET f_name = c.2.replace("_", " "); Y = l('YES'); N = l('NO') %]
+ <label for="[% c %]">[% c.3.size %] hold(s) currently with [% f_name %] set to [% c.0 == 'false' ? N : Y %]. Update to [% c.1 == 'false' ? N : Y %]?</label>
+ [% ELSE %]
+ [% SET f_name = c.2.replace("_", " ") %]
+ <label for="[% c %]">[% c.3.size %] hold(s) currently with [% f_name %] set to '[% c.0 ? c.0 : blnk %]'. Update to '[% c.1 ? c.1 : blnk %]'?</label>
+ [% END %]
+ </td>
+ </tr>
+ [% END %]
+ </tbody>
+ </table>
+ <input type='submit' disabled value="[% l('Update') %]" class="opac-button" />
+ <a href='/eg/opac/myopac/prefs_notify'>[% l('Continue without updating') %]</a>
+ </form>
+ [% ELSE %]
+ <form id="hold_notify_form" name="hold_notify_form" method='post'>
[% setting = 'opac.hold_notify' %]
- <tr>
- [%# WCAG insists that labels for checkboxes contain the input
- or directly follow the input, which would not look right
- with the rest of the table. As an alternative, we can
- repeat the label as a title attr.
- http://www.w3.org/TR/WCAG20-TECHS/H44.html %]
- [% email_label = l('Notify by Email by default when a hold is ready for pickup?') %]
+ <input name='[% setting %]' type="hidden"
+ [% IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/>
- <td><label for='[% setting %].email'>[% email_label %]</label></td>
- <td>
- <input id='[% setting %].email' name='[% setting %].email'
- type="checkbox" title="[% email_label %]"
- [% IF (matches = ctx.user_setting_map.$setting.match('email')); %] checked='checked' [% END %]/>
- </td>
- </tr>
- [%- IF allow_phone_notifications == 'true';
- setting = 'opac.hold_notify';
- -%]
- <tr>
- [% phone_label = l('Notify by Phone by default when a hold is ready for pickup?') %]
- <td><label for='[% setting %].phone'>[% phone_label %]</label></td>
- <td>
- <input id='[% setting %].phone' name='[% setting %].phone'
- type="checkbox" title="[% phone_label %]"
- [% IF (matches = ctx.user_setting_map.$setting.match('phone')); %] checked='checked' [% END %]/>
- </td>
- </tr>
- [% setting = 'opac.default_phone' %]
- <tr>
- <td><label for='[% setting %]'>[% l('Default Phone Number') %]</label></td>
- <td>
- <input id='[% setting %]' name='[% setting %]' type="text"
- [% IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/>
- </td>
- </tr>
- [%- END %]
- [%- IF ctx.get_org_setting(ctx.search_ou, 'sms.enable') == 1;
- setting = 'opac.hold_notify';
- -%]
- <tr>
- [% sms_label = l('Notify by Text by default when a hold is ready for pickup?') %]
- <td><label for='[% setting %].sms'>[% sms_label %]</label></td>
- <td>
- <input id='[% setting %].sms' name='[% setting %].sms'
- type="checkbox" title="[% sms_label %]"
- [% IF (matches = ctx.user_setting_map.$setting.match('sms')); %] checked='checked' [% END %]/>
- </td>
- </tr>
- <tr>
- <td>[% l('Default Mobile Carrier') %]</td>
- <td>[% INCLUDE "opac/parts/sms_carrier_selector.tt2" sms_carrier_hide_label="true" %]</td>
- </tr>
- [% setting = 'opac.default_sms_notify' %]
- <tr>
- <td><label for='[% setting %]'>[% l('Default Mobile Number') %]</label></td>
- <td>
- <input id='[% setting %]' name='[% setting %]' type="text"
- [% IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/>
- [% l('Hint: use the full 10 digits of your phone #, no spaces, no dashes'); %]
- </td>
- </tr>
- [% END %]
- [% FOR optin IN ctx.opt_in_settings %]
- <tr>
- <td><label for='[% optin.cust.name | uri %]'>[% optin.cust.label | html %]</label></td>
- <td>
- <input type='checkbox' name='setting'
- value='[% optin.cust.name | uri %]'
- id='[% optin.cust.name | uri %]'
- title="[% optin.cust.label | html %]"
- [% IF optin.value %] checked='checked' [% END %]/>
- </td>
- </tr>
- [% END %]
- </tbody>
- </table>
+ <table class="full-width data_grid" id="acct_search_main"
+ title="[% l('Notification Preferences') %]">
+ <tbody>
+
+ [% IF ctx.updated_user_settings %]
+ <tr><td colspan='2'>
+ <div class='renew-summary'>
+ [% l('Account Successfully Updated') %]
+ </div>
+ </td></tr>
+ [% END %]
+
+ [% setting = 'opac.hold_notify' %]
+ <tr>
+ [%# WCAG insists that labels for checkboxes contain the input
+ or directly follow the input, which would not look right
+ with the rest of the table. As an alternative, we can
+ repeat the label as a title attr.
+ http://www.w3.org/TR/WCAG20-TECHS/H44.html %]
+ [% email_label = l('Notify by Email by default when a hold is ready for pickup?') %]
+
+ <td><label for='[% setting %].email'>[% email_label %]</label></td>
+ <td>
+ <input onchange="record_change(event)" id='[% setting %].email' name='[% setting %].email'
+ type="checkbox" title="[% email_label %]"
+ [% IF (matches = ctx.user_setting_map.$setting.match('email')); %] checked='checked' [% END %]/>
+ </td>
+ </tr>
+ [%- IF allow_phone_notifications == 'true';
+ setting = 'opac.hold_notify';
+ -%]
+ <tr>
+ [% phone_label = l('Notify by Phone by default when a hold is ready for pickup?') %]
+ <td><label for='[% setting %].phone'>[% phone_label %]</label></td>
+ <td>
+ <input onchange="record_change(event)" id='[% setting %].phone' name='[% setting %].phone'
+ type="checkbox" title="[% phone_label %]"
+ [% IF (matches = ctx.user_setting_map.$setting.match('phone')); %] checked='checked' [% END %]/>
+ </td>
+ </tr>
+ [% setting = 'opac.default_phone' %]
+ <tr>
+ <td><label for='[% setting %]'>[% l('Default Phone Number') %]</label></td>
+ <td>
+ <input onchange="record_change(event)" id='[% setting %]' name='[% setting %]' type="text"
+ [% IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/>
+ </td>
+ </tr>
+ [%- END %]
+ [%- IF ctx.get_org_setting(ctx.search_ou, 'sms.enable') == 1;
+ setting = 'opac.hold_notify';
+ -%]
+ <tr>
+ [% sms_label = l('Notify by Text by default when a hold is ready for pickup?') %]
+ <td><label for='[% setting %].sms'>[% sms_label %]</label></td>
+ <td>
+ <input onchange="record_change(event)" id='[% setting %].sms' name='[% setting %].sms'
+ type="checkbox" title="[% sms_label %]"
+ [% IF (matches = ctx.user_setting_map.$setting.match('sms')); %] checked='checked' [% END %]/>
+ </td>
+ </tr>
+ <tr>
+ <td>[% l('Default Mobile Carrier') %]</td>
+ <td>[% INCLUDE "opac/parts/sms_carrier_selector.tt2" sms_carrier_hide_label="true" %]</td>
+ </tr>
+ [% setting = 'opac.default_sms_notify' %]
+ <tr>
+ <td><label for='[% setting %]'>[% l('Default Mobile Number') %]</label></td>
+ <td>
+ <input onchange="record_change(event)" id='[% setting %]' name='[% setting %]' type="text"
+ [% IF ctx.user_setting_map.$setting; %] value='[% ctx.user_setting_map.$setting | html %]' [% END %]/>
+ [% l('Hint: use the full 10 digits of your phone #, no spaces, no dashes'); %]
+ </td>
+ </tr>
+ [% END %]
+ [% FOR optin IN ctx.opt_in_settings %]
+ <tr>
+ <td><label for='[% optin.cust.name | uri %]'>[% optin.cust.label | html %]</label></td>
+ <td>
+ <input type='checkbox' name='setting'
+ value='[% optin.cust.name | uri %]'
+ id='[% optin.cust.name | uri %]'
+ title="[% optin.cust.label | html %]"
+ [% IF optin.value %] checked='checked' [% END %]/>
+ </td>
+ </tr>
+ [% END %]
+ </tbody>
+ </table>
- <input type='submit' value="[% l('Save') %]" class="opac-button" />
-</form>
+ <input type='submit' value="[% l('Save') %]" class="opac-button" />
+ </form>
+ [% END %]
[% END %]
--- /dev/null
+[% PROCESS "opac/parts/header.tt2";
+ WRAPPER "opac/parts/myopac/prefs_base.tt2";
+ myopac_page = "prefs";
+ prefs_page = 'prefs_notify' %]
+
+<h3 class="sr-only">[% l('Affected Holds') %]</h3>
+<div id="update_hold_notify_confirm" >
+ [% IF ctx.updated %]
+ <p>[% l('Hold Notification Information Updated.') %]</p>
+<!--
+ <ul>
+ [% FOREACH c IN ctx.updated %]
+ <li>
+ [% l('Holds updated: ') %]
+ [% FOREACH i IN c %]
+ [% i %]
+ [% END %]
+ </li>
+ [% END %]
+ </ul>
+-->
+ [% ELSE %]
+ <p>[% l('No changes') %].</p>
+ [% END %]
+ <a href='/eg/opac/myopac/prefs_notify'>[% l('Continue.') %]</a>
+</form>
+[% END %]
+
+
--- /dev/null
+[% BLOCK get_hold_notify %]
+ [% # get hash of sms carriers keyed by id:
+ temp = ctx.search_csc('active','t');
+ tcos = { '0' => 'None' };
+ FOR o IN temp;
+ id = o.id;
+ tcos.$id = o;
+ END;
+ %]
+ [% SET any_notify = 0 %]
+ <div>
+ [% IF h.email_notify == 't' %]
+ [% any_notify = 1 %]
+ <strong>[% l("Email") %]</strong>: [% l("Yes") %]<br/>
+ [% END %]
+ [% IF h.phone_notify %]
+ [% any_notify = 1 %]
+ <strong>[% l("Phone") %]</strong>: [% h.phone_notify | html %]<br/>
+ [% END %]
+ [% IF h.sms_notify %]
+ [% any_notify = 1, cid = h.sms_carrier; %]
+ <strong>[% l("SMS") %]</strong>: [% h.sms_notify | html %] ([% tcos.$cid.name() | html %])<br/>
+ [% END %]
+ [% UNLESS any_notify %]
+ <span style="color:red">[% l("None") %]</span>
+ [% END %]
+ </div>
+[% END %]
END;
%]
[% IF NOT sms_carrier_hide_label; '<label for="sms_carrier">' _ l('Mobile carrier:') _ '</label>'; END; %]
-<select name="sms_carrier" id="sms_carrier" [% IF sms_carrier_hide_label; 'aria-label="' _ l('Mobile carrier') _ '"'; END; %]>
+<select onchange="record_change(event)" id="sms_carrier" name="sms_carrier" id="sms_carrier" [% IF sms_carrier_hide_label; 'aria-label="' _ l('Mobile carrier') _ '"'; END; %]>
<option value="">[% l('Please select your mobile carrier') %]</option>
[% FOR carrier IN carriers.sort('name','region') -%]
<option value='[% carrier.id | html %]'[%
- default_carrier == carrier.id ? ' selected="selected"' : ''
+ default_carrier == carrier.id || ahr.sms_carrier == carrier.id ? ' selected="selected"' : ''
%]>[% carrier.name | html %] ([% carrier.region | html %])</option>
[% END -%]
</select>
%]
<div class="col-md-3 reg-field-input">
<input
- [% IF type == "email" %]type="text"
+ [% IF type == "email" %]type="text" ng-required="hold_notify_type.email"
[% ELSE %]type="[% type %]"
[% END %]
class="form-control"
<label>{{user_setting_types['opac.default_phone'].label()}}</label>
</div>
<div class="col-md-3 reg-field-input">
- <input
+ <input ng-required="hold_notify_type.phone"
ng-change="field_modified()"
+ ng-blur="handle_field_changed(user_settings, 'opac.default_phone')"
type='text' ng-model="user_settings['opac.default_phone']"/>
</div>
</div>
<label>[% l('Default SMS/Text Number') %]</label>
</div>
<div class="col-md-3 reg-field-input">
- <input
+ <input ng-required="hold_notify_type.sms"
ng-change="field_modified()" ng-model="user_settings['opac.default_sms_notify']"
+ ng-blur="handle_field_changed(user_settings, 'opac.default_sms_notify')"
type='text'/>
</div>
</div>
</div>
<div class="col-md-3 reg-field-input">
<span class="nullable">
- <select str-to-int class="form-control" ng-model="user_settings['opac.default_sms_carrier']" ng-options="c.id() as c.name() for c in sms_carriers">
+ <select str-to-int ng-required="user_settings['opac.default_sms_notify']" class="form-control" ng-model="user_settings['opac.default_sms_carrier']" ng-options="c.id() as c.name() for c in sms_carriers"
+ ng-blur="handle_field_changed(user_settings, 'opac.default_sms_carrier')">
<option value="">Select a Carrier</option>
</select>
</span>
--- /dev/null
+<div class="modal-header">
+ <button type="button" class="close" ng-click="ok('no-update')"
+ aria-hidden="true">×</button>
+ <h4 class="modal-title">[% l('Update Hold Notification Info?') %]</h4>
+</div>
+<div class="modal-body">
+<form name="updateHoldsForm">
+ <div class="row" ng-repeat="f in ch_fields">
+ <div class="col-md-11">
+ <span ng-switch="f.name">
+ <span ng-switch-when="phone_notify">[% l("You have set Notify by Phone to '[_1]'", '{{prettyBool(f.newval)}}') %]</span>
+ <span ng-switch-when="sms_notify">[% l("You have set Notify by SMS to '[_1]'", '{{prettyBool(f.newval)}}') %]</span>
+ <span ng-switch-when="email_notify">[% l("You have set Notify by Email to '[_1]'", '{{prettyBool(f.newval)}}') %]</span>
+ <span ng-switch-when="default_phone">[% l("You have set Default Phone Number to '[_1]'", '{{f.newval}}') %]</span>
+ <span ng-switch-when="default_sms">[% l("You have set Default SMS/Text Number to '[_1]'", '{{f.newval}}') %]</span>
+ <span ng-switch-when="default_sms_carrier_id">[% l("You have set Default SMS Carrier to '[_1]'", '{{prettyCarrier(f.newval)}}') %]</span>
+ </span>
+ <ul style="padding-left:0" ng-if="isNumberCh(f)" class="list-unstyled">
+ <li ng-repeat="(k, h) in f.groups" style="margin-left: 20px">
+ <input id="{{f.name + h[0].id}}" type="checkbox" ng-model="h.isChecked" ng-change="groupChanged(f, k)" style="position: absolute" />
+ <label ng-if="f.newval" for="{{f.name + h[0].id}}" style="padding-left: 1.5em">[% l("'[_1]' is currently used for [_2] hold(s). Update to '[_3]'?", "{{k}}", "{{f.groups[k].length}}", "{{f.newval ? f.newval : '(null)'}}") %]</label>
+ <label ng-if="!f.newval" for="{{f.name + h[0].id}}" style="padding-left: 1.5em">[% l("'[_1]' is currently used for [_2] hold(s). Remove that from the hold(s)?", "{{k}}", "{{f.groups[k].length}}") %]</label>
+ </li>
+ </ul>
+ <ul style="padding-left:0" ng-if="!isNumberCh(f)" class="list-unstyled">
+ <li style="margin-left: 20px">
+ <input id="{{f.name}}" type="checkbox" ng-model="f.isChecked" ng-change="nonGrpChanged(f)" style="position: absolute" />
+ <label ng-if="f.name.includes('sms_carrier')" for="{{f.name}}" style="padding-left: 1.5em">[% l("A carrier other than '[_1]' is currently used in [_2] hold(s). Update to '[_3]'?", "{{prettyCarrier(f.newval)}}", "{{f.affects.length}}", "{{prettyCarrier(f.newval)}}") %]</label>
+ <label ng-if="!f.name.includes('sms_carrier')" for="{{f.name}}" style="padding-left: 1.5em">[% l("[_1] hold(s) have it set to [_2]. Update to [_3]?", "{{f.affects.length}}", "{{prettyBool(f.old)}}", "{{prettyBool(f.newval)}}") %]</label>
+ </li>
+ </ul>
+ </div>
+ </div>
+<div class="modal-footer">
+ <div class="row">
+ <div class="col-md-10 pull-right">
+ <input type="submit" class="btn btn-primary" ng-disabled="chgCt < 1" ng-click="ok()" value="[% l('Update Holds') %]"/>
+ <input type="submit" class="btn btn-warning" ng-click="ok('no-update')" value="[% l('Do Not Update Holds') %]"/>
+ </div>
+ </div>
+
+</div>
<eg-grid-field path='hold.requestor.id' parent-idl-class="ahr" label="[% l('Requestor ID') %]" hidden></eg-grid-field>
<eg-grid-field path='hold.requestor.usrname' parent-idl-class="ahr" label="[% l('Requestor Username') %]" hidden></eg-grid-field>
<eg-grid-field path='hold.sms_carrier.name' parent-idl-class="ahr" label="[% l('Notifications SMS Carrier') %]" hidden></eg-grid-field>
+ <eg-grid-field path='hold.sms_carrier' label="[% l('SMS Carrier') %]" hidden></eg-grid-field>
<eg-grid-field path='part.label' parent-idl-class="bmp" label="[% l('Part') %]" hidden></eg-grid-field>
<eg-grid-field path='volume.*' parent-idl-class="acn" hidden></eg-grid-field>
checkbox.form.submit();
}
+
+// prefs notify update holds-related code
+var hold_notify_prefs = [];
+document.addEventListener("DOMContentLoaded", function() {
+ var form = document.getElementById('hold_notify_form');
+ if (!form) return;
+ var els = form.elements;
+ for (i = 0; i < els.length; i++){
+ var e = els[i];
+ if (e.id.startsWith("opac") || e.id == 'sms_carrier'){
+ hold_notify_prefs.push({
+ name : e.id,
+ oldval : e.type == 'checkbox' ? e.checked : e.value,
+ newval : null
+ });
+ // set required attribute input fields that need it
+ if (e.id.includes('hold_notify') && !e.id.includes('email')){
+ var fieldToReq = e.id.includes('sms') ? 'opac.default_sms_notify' : 'opac.default_phone';
+ toggle_related_required(fieldToReq, e.checked);
+ }
+
+ }
+ }
+ form.addEventListener('submit', addHoldUpdates);
+});
+
+function appendChgInputs(chg){
+ // server-side we'll parse the param as an array where:
+ // [ #oldval, #newval, #name, [#arr of affected holds], #propagateBool ]
+ // this first POST will set the first three, and the confirmation interstitial
+ // the rest.
+ var form = document.getElementById('hold_notify_form');
+
+ var inputold = document.createElement('input');
+ inputold.setAttribute('type', 'hidden');
+ inputold.setAttribute('name', chg.name + '[]');
+ inputold.setAttribute('value', chg.oldval);
+ form.appendChild(inputold);
+
+ var inputnew = document.createElement('input');
+ inputnew.setAttribute('type', 'hidden');
+ inputnew.setAttribute('name', chg.name + '[]');
+ inputnew.setAttribute('value', chg.newval);
+ form.appendChild(inputnew);
+
+ var inputname = document.createElement('input');
+ inputname.setAttribute('type', 'hidden');
+ inputname.setAttribute('name', chg.name + '[]');
+ inputname.setAttribute('value', chg.name);
+ form.appendChild(inputname);
+}
+
+function addHoldUpdates(){
+ paramTranslate(hold_notify_prefs).forEach(function(chg){
+ // only append a change if it actually changed from
+ // what we had server-side originally
+ if (chg.newval != null && chg.oldval != chg.newval) appendChgInputs(chg);
+ });
+ return true;
+}
+
+function chkPh(number){
+ // normalize phone # for comparison, only digits
+ if (number == null || number == undefined) return '';
+ var regex = /[^\d]/g;
+ return number.replace(regex, '');
+}
+
+function idxOfName(n){
+ return hold_notify_prefs.findIndex(function(e){ return e.name === n});
+}
+
+function record_change(evt){
+ var field = evt.target;
+ switch(field.id){
+ case "opac.hold_notify.email":
+ var chg = hold_notify_prefs[idxOfName(field.id)]
+ chg.newval = field.checked;
+ break;
+ case "opac.hold_notify.phone":
+ var chg = hold_notify_prefs[idxOfName(field.id)]
+ chg.newval = field.checked;
+ toggle_related_required('opac.default_phone', chg.newval);
+ break;
+ case "opac.hold_notify.sms":
+ var chg = hold_notify_prefs[idxOfName(field.id)]
+ chg.newval = field.checked;
+ toggle_related_required('opac.default_sms_notify', chg.newval);
+ break;
+ case "sms_carrier": // carrier id string
+ var chg = hold_notify_prefs[idxOfName(field.id)]
+ chg.newval = field.value;
+ break;
+ case "opac.default_phone":
+ var chg = hold_notify_prefs[idxOfName(field.id)]
+ if (chkPh(field.value) != chkPh(chg.oldval)){
+ chg.newval = field.value;
+ }
+ break;
+ case "opac.default_sms_notify":
+ var chg = hold_notify_prefs[idxOfName(field.id)]
+ if (chkPh(field.value) != chkPh(chg.oldval)){
+ chg.newval = field.value;
+ toggle_related_required('sms_carrier', chg.newval ? true : false);
+ }
+ break;
+ }
+}
+
+// there are the param values for the changed fields we expect server-side
+function paramTranslate(chArr){
+ return chArr.map(function(ch){
+ var n = "";
+ switch(ch.name){
+ case "opac.hold_notify.email":
+ n = "email_notify";
+ break;
+ case "opac.hold_notify.phone":
+ n = "phone_notify";
+ break;
+ case "opac.hold_notify.sms":
+ n = "sms_notify";
+ break;
+ case "sms_carrier": // carrier id string
+ n = "default_sms_carrier_id";
+ break;
+ case "opac.default_phone":
+ n = "default_phone";
+ break;
+ case "opac.default_sms_notify":
+ n = "default_sms";
+ break;
+ }
+ return { name : n, oldval : ch.oldval, newval : ch.newval };
+ });
+}
+
+function updateHoldsCheck() {
+ // just dynamically add an input that flags that we have
+ // holds-related updates
+ var form = document.getElementById('hold_updates_form');
+ if (!form) return;
+ var els = form.elements;
+ var isValid = false;
+ for (i = 0; i < els.length; i++){
+ var e = els[i];
+ if (e.type == "checkbox" && e.checked){
+ var flag = document.createElement('input');
+ flag.setAttribute('name', 'hasHoldsChanges');
+ flag.setAttribute('type', 'hidden');
+ flag.setAttribute('value', 1);
+ form.appendChild(flag);
+ isValid = true;
+ return isValid;
+ }
+ }
+
+ alert("No option selected.");
+ return isValid;
+}
+
+function check_sms_carrier(e){
+ var sms_num = e.target;
+ // if sms number has anything in it that's not just whitespace, then require a carrier
+ if (!sms_num.value.match(/\S+/)) return;
+
+ var carrierSelect = document.getElementById('sms_carrier');
+ if (carrierSelect.selectedIndex == 0){
+ carrierSelect.setAttribute("required", "");
+ }
+
+}
+
+function canSubmit(evt){
+ // check hold updates form to see if we have any selected
+ // enable the submit button if we do
+ var form = document.getElementById('hold_updates_form');
+ var submit = form.querySelector('input[type="submit"]');
+ if (!form || !submit) return;
+ var els = form.elements;
+ for (i = 0; i < els.length; i++){
+ var e = els[i];
+ if (e.type == "checkbox" && !e.hidden && e.checked){
+ submit.removeAttribute("disabled");
+ return;
+ }
+ }
+
+ submit.setAttribute("disabled","");
+}
+
+function toggle_related_required(id, isRequired){
+ var input = document.getElementById(id);
+ input.required = isRequired;
+}
$scope.page_data_loaded = false;
$scope.hold_notify_type = { phone : null, email : null, sms : null };
+ $scope.hold_notify_observer = {};
+ $scope.hold_rel_contacts = {};
$scope.clone_id = patronRegSvc.clone_id = $routeParams.clone_id;
$scope.stage_username =
patronRegSvc.stage_username = $routeParams.stage_username;
}
extract_hold_notify();
+
if ($scope.patron.isnew)
set_new_patron_defaults(prs);
}
});
}
+
+ // add watchers for hold notify method prefs
+ $scope.$watch('hold_notify_type.phone', function(newVal, oldVal) {
+ var notifyOpt = $scope.hold_notify_observer['phone'];
+ if (newVal !== null) {
+ notifyOpt.newval = newVal;
+ }
+ });
+
+ $scope.$watch('hold_notify_type.sms', function(newVal, oldVal) {
+ var notifyOpt = $scope.hold_notify_observer['sms'];
+ if (newVal !== null) {
+ notifyOpt.newval = newVal;
+ }
+ });
+
+ $scope.$watch('hold_notify_type.email', function(newVal, oldVal) {
+ var notifyOpt = $scope.hold_notify_observer['email'];
+ if (newVal !== null) {
+ notifyOpt.newval = newVal;
+ }
+ });
// update the currently displayed field documentation
$scope.set_selected_field_doc = function(cls, field) {
}
function extract_hold_notify() {
- var notify = $scope.user_settings['opac.hold_notify'];
- if (!notify) return;
+ var p = $scope.patron;
+ var notify = $scope.user_settings['opac.hold_notify'] || '';
+
$scope.hold_notify_type.phone = Boolean(notify.match(/phone/));
$scope.hold_notify_type.email = Boolean(notify.match(/email/));
$scope.hold_notify_type.sms = Boolean(notify.match(/sms/));
+
+ // stores original loaded values for comparison later
+ for (var k in $scope.hold_notify_type){
+ var val = $scope.hold_notify_type[k];
+
+ if ($scope.hold_notify_type.hasOwnProperty(k)){
+ $scope.hold_notify_observer[k] = {old : val, newval: null};
+ }
+ }
+
+ // actual value from user
+ $scope.hold_rel_contacts.day_phone = { old: p.day_phone, newval : null };
+ $scope.hold_rel_contacts.other_phone = { old: p.other_phone, newval : null };
+ $scope.hold_rel_contacts.evening_phone = { old: p.evening_phone, newval : null };
+ // from user_settings
+ $scope.hold_rel_contacts.default_phone = { old: $scope.user_settings['opac.default_phone'], newval : null };
+ $scope.hold_rel_contacts.default_sms = { old: $scope.user_settings['opac.default_sms_notify'], newval : null };
+ $scope.hold_rel_contacts.default_sms_carrier_id = { old: $scope.user_settings['opac.default_sms_carrier'], newval : null };
+
+ }
+
+ function normalizePhone(number){
+ // normalize phone # for comparison, only digits
+ if (number == null || number == undefined) return '';
+
+ var regex = /[^\d]/g;
+ return number.replace(regex, '');
}
$scope.invalidate_field = function(field) {
- patronRegSvc.invalidate_field($scope.patron, field);
+ patronRegSvc.invalidate_field($scope.patron, field).then(function() {
+ $scope.handle_field_changed($scope.patron, field);
+ });
}
address_alert = function(addr) {
console.debug('changing field ' + field_name + ' to ' + value);
switch (field_name) {
- case 'day_phone' :
+ case 'day_phone' :
+ if (normalizePhone(value) !== normalizePhone($scope.hold_rel_contacts.day_phone.old)){
+ $scope.hold_rel_contacts.day_phone.newval = value;
+ }
if ($scope.patron.day_phone &&
$scope.patron.isnew &&
$scope.org_settings['patron.password.use_phone']) {
$scope.patron.passwd = $scope.patron.day_phone.substr(-4);
}
- case 'evening_phone' :
+ $scope.dupe_value_changed(field_name, value);
+ break;
+ case 'evening_phone' :
+ if (normalizePhone(value) !== normalizePhone($scope.hold_rel_contacts.evening_phone.old)){
+ $scope.hold_rel_contacts.evening_phone.newval = value;
+ }
+ $scope.dupe_value_changed(field_name, value);
+ break;
case 'other_phone' :
+ if (normalizePhone(value) !== normalizePhone($scope.hold_rel_contacts.other_phone.old)){
+ $scope.hold_rel_contacts.other_phone.newval = value;
+ }
$scope.dupe_value_changed(field_name, value);
break;
-
case 'ident_value':
case 'ident_value2':
$scope.dupe_value_changed('ident', value);
$scope.barcode_changed(value);
apply_username_regex();
break;
+ case 'opac.default_phone':
+ if (normalizePhone(value) !== normalizePhone($scope.hold_rel_contacts.default_phone.old)){
+ $scope.hold_rel_contacts.default_phone.newval = value;
+ }
+ break;
+ case 'opac.default_sms_notify':
+ if (normalizePhone(value) !== normalizePhone($scope.hold_rel_contacts.default_sms.old)){
+ $scope.hold_rel_contacts.default_sms.newval = value;
+ }
+ break;
+ case 'opac.default_sms_carrier':
+ if (value !== $scope.hold_rel_contacts.default_sms_carrier_id.old){
+ $scope.hold_rel_contacts.default_sms_carrier_id.newval = value;
+ }
+ break;
}
}
var ids = $scope.patron.groups.map(function(g) {return g.id()});
return patronRegSvc.apply_secondary_groups(updated_user.id(), ids)
}
-
return $q.when();
+ }).then(findChangedFieldsAffectedHolds)
+ .then(function(changed_fields_plus_holds) {
+ var needModal = changed_fields_plus_holds[0] && changed_fields_plus_holds[0].length > 0;
+ return needModal
+ ? $scope.update_holds_notify_modal(changed_fields_plus_holds[0])
+ : $q.when(); // nothing changed, continue
}).then(function() {
-
if (updated_user) {
egWorkLog.record(
$scope.patron.isnew
}
});
}
+
+ var phone_inputs = ["day_phone", "evening_phone","other_phone", "default_phone"];
+ var sms_inputs = ["default_sms", "default_sms_carrier_id"];
+ var method_prefs = ["sms_notify", "phone_notify", "email_notify"];
+ var groupBy = function(xs, key){
+ return xs.reduce(function(rv, x){
+ (rv[x[key]] = rv[x[key]] || []).push(x);
+ return rv;
+ }, {});
+ };
+
+ function findChangedFieldsAffectedHolds(){
+
+ var changed_hold_fields = [];
+
+ var default_phone_changed = false;
+ var default_sms_carrier_changed = false;
+ var default_sms_changed = false;
+ for (var c in $scope.hold_rel_contacts){
+ var newinput = $scope.hold_rel_contacts[c].newval;
+ if ($scope.hold_rel_contacts.hasOwnProperty(c)
+ && newinput !== null // null means user has not provided a value in this session
+ && newinput != $scope.hold_rel_contacts[c].old){
+ var changed = $scope.hold_rel_contacts[c];
+ changed.name = c;
+ changed.isChecked = false;
+ changed_hold_fields.push(changed);
+ if (c === 'default_phone') default_phone_changed = true;
+ if (c === 'default_sms_carrier_id') default_sms_carrier_changed = true;
+ if (c === 'default_sms') default_sms_changed = true;
+ }
+ }
+ for (var c in $scope.hold_notify_observer){
+ var newinput = $scope.hold_notify_observer[c].newval;
+ if ($scope.hold_notify_observer.hasOwnProperty(c)
+ && newinput !== null // null means user has not provided a value in this session
+ && newinput != $scope.hold_notify_observer[c].old){
+ var changed = $scope.hold_notify_observer[c];
+ changed.name = c + "_notify";
+ changed.isChecked = false;
+ changed_hold_fields.push(changed);
+
+ // if we're turning on phone notifications, offer to update to the
+ // current default number
+ if (c === 'phone' && $scope.user_settings['opac.default_phone'] && newinput && !default_phone_changed) {
+ changed_hold_fields.push({
+ name: 'default_phone',
+ old: 'nosuch',
+ newval: $scope.user_settings['opac.default_phone'],
+ isChecked: false
+ });
+ }
+ // and similarly for SMS
+ if (c === 'sms' && $scope.user_settings['opac.default_sms_carrier'] && newinput && !default_sms_carrier_changed) {
+ changed_hold_fields.push({
+ name: 'default_sms_carrier_id',
+ old: -1,
+ newval: $scope.user_settings['opac.default_sms_carrier'],
+ isChecked: false
+ });
+ }
+ if (c === 'sms' && $scope.user_settings['opac.default_sms_notify'] && newinput && !default_sms_changed) {
+ changed_hold_fields.push({
+ name: 'default_sms',
+ old: 'nosuch',
+ newval: $scope.user_settings['opac.default_sms_notify'],
+ isChecked: false
+ });
+ }
+ }
+ }
+
+ var promises = [];
+ angular.forEach(changed_hold_fields, function(c){
+ promises.push(egCore.net.request('open-ils.circ',
+ 'open-ils.circ.holds.retrieve_by_notify_staff',
+ egCore.auth.token(),
+ $scope.patron.id,
+ c.name.includes('notify') || c.name.includes('carrier') ? c.old : c.newval,
+ c.name)
+ .then(function(affected_holds){
+ if(!affected_holds || affected_holds.length < 1){
+ // no holds affected - remove change from list
+ var p = changed_hold_fields.indexOf(c);
+ changed_hold_fields.splice(p, 1);
+ } else {
+ c.affects = affected_holds;
+ //c.groups = {};
+ //angular.forEach(c.affects, function(h){
+ // c.groups[]
+ //});
+ if (!c.name.includes("notify")){
+ if (c.name === "default_sms_carrier_id") {
+ c.groups = groupBy(c.affects,'sms_carrier');
+ } else {
+ c.groups = groupBy(c.affects, c.name.includes('_phone') ? 'phone_notify':'sms_notify');
+ }
+ }
+ }
+ return $q.when(changed_hold_fields);
+ })
+ );
+ });
+
+ return $q.all(promises);
+ }
+
+ $scope.update_holds_notify_modal = function(changed_hold_fields){
+ // open modal after-save, pre-reload modal to deal with updated hold notification stuff
+ if ($scope.patron.isnew || changed_hold_fields.length < 1){
+ return $q.when();
+ }
+
+ return $uibModal.open({
+ templateUrl: './circ/patron/t_hold_notify_update',
+ backdrop: 'static',
+ controller:
+ ['$scope','$uibModalInstance','changed_fields','patron','carriers','def_carrier_id','default_phone','default_sms',
+ function($scope , $uibModalInstance , changed_fields , patron, carriers, def_carrier_id , default_phone , default_sms) {
+ // local modal scope
+ $scope.ch_fields = changed_fields;
+ $scope.focusMe = true;
+ $scope.ok = function(msg) {
+
+ // Need to do this so the page will reload automatically
+ if (msg == 'no-update') return $uibModalInstance.close();
+
+ //var selectedChanges = $scope.changed_fields.filter(function(c) {
+ // return c.isChecked;
+ //});
+ var selectedChanges = [];
+ angular.forEach($scope.ch_fields, function(f){
+ if (f.name == 'phone_notify' && f.newval && f.isChecked) {
+ // convert to default_phone change
+ f.sel_hids = f.affects.map(function(h){ return h.id});
+ f.newval = default_phone;
+ f.name = 'default_phone';
+ selectedChanges.push(f);
+ } else if (f.name == 'sms_notify' && f.newval && f.isChecked) {
+ // convert to default_sms change
+ f.sel_hids = f.affects.map(function(h){ return h.id});
+ f.newval = default_sms;
+ f.name = 'default_sms';
+ selectedChanges.push(f);
+ } else if (f.name.includes('notify') || f.name.includes('carrier')){
+ if (f.isChecked){
+ f.sel_hids = f.affects.map(function(h){ return h.id});
+ selectedChanges.push(f);
+ }
+ } else {
+ // this is the sms or phone, so look in the groups obj
+ f.sel_hids = [];
+ for (var k in f.groups){
+ if (f.groups.hasOwnProperty(k)){
+ var sel_holds = f.groups[k].filter(function(h){
+ return h.isChecked;
+ });
+
+ var hids = sel_holds.map(function(h){ return h.id});
+ f.sel_hids.push.apply(f.sel_hids, hids);
+ }
+ }
+
+ if (f.sel_hids.length > 0) selectedChanges.push(f);
+ }
+ });
+
+
+ // call method to update holds for each change
+ var chain = $q.when();
+ angular.forEach(selectedChanges, function(c){
+ var carrierId = c.name.includes('default_sms') ? Number(def_carrier_id) : null;
+ chain = chain.then(function() {
+ return egCore.net.request('open-ils.circ',
+ 'open-ils.circ.holds.batch_update_holds_by_notify_staff', egCore.auth.token(),
+ patron.id,
+ c.sel_hids,
+ c.old, // TODO: for number changes, old val is effectively moot
+ c.newval,
+ c.name,
+ carrierId).then(function(okList){ console.log(okList) });
+ });
+ });
+
+ // carry out the updates and close modal
+ chain.finally(function(){ $uibModalInstance.close() });
+ }
+
+ $scope.cancel = function () { $uibModalInstance.dismiss() }
+
+ $scope.isNumberCh = function(c){
+ return !(c.name.includes('notify') || c.name.includes('carrier'));
+ }
+
+ $scope.chgCt = 0;
+ $scope.groupChanged = function(ch_f, grpK){
+ var holdArr = ch_f.groups[grpK];
+ if (holdArr && holdArr.length > 0){
+ angular.forEach(holdArr, function(h){
+ if (h.isChecked) { h.isChecked = !h.isChecked; $scope.chgCt-- }
+ else { h.isChecked = true; $scope.chgCt++ }
+ });
+ }
+ }
+
+ $scope.nonGrpChanged = function(field_ch){
+ if (field_ch.isChecked) $scope.chgCt++;
+ else $scope.chgCt--;
+ };
+
+ // use this function as a keydown handler on form
+ // elements that should not submit the form on enter.
+ $scope.preventSubmit = function($event) {
+ if ($event.keyCode == 13)
+ $event.preventDefault();
+ }
+
+ $scope.prettyCarrier = function(carrierId){
+ var sms_carrierObj = carriers.find(function(c){ return c.id == carrierId});
+ return sms_carrierObj.name;
+ };
+ $scope.prettyBool = function(v){
+ return v ? 'YES' : 'NO';
+ };
+ }],
+ resolve : {
+ changed_fields : function(){ return changed_hold_fields },
+ patron : function(){ return $scope.patron },
+ def_carrier_id : function(){
+ var d = $scope.hold_rel_contacts.default_sms_carrier_id;
+ return d.newval ? d.newval : d.old;
+ },
+ default_phone : function() {
+ return ($scope.hold_rel_contacts.default_phone.newval) ?
+ $scope.hold_rel_contacts.default_phone.newval :
+ $scope.hold_rel_contacts.default_phone.old;
+ },
+ default_sms : function() {
+ return ($scope.hold_rel_contacts.default_sms.newval) ?
+ $scope.hold_rel_contacts.default_sms.newval :
+ $scope.hold_rel_contacts.default_sms.old;
+ },
+ carriers : function(){ return $scope.sms_carriers.map(function(c){ return egCore.idl.toHash(c) }) }
+ }
+ }).result;
+ }
+
$scope.edit_passthru.print = function() {
var print_data = {patron : $scope.patron}