1 package Koha::Patron::MessagePreference;
3 # Copyright Koha-Suomi Oy 2016
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
24 use Koha::Exceptions::Patron::MessagePreference;
25 use Koha::Exceptions::Patron::MessagePreference::Transport;
26 use Koha::Exceptions::Patron::Category;
27 use Koha::Patron::Categories;
28 use Koha::Patron::MessagePreference::Attributes;
29 use Koha::Patron::MessagePreferences;
30 use Koha::Patron::MessagePreference::Transport::Preferences;
31 use Koha::Patron::MessagePreference::Transport::Types;
32 use Koha::Patron::MessagePreference::Transports;
35 use base qw(Koha::Object);
39 Koha::Patron::MessagePreference - Koha Patron Message Preference object class
49 my $preference = Koha::Patron::MessagePreference->new({
50 borrowernumber => 123,
51 #categorycode => 'ABC',
52 message_attribute_id => 4,
53 message_transport_types => ['email', 'sms'], # see documentation below
58 Takes either borrowernumber or categorycode, but not both.
60 days_in_advance may not be available. See message_attributes table for takes_days
63 wants_digest may not be available. See message_transports table for is_digest
66 You can instantiate a new object without custom validation errors, but when
67 storing, validation may throw exceptions. See C<validate()> for more
70 C<message_transport_types> is a parameter that is not actually a column in this
71 Koha-object. Given this parameter, the message transport types will be added as
72 related transport types for this object. For get and set, you can access them via
73 subroutine C<message_transport_types()> in this class.
78 my ($class, $params) = @_;
80 my $types = $params->{'message_transport_types'};
81 delete $params->{'message_transport_types'};
83 my $self = $class->SUPER::new($params);
85 $self->_set_message_transport_types($types);
90 =head3 new_from_default
92 my $preference = Koha::Patron::MessagePreference->new_from_default({
93 borrowernumber => 123,
94 categorycode => 'ABC', # if not given, patron's categorycode will be used
95 message_attribute_id => 1,
98 NOTE: This subroutine initializes and STORES the object (in order to set
99 message transport types for the preference), so no need to call ->store when
100 preferences are initialized via this method.
102 Stores default messaging preference for C<categorycode> to patron for given
103 C<message_attribute_id>.
105 Throws Koha::Exceptions::MissingParameter if any of following is missing:
107 - message_attribute_id
109 Throws Koha::Exceptions::ObjectNotFound if default preferences are not found.
113 sub new_from_default {
114 my ($class, $params) = @_;
116 my @required = qw(borrowernumber message_attribute_id);
117 foreach my $p (@required) {
118 Koha::Exceptions::MissingParameter->throw(
119 error => "Missing required parameter '$p'.",
120 ) unless exists $params->{$p};
122 unless ($params->{'categorycode'}) {
123 my $patron = Koha::Patrons->find($params->{borrowernumber});
124 $params->{'categorycode'} = $patron->categorycode;
127 my $default = Koha::Patron::MessagePreferences->find({
128 categorycode => $params->{'categorycode'},
129 message_attribute_id => $params->{'message_attribute_id'},
131 Koha::Exceptions::ObjectNotFound->throw(
132 error => 'Default messaging preference for given categorycode and'
133 .' message_attribute_id cannot be found.',
135 $default = $default->unblessed;
137 # Add a new messaging preference for patron
138 my $self = $class->SUPER::new({
139 borrowernumber => $params->{'borrowernumber'},
140 message_attribute_id => $default->{'message_attribute_id'},
141 days_in_advance => $default->{'days_in_advance'},
142 wants_digest => $default->{'wants_digest'},
145 # Set default messaging transport types
146 my $default_transport_types =
147 Koha::Patron::MessagePreference::Transport::Preferences->search({
148 borrower_message_preference_id =>
149 $default->{'borrower_message_preference_id'}
151 while (my $transport = $default_transport_types->next) {
152 Koha::Patron::MessagePreference::Transport::Preference->new({
153 borrower_message_preference_id => $self->borrower_message_preference_id,
154 message_transport_type => $transport->message_transport_type,
163 $preference->message_name
165 Gets message_name for this messaging preference.
167 Setter not implemented.
174 if ($self->{'_message_name'}) {
175 return $self->{'_message_name'};
177 $self->{'_message_name'} = Koha::Patron::MessagePreference::Attributes->find({
178 message_attribute_id => $self->message_attribute_id,
180 return $self->{'_message_name'};
183 =head3 message_transport_types
185 $preference->message_transport_types
186 Returns a HASHREF of message transport types for this messaging preference, e.g.
187 if ($preference->message_transport_types->{'email'}) {
188 # email is one of the transport preferences
191 $preference->message_transport_types('email', 'sms');
192 Sets the given message transport types for this messaging preference
196 sub message_transport_types {
200 if ($self->{'_message_transport_types'}) {
201 return $self->{'_message_transport_types'};
204 my $transport = Koha::Patron::MessagePreference::Transports->find({
205 message_attribute_id => $self->message_attribute_id,
206 message_transport_type => $_->message_transport_type,
207 is_digest => $self->wants_digest
209 unless ($transport) {
210 my $logger = Koha::Logger->get;
212 $self->message_name . ' has no transport with '.
213 $_->message_transport_type . ' (digest: '.
214 ($self->wants_digest ? 'yes':'no').').'
217 $self->{'_message_transport_types'}->{$_->message_transport_type}
218 = $transport ? $transport->letter_code : ' ';
220 Koha::Patron::MessagePreference::Transport::Preferences->search({
221 borrower_message_preference_id => $self->borrower_message_preference_id,
223 return $self->{'_message_transport_types'} || {};
226 $self->_set_message_transport_types(@_);
231 =head3 mtt_deliverable
233 $preference->mtt_deliverable('sms'[, $borrowernumer]);
235 Returns true if given message transport type can be used to deliver message to
238 By default, uses the borrowernumber bound to C<$preference>, but this may be
239 overridden by providing optional C<$borrowernumber> parameter.
243 sub mtt_deliverable {
244 my ( $self, $mtt, $borrowernumber ) = @_;
246 $borrowernumber //= $self->borrowernumber;
248 return 0 unless ($borrowernumber);
250 my $patron = Koha::Patrons->find($self->borrowernumber);
252 return (( $mtt eq 'email' and $patron->notice_email_address ) # No email address
253 or ( $mtt eq 'sms' and $patron->smsalertnumber ) # No SMS number
254 or ( $mtt eq 'itiva' and C4::Context->preference('TalkingTechItivaPhoneNotification') ) # Notice is handled by TalkingTech_itiva_outbound.pl
255 or ( $mtt eq 'phone' and $patron->phone )) # No phone number to call
262 message_transport_types => ['sms', 'phone'],
266 Sets preference object values and additionally message_transport_types if given.
271 my ($self, $params) = @_;
273 my $mtt = $params->{'message_transport_types'};
274 delete $params->{'message_transport_types'};
276 $self->SUPER::set($params) if $params;
278 $self->message_transport_types($mtt);
286 Makes a validation before actual Koha::Object->store so that proper exceptions
287 can be thrown. See C<validate()> for documentation about exceptions.
294 $self->validate->SUPER::store(@_);
296 # store message transport types
297 if (exists $self->{'_message_transport_types'}) {
298 Koha::Patron::MessagePreference::Transport::Preferences->search({
299 borrower_message_preference_id =>
300 $self->borrower_message_preference_id,
302 foreach my $type (keys %{$self->{'_message_transport_types'}}) {
303 Koha::Patron::MessagePreference::Transport::Preference->new({
304 borrower_message_preference_id =>
305 $self->borrower_message_preference_id,
306 message_transport_type => $type,
316 Makes a basic validation for object.
318 Returns Koha::Patron::MessagePreference object, or throws and exception.
325 if ($self->borrowernumber && $self->categorycode) {
326 Koha::Exceptions::TooManyParameters->throw(
327 error => 'Both borrowernumber and category given, only one accepted',
330 if (!$self->borrowernumber && !$self->categorycode) {
331 Koha::Exceptions::MissingParameter->throw(
332 error => 'borrowernumber or category required, none given',
335 if ($self->borrowernumber) {
336 Koha::Exceptions::Patron::NotFound->throw(
337 error => 'Patron not found.',
338 ) unless Koha::Patrons->find($self->borrowernumber);
340 if ($self->categorycode) {
341 Koha::Exceptions::Patron::Category::NotFound->throw(
342 error => 'Category not found.',
343 ) unless Koha::Patron::Categories->find($self->categorycode);
346 if (!$self->in_storage) {
347 my $previous = Koha::Patron::MessagePreferences->search({
348 borrowernumber => $self->borrowernumber,
349 categorycode => $self->categorycode,
350 message_attribute_id => $self->message_attribute_id,
352 if ($previous->count) {
353 Koha::Exceptions::DuplicateObject->throw(
354 error => 'A preference for this borrower/category and'
355 .' message_attribute_id already exists',
360 my $attr = Koha::Patron::MessagePreference::Attributes->find(
361 $self->message_attribute_id
364 Koha::Exceptions::Patron::MessagePreference::AttributeNotFound->throw(
365 error => 'Message attribute with id '.$self->message_attribute_id
367 message_attribute_id => $self->message_attribute_id,
370 if (defined $self->days_in_advance) {
371 if ($attr && $attr->takes_days == 0) {
372 Koha::Exceptions::Patron::MessagePreference::DaysInAdvanceNotAvailable->throw(
373 error => 'days_in_advance cannot be defined for '.
374 $attr->message_name . '.',
375 message_name => $attr->message_name,
378 elsif ($self->days_in_advance < 0 || $self->days_in_advance > 30) {
379 Koha::Exceptions::Patron::MessagePreference::DaysInAdvanceOutOfRange->throw(
380 error => 'days_in_advance has to be a value between 0-30 for '.
381 $attr->message_name . '.',
382 message_name => $attr->message_name,
388 if (defined $self->wants_digest) {
389 my $transports = Koha::Patron::MessagePreference::Transports->search({
390 message_attribute_id => $self->message_attribute_id,
391 is_digest => $self->wants_digest ? 1 : 0,
393 unless ($transports->count) {
394 if (!$self->wants_digest) {
395 Koha::Exceptions::Patron::MessagePreference::DigestRequired->throw(
396 error => 'Digest must be selected for '.$attr->message_name.'.',
397 message_name => $attr->message_name
400 Koha::Exceptions::Patron::MessagePreference::DigestNotAvailable->throw(
401 error => 'Digest cannot be selected for '.$attr->message_name.'.',
402 message_name => $attr->message_name
411 sub _set_message_transport_types {
416 $self->{'_message_transport_types'} = undef;
417 my $types = ref $_[0] eq "ARRAY" ? $_[0] : [@_];
418 return unless $types;
419 $self->_validate_message_transport_types({ message_transport_types => $types });
420 foreach my $type (@$types) {
421 unless (exists $self->{'_message_transport_types'}->{$type}) {
422 my $transport = Koha::Patron::MessagePreference::Transports->search({
423 message_attribute_id => $self->message_attribute_id,
424 message_transport_type => $type
426 unless ($transport) {
427 Koha::Exceptions::Patron::MessagePreference::NoTransportType->throw(
428 error => 'No transport configured for '.$self->message_name.
429 " transport type $type.",
430 message_name => $self->message_name,
431 transport_type => $type,
434 if (defined $self->borrowernumber) {
435 if ( ! $self->mtt_deliverable($type) ) {
436 Koha::Exceptions::Patron::MessagePreference::EmailAddressRequired->throw(
437 error => 'Patron has not set email address, '.
438 'cannot use email as message transport',
439 message_name => $self->message_name,
440 borrowernumber => $self->borrowernumber,
441 ) if $type eq 'email';
442 Koha::Exceptions::Patron::MessagePreference::TalkingTechItivaPhoneNotificationRequired->throw(
443 error => 'System preference TalkingTechItivaPhoneNotification disabled'.
444 'cannot use itiva as message transport',
445 message_name => $self->message_name,
446 borrowernumber => $self->borrowernumber,
447 ) if $type eq 'itiva';
448 Koha::Exceptions::Patron::MessagePreference::PhoneNumberRequired->throw(
449 error => 'Patron has not set phone number'.
450 'cannot use phone as message transport',
451 message_name => $self->message_name,
452 borrowernumber => $self->borrowernumber,
453 ) if $type eq 'phone';
454 Koha::Exceptions::Patron::MessagePreference::SMSNumberRequired->throw(
455 error => 'Patron has not set SMS number'.
456 'cannot use sms as message transport',
457 message_name => $self->message_name,
458 borrowernumber => $self->borrowernumber,
462 $self->{'_message_transport_types'}->{$type}
463 = $transport->letter_code;
469 sub _validate_message_transport_types {
470 my ($self, $params) = @_;
472 if (ref($params) eq 'HASH' && $params->{'message_transport_types'}) {
473 if (ref($params->{'message_transport_types'}) ne 'ARRAY') {
474 $params->{'message_transport_types'} = [$params->{'message_transport_types'}];
476 my $types = $params->{'message_transport_types'};
478 foreach my $type (@{$types}) {
479 unless (Koha::Patron::MessagePreference::Transport::Types->find({
480 message_transport_type => $type
482 Koha::Exceptions::Patron::MessagePreference::Transport::TypeNotFound->throw(
483 error => "Message transport type '$type' does not exist",
484 transport_type => $type,
497 return 'BorrowerMessagePreference';
502 Lari Taskula <lari.taskula@hypernova.fi>