| Filename | /mnt/catalyst/koha/C4/Members/Messaging.pm |
| Statements | Executed 10 statements in 867µs |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 544µs | 559µs | C4::Members::Messaging::BEGIN@20 |
| 1 | 1 | 1 | 12µs | 14µs | C4::Members::Messaging::BEGIN@22 |
| 1 | 1 | 1 | 9µs | 30µs | C4::Members::Messaging::BEGIN@24 |
| 1 | 1 | 1 | 8µs | 17µs | C4::Members::Messaging::BEGIN@21 |
| 1 | 1 | 1 | 4µs | 4µs | C4::Members::Messaging::BEGIN@26 |
| 0 | 0 | 0 | 0s | 0s | C4::Members::Messaging::GetMessagingOptions |
| 0 | 0 | 0 | 0s | 0s | C4::Members::Messaging::GetMessagingPreferences |
| 0 | 0 | 0 | 0s | 0s | C4::Members::Messaging::SetMessagingPreference |
| 0 | 0 | 0 | 0s | 0s | C4::Members::Messaging::SetMessagingPreferencesFromDefaults |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package C4::Members::Messaging; | ||||
| 2 | |||||
| 3 | # Copyright (C) 2008 LibLime | ||||
| 4 | # | ||||
| 5 | # This file is part of Koha. | ||||
| 6 | # | ||||
| 7 | # Koha is free software; you can redistribute it and/or modify it under the | ||||
| 8 | # terms of the GNU General Public License as published by the Free Software | ||||
| 9 | # Foundation; either version 2 of the License, or (at your option) any later | ||||
| 10 | # version. | ||||
| 11 | # | ||||
| 12 | # Koha is distributed in the hope that it will be useful, but WITHOUT ANY | ||||
| 13 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | ||||
| 14 | # A PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||||
| 15 | # | ||||
| 16 | # You should have received a copy of the GNU General Public License along | ||||
| 17 | # with Koha; if not, write to the Free Software Foundation, Inc., | ||||
| 18 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
| 19 | |||||
| 20 | 2 | 29µs | 2 | 573µs | # spent 559µs (544+15) within C4::Members::Messaging::BEGIN@20 which was called:
# once (544µs+15µs) by C4::Reserves::BEGIN@34 at line 20 # spent 559µs making 1 call to C4::Members::Messaging::BEGIN@20
# spent 15µs making 1 call to strict::import |
| 21 | 2 | 22µs | 2 | 25µs | # spent 17µs (8+8) within C4::Members::Messaging::BEGIN@21 which was called:
# once (8µs+8µs) by C4::Reserves::BEGIN@34 at line 21 # spent 17µs making 1 call to C4::Members::Messaging::BEGIN@21
# spent 8µs making 1 call to warnings::import |
| 22 | 2 | 26µs | 2 | 16µs | # spent 14µs (12+2) within C4::Members::Messaging::BEGIN@22 which was called:
# once (12µs+2µs) by C4::Reserves::BEGIN@34 at line 22 # spent 14µs making 1 call to C4::Members::Messaging::BEGIN@22
# spent 2µs making 1 call to C4::Context::import |
| 23 | |||||
| 24 | 2 | 30µs | 2 | 52µs | # spent 30µs (9+22) within C4::Members::Messaging::BEGIN@24 which was called:
# once (9µs+22µs) by C4::Reserves::BEGIN@34 at line 24 # spent 30µs making 1 call to C4::Members::Messaging::BEGIN@24
# spent 22µs making 1 call to vars::import |
| 25 | |||||
| 26 | # spent 4µs within C4::Members::Messaging::BEGIN@26 which was called:
# once (4µs+0s) by C4::Reserves::BEGIN@34 at line 29 | ||||
| 27 | # set the version for version checking | ||||
| 28 | 1 | 4µs | $VERSION = 3.07.00.049; | ||
| 29 | 1 | 752µs | 1 | 4µs | } # spent 4µs making 1 call to C4::Members::Messaging::BEGIN@26 |
| 30 | |||||
| 31 | =head1 NAME | ||||
| 32 | |||||
| 33 | C4::Members::Messaging - manage patron messaging preferences | ||||
| 34 | |||||
| 35 | =head1 SYNOPSIS | ||||
| 36 | |||||
| 37 | use C4::Members::Messaging | ||||
| 38 | |||||
| 39 | =head1 DESCRIPTION | ||||
| 40 | |||||
| 41 | This module lets you modify a patron's messaging preferences. | ||||
| 42 | |||||
| 43 | =head1 FUNCTIONS | ||||
| 44 | |||||
| 45 | =head2 GetMessagingPreferences | ||||
| 46 | |||||
| 47 | my $preferences = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $borrower->{'borrowernumber'}, | ||||
| 48 | message_name => 'DUE' } ); | ||||
| 49 | |||||
| 50 | my $preferences = C4::Members::Messaging::GetMessagingPreferences( { categorycode => 'LIBRARY', | ||||
| 51 | message_name => 'DUE' } ); | ||||
| 52 | |||||
| 53 | returns: a hashref of messaging preferences for a borrower or patron category for a particlar message_name | ||||
| 54 | |||||
| 55 | Requires either a borrowernumber or a categorycode key, but not both. | ||||
| 56 | |||||
| 57 | =cut | ||||
| 58 | |||||
| 59 | sub GetMessagingPreferences { | ||||
| 60 | my $params = shift; | ||||
| 61 | |||||
| 62 | return unless exists $params->{message_name}; | ||||
| 63 | return unless exists $params->{borrowernumber} xor exists $params->{categorycode}; # yes, xor | ||||
| 64 | my $sql = <<'END_SQL'; | ||||
| 65 | SELECT borrower_message_preferences.*, | ||||
| 66 | borrower_message_transport_preferences.message_transport_type, | ||||
| 67 | message_attributes.message_name, | ||||
| 68 | message_attributes.takes_days, | ||||
| 69 | message_transports.is_digest, | ||||
| 70 | message_transports.letter_module, | ||||
| 71 | message_transports.letter_code | ||||
| 72 | FROM borrower_message_preferences | ||||
| 73 | LEFT JOIN borrower_message_transport_preferences | ||||
| 74 | ON borrower_message_transport_preferences.borrower_message_preference_id = borrower_message_preferences.borrower_message_preference_id | ||||
| 75 | LEFT JOIN message_attributes | ||||
| 76 | ON message_attributes.message_attribute_id = borrower_message_preferences.message_attribute_id | ||||
| 77 | JOIN message_transports | ||||
| 78 | ON message_transports.message_attribute_id = message_attributes.message_attribute_id | ||||
| 79 | AND message_transports.message_transport_type = borrower_message_transport_preferences.message_transport_type | ||||
| 80 | WHERE message_attributes.message_name = ? | ||||
| 81 | END_SQL | ||||
| 82 | |||||
| 83 | my @bind_params = ( $params->{'message_name'} ); | ||||
| 84 | if ( exists $params->{'borrowernumber'} ) { | ||||
| 85 | $sql .= " AND borrower_message_preferences.borrowernumber = ? "; | ||||
| 86 | push @bind_params, $params->{borrowernumber}; | ||||
| 87 | } else { | ||||
| 88 | $sql .= " AND borrower_message_preferences.categorycode = ? "; | ||||
| 89 | push @bind_params, $params->{categorycode}; | ||||
| 90 | } | ||||
| 91 | |||||
| 92 | my $sth = C4::Context->dbh->prepare($sql); | ||||
| 93 | $sth->execute(@bind_params); | ||||
| 94 | my $return; | ||||
| 95 | my %transports; # helps build a list of unique message_transport_types | ||||
| 96 | ROW: while ( my $row = $sth->fetchrow_hashref() ) { | ||||
| 97 | next ROW unless $row->{'message_attribute_id'}; | ||||
| 98 | $return->{'days_in_advance'} = $row->{'days_in_advance'} if defined $row->{'days_in_advance'}; | ||||
| 99 | $return->{'wants_digest'} = $row->{'wants_digest'} if defined $row->{'wants_digest'}; | ||||
| 100 | $return->{'letter_code'} = $row->{'letter_code'}; | ||||
| 101 | $return->{'transports'}->{ $row->{'message_transport_type'} } = $row->{'letter_code'}; | ||||
| 102 | } | ||||
| 103 | return $return; | ||||
| 104 | } | ||||
| 105 | |||||
| 106 | =head2 SetMessagingPreference | ||||
| 107 | |||||
| 108 | This method defines how a user (or a default for a patron category) wants to get a certain | ||||
| 109 | message delivered. The list of valid message types can be delivered can be found in the | ||||
| 110 | C<message_attributes> table, and the list of valid message transports can be | ||||
| 111 | found in the C<message_transport_types> table. | ||||
| 112 | |||||
| 113 | C4::Members::Messaging::SetMessagingPreference( { borrowernumber => $borrower->{'borrowernumber'} | ||||
| 114 | message_attribute_id => $message_attribute_id, | ||||
| 115 | message_transport_types => [ qw( email sms ) ], | ||||
| 116 | days_in_advance => 5 | ||||
| 117 | wants_digest => 1 } ) | ||||
| 118 | |||||
| 119 | returns nothing useful. | ||||
| 120 | |||||
| 121 | =cut | ||||
| 122 | |||||
| 123 | sub SetMessagingPreference { | ||||
| 124 | my $params = shift; | ||||
| 125 | |||||
| 126 | unless (exists $params->{borrowernumber} xor exists $params->{categorycode}) { # yes, xor | ||||
| 127 | warn "SetMessagingPreference called without exactly one of borrowernumber or categorycode"; | ||||
| 128 | return; | ||||
| 129 | } | ||||
| 130 | foreach my $required ( qw( message_attribute_id message_transport_types ) ) { | ||||
| 131 | if ( ! exists $params->{ $required } ) { | ||||
| 132 | warn "SetMessagingPreference called without required parameter: $required"; | ||||
| 133 | return; | ||||
| 134 | } | ||||
| 135 | } | ||||
| 136 | $params->{'days_in_advance'} = undef unless exists ( $params->{'days_in_advance'} ); | ||||
| 137 | $params->{'wants_digest'} = 0 unless exists ( $params->{'wants_digest'} ); | ||||
| 138 | |||||
| 139 | my $dbh = C4::Context->dbh(); | ||||
| 140 | |||||
| 141 | my $delete_sql = <<'END_SQL'; | ||||
| 142 | DELETE FROM borrower_message_preferences | ||||
| 143 | WHERE message_attribute_id = ? | ||||
| 144 | END_SQL | ||||
| 145 | my @bind_params = ( $params->{'message_attribute_id'} ); | ||||
| 146 | if ( exists $params->{'borrowernumber'} ) { | ||||
| 147 | $delete_sql .= " AND borrowernumber = ? "; | ||||
| 148 | push @bind_params, $params->{borrowernumber}; | ||||
| 149 | } else { | ||||
| 150 | $delete_sql .= " AND categorycode = ? "; | ||||
| 151 | push @bind_params, $params->{categorycode}; | ||||
| 152 | } | ||||
| 153 | my $sth = $dbh->prepare( $delete_sql ); | ||||
| 154 | my $deleted = $sth->execute( @bind_params ); | ||||
| 155 | |||||
| 156 | if ( $params->{'message_transport_types'} ) { | ||||
| 157 | my $insert_bmp = <<'END_SQL'; | ||||
| 158 | INSERT INTO borrower_message_preferences | ||||
| 159 | (borrower_message_preference_id, borrowernumber, categorycode, message_attribute_id, days_in_advance, wants_digest) | ||||
| 160 | VALUES | ||||
| 161 | (NULL, ?, ?, ?, ?, ?) | ||||
| 162 | END_SQL | ||||
| 163 | |||||
| 164 | $sth = C4::Context->dbh()->prepare($insert_bmp); | ||||
| 165 | # set up so that we can easily construct the insert SQL | ||||
| 166 | $params->{'borrowernumber'} = undef unless exists ( $params->{'borrowernumber'} ); | ||||
| 167 | $params->{'categorycode'} = undef unless exists ( $params->{'categorycode'} ); | ||||
| 168 | my $success = $sth->execute( $params->{'borrowernumber'}, | ||||
| 169 | $params->{'categorycode'}, | ||||
| 170 | $params->{'message_attribute_id'}, | ||||
| 171 | $params->{'days_in_advance'}, | ||||
| 172 | $params->{'wants_digest'} ); | ||||
| 173 | # my $borrower_message_preference_id = $dbh->last_insert_id(); | ||||
| 174 | my $borrower_message_preference_id = $dbh->{'mysql_insertid'}; | ||||
| 175 | |||||
| 176 | my $insert_bmtp = <<'END_SQL'; | ||||
| 177 | INSERT INTO borrower_message_transport_preferences | ||||
| 178 | (borrower_message_preference_id, message_transport_type) | ||||
| 179 | VALUES | ||||
| 180 | (?, ?) | ||||
| 181 | END_SQL | ||||
| 182 | $sth = C4::Context->dbh()->prepare($insert_bmtp); | ||||
| 183 | foreach my $transport ( @{$params->{'message_transport_types'}}) { | ||||
| 184 | my $success = $sth->execute( $borrower_message_preference_id, $transport ); | ||||
| 185 | } | ||||
| 186 | } | ||||
| 187 | return; | ||||
| 188 | } | ||||
| 189 | |||||
| 190 | =head2 GetMessagingOptions | ||||
| 191 | |||||
| 192 | my $messaging_options = C4::Members::Messaging::GetMessagingOptions() | ||||
| 193 | |||||
| 194 | returns a hashref of messaging options available. | ||||
| 195 | |||||
| 196 | =cut | ||||
| 197 | |||||
| 198 | sub GetMessagingOptions { | ||||
| 199 | |||||
| 200 | my $sql = <<'END_SQL'; | ||||
| 201 | select message_attributes.message_attribute_id, takes_days, message_name, message_transport_type, is_digest | ||||
| 202 | FROM message_attributes | ||||
| 203 | LEFT JOIN message_transports | ||||
| 204 | ON message_attributes.message_attribute_id = message_transports.message_attribute_id | ||||
| 205 | END_SQL | ||||
| 206 | |||||
| 207 | my $sth = C4::Context->dbh->prepare($sql); | ||||
| 208 | $sth->execute(); | ||||
| 209 | my $choices; | ||||
| 210 | while ( my $row = $sth->fetchrow_hashref() ) { | ||||
| 211 | $choices->{ $row->{'message_name'} }->{'message_attribute_id'} = $row->{'message_attribute_id'}; | ||||
| 212 | $choices->{ $row->{'message_name'} }->{'message_name'} = $row->{'message_name'}; | ||||
| 213 | $choices->{ $row->{'message_name'} }->{'takes_days'} = $row->{'takes_days'}; | ||||
| 214 | $choices->{ $row->{'message_name'} }->{'has_digest'} = 1 if $row->{'is_digest'}; | ||||
| 215 | $choices->{ $row->{'message_name'} }->{'transport_' . $row->{'message_transport_type'}} = ' '; | ||||
| 216 | } | ||||
| 217 | |||||
| 218 | my @return = values %$choices; | ||||
| 219 | # warn( Data::Dumper->Dump( [ \@return ], [ 'return' ] ) ); | ||||
| 220 | return \@return; | ||||
| 221 | } | ||||
| 222 | |||||
| 223 | =head2 SetMessagingPreferencesFromDefaults | ||||
| 224 | |||||
| 225 | C4::Members::Messaging::SetMessagingPreferenceFromDefaults( { borrowernumber => $borrower->{'borrowernumber'} | ||||
| 226 | categorycode => 'CPL' } ); | ||||
| 227 | |||||
| 228 | Given a borrowernumber and a patron category code (from the C<borrowernumber> and C<categorycode> keys | ||||
| 229 | in the parameter hashref), replace all of the patron's current messaging preferences with | ||||
| 230 | whatever defaults are defined for the patron category. | ||||
| 231 | |||||
| 232 | =cut | ||||
| 233 | |||||
| 234 | sub SetMessagingPreferencesFromDefaults { | ||||
| 235 | my $params = shift; | ||||
| 236 | |||||
| 237 | foreach my $required ( qw( borrowernumber categorycode ) ) { | ||||
| 238 | unless ( exists $params->{ $required } ) { | ||||
| 239 | die "SetMessagingPreferencesFromDefaults called without required parameter: $required"; | ||||
| 240 | } | ||||
| 241 | } | ||||
| 242 | |||||
| 243 | my $messaging_options = GetMessagingOptions(); | ||||
| 244 | OPTION: foreach my $option ( @$messaging_options ) { | ||||
| 245 | my $default_pref = GetMessagingPreferences( { categorycode => $params->{categorycode}, | ||||
| 246 | message_name => $option->{'message_name'} } ); | ||||
| 247 | # FIXME - except for setting the borrowernumber, it really ought to be possible | ||||
| 248 | # to have the output of GetMessagingPreferences be able to be the input | ||||
| 249 | # to SetMessagingPreference | ||||
| 250 | my @message_transport_types = keys %{ $default_pref->{transports} }; | ||||
| 251 | $default_pref->{message_attribute_id} = $option->{'message_attribute_id'}; | ||||
| 252 | $default_pref->{message_transport_types} = \@message_transport_types; | ||||
| 253 | $default_pref->{borrowernumber} = $params->{borrowernumber}; | ||||
| 254 | SetMessagingPreference( $default_pref ); | ||||
| 255 | } | ||||
| 256 | } | ||||
| 257 | |||||
| 258 | =head1 TABLES | ||||
| 259 | |||||
| 260 | =head2 message_queue | ||||
| 261 | |||||
| 262 | The actual messages which will be sent via a cron job running | ||||
| 263 | F<misc/cronjobs/process_message_queue.pl>. | ||||
| 264 | |||||
| 265 | =head2 message_attributes | ||||
| 266 | |||||
| 267 | What kinds of messages can be sent? | ||||
| 268 | |||||
| 269 | =head2 message_transport_types | ||||
| 270 | |||||
| 271 | What transports can messages be sent vith? (email, sms, etc.) | ||||
| 272 | |||||
| 273 | =head2 message_transports | ||||
| 274 | |||||
| 275 | How are message_attributes and message_transport_types correlated? | ||||
| 276 | |||||
| 277 | =head2 borrower_message_preferences | ||||
| 278 | |||||
| 279 | What messages do the borrowers want to receive? | ||||
| 280 | |||||
| 281 | =head2 borrower_message_transport_preferences | ||||
| 282 | |||||
| 283 | What transport should a message be sent with? | ||||
| 284 | |||||
| 285 | =head1 CONFIG | ||||
| 286 | |||||
| 287 | =head2 Adding a New Kind of Message to the System | ||||
| 288 | |||||
| 289 | =over 4 | ||||
| 290 | |||||
| 291 | =item 1. | ||||
| 292 | |||||
| 293 | Add a new template to the `letter` table. | ||||
| 294 | |||||
| 295 | =item 2. | ||||
| 296 | |||||
| 297 | Insert a row into the `message_attributes` table. | ||||
| 298 | |||||
| 299 | =item 3. | ||||
| 300 | |||||
| 301 | Insert rows into `message_transports` for each message_transport_type. | ||||
| 302 | |||||
| 303 | =back | ||||
| 304 | |||||
| 305 | =head1 SEE ALSO | ||||
| 306 | |||||
| 307 | L<C4::Letters> | ||||
| 308 | |||||
| 309 | =head1 AUTHOR | ||||
| 310 | |||||
| 311 | Koha Development Team <http://koha-community.org/> | ||||
| 312 | |||||
| 313 | Andrew Moore <andrew.moore@liblime.com> | ||||
| 314 | |||||
| 315 | =cut | ||||
| 316 | |||||
| 317 | 1 | 2µs | 1; |