Bug 17499: (QA follow-up) Fix Licence Statements
[koha.git] / Koha / Patron / Message / Preference.pm
1 package Koha::Patron::Message::Preference;
2
3 # Copyright Koha-Suomi Oy 2016
4 #
5 # This file is part of Koha.
6 #
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.
11 #
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.
16 #
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>.
19
20 use Modern::Perl;
21
22 use Koha::Database;
23 use Koha::Exceptions;
24 use Koha::Patron::Categories;
25 use Koha::Patron::Message::Attributes;
26 use Koha::Patron::Message::Preferences;
27 use Koha::Patron::Message::Transport::Preferences;
28 use Koha::Patron::Message::Transport::Types;
29 use Koha::Patron::Message::Transports;
30 use Koha::Patrons;
31
32 use base qw(Koha::Object);
33
34 =head1 NAME
35
36 Koha::Patron::Message::Preference - Koha Patron Message Preference object class
37
38 =head1 API
39
40 =head2 Class Methods
41
42 =cut
43
44 =head3 new
45
46 my $preference = Koha::Patron::Message::Preference->new({
47    borrowernumber => 123,
48    #categorycode => 'ABC',
49    message_attribute_id => 4,
50    message_transport_types => ['email', 'sms'], # see documentation below
51    wants_digest => 1,
52    days_in_advance => 7,
53 });
54
55 Takes either borrowernumber or categorycode, but not both.
56
57 days_in_advance may not be available. See message_attributes table for takes_days
58 configuration.
59
60 wants_digest may not be available. See message_transports table for is_digest
61 configuration.
62
63 You can instantiate a new object without custom validation errors, but when
64 storing, validation may throw exceptions. See C<validate()> for more
65 documentation.
66
67 C<message_transport_types> is a parameter that is not actually a column in this
68 Koha-object. Given this parameter, the message transport types will be added as
69 related transport types for this object. For get and set, you can access them via
70 subroutine C<message_transport_types()> in this class.
71
72 =cut
73
74 sub new {
75     my ($class, $params) = @_;
76
77     my $types = $params->{'message_transport_types'};
78     delete $params->{'message_transport_types'};
79
80     my $self = $class->SUPER::new($params);
81
82     $self->_set_message_transport_types($types);
83
84     return $self;
85 }
86
87 =head3 new_from_default
88
89 my $preference = Koha::Patron::Message::Preference->new_from_default({
90     borrowernumber => 123,
91     categorycode   => 'ABC',   # if not given, patron's categorycode will be used
92     message_attribute_id => 1,
93 });
94
95 NOTE: This subroutine initializes and STORES the object (in order to set
96 message transport types for the preference), so no need to call ->store when
97 preferences are initialized via this method.
98
99 Stores default messaging preference for C<categorycode> to patron for given
100 C<message_attribute_id>.
101
102 Throws Koha::Exceptions::MissingParameter if any of following is missing:
103 - borrowernumber
104 - message_attribute_id
105
106 Throws Koha::Exceptions::ObjectNotFound if default preferences are not found.
107
108 =cut
109
110 sub new_from_default {
111     my ($class, $params) = @_;
112
113     my @required = qw(borrowernumber message_attribute_id);
114     foreach my $p (@required) {
115         Koha::Exceptions::MissingParameter->throw(
116             error => "Missing required parameter '$p'.",
117         ) unless exists $params->{$p};
118     }
119     unless ($params->{'categorycode'}) {
120         my $patron = Koha::Patrons->find($params->{borrowernumber});
121         $params->{'categorycode'} = $patron->categorycode;
122     }
123
124     my $default = Koha::Patron::Message::Preferences->find({
125         categorycode => $params->{'categorycode'},
126         message_attribute_id => $params->{'message_attribute_id'},
127     });
128     Koha::Exceptions::ObjectNotFound->throw(
129         error => 'Default messaging preference for given categorycode and'
130         .' message_attribute_id cannot be found.',
131     ) unless $default;
132     $default = $default->unblessed;
133
134     # Add a new messaging preference for patron
135     my $self = $class->SUPER::new({
136         borrowernumber => $params->{'borrowernumber'},
137         message_attribute_id => $default->{'message_attribute_id'},
138         days_in_advance => $default->{'days_in_advance'},
139         wants_digest => $default->{'wants_digest'},
140     })->store;
141
142     # Set default messaging transport types
143     my $default_transport_types =
144     Koha::Patron::Message::Transport::Preferences->search({
145         borrower_message_preference_id =>
146                     $default->{'borrower_message_preference_id'}
147     });
148     while (my $transport = $default_transport_types->next) {
149         Koha::Patron::Message::Transport::Preference->new({
150             borrower_message_preference_id => $self->borrower_message_preference_id,
151             message_transport_type => $transport->message_transport_type,
152         })->store;
153     }
154
155     return $self;
156 }
157
158 =head3 message_name
159
160 $preference->message_name
161
162 Gets message_name for this messaging preference.
163
164 Setter not implemented.
165
166 =cut
167
168 sub message_name {
169     my ($self) = @_;
170
171     if ($self->{'_message_name'}) {
172         return $self->{'_message_name'};
173     }
174     $self->{'_message_name'} = Koha::Patron::Message::Attributes->find({
175         message_attribute_id => $self->message_attribute_id,
176     })->message_name;
177     return $self->{'_message_name'};
178 }
179
180 =head3 message_transport_types
181
182 $preference->message_transport_types
183 Returns a HASHREF of message transport types for this messaging preference, e.g.
184 if ($preference->message_transport_types->{'email'}) {
185     # email is one of the transport preferences
186 }
187
188 $preference->message_transport_types('email', 'sms');
189 Sets the given message transport types for this messaging preference
190
191 =cut
192
193 sub message_transport_types {
194     my $self = shift;
195
196     unless (@_) {
197         if ($self->{'_message_transport_types'}) {
198             return $self->{'_message_transport_types'};
199         }
200         map {
201             my $transport = Koha::Patron::Message::Transports->find({
202                 message_attribute_id => $self->message_attribute_id,
203                 message_transport_type => $_->message_transport_type,
204                 is_digest => $self->wants_digest
205             });
206             unless ($transport) {
207                 my $logger = Koha::Logger->get;
208                 $logger->warn(
209                     $self->message_name . ' has no transport with '.
210                     $_->message_transport_type . ' (digest: '.
211                     ($self->wants_digest ? 'yes':'no').').'
212                 );
213             }
214             $self->{'_message_transport_types'}->{$_->message_transport_type}
215                 = $transport ? $transport->letter_code : ' ';
216         }
217         Koha::Patron::Message::Transport::Preferences->search({
218             borrower_message_preference_id => $self->borrower_message_preference_id,
219         })->as_list;
220         return $self->{'_message_transport_types'} || {};
221     }
222     else {
223         $self->_set_message_transport_types(@_);
224         return $self;
225     }
226 }
227
228 =head3 set
229
230 $preference->set({
231     message_transport_types => ['sms', 'phone'],
232     wants_digest => 0,
233 })->store;
234
235 Sets preference object values and additionally message_transport_types if given.
236
237 =cut
238
239 sub set {
240     my ($self, $params) = @_;
241
242     my $mtt = $params->{'message_transport_types'};
243     delete $params->{'message_transport_types'};
244
245     $self->SUPER::set($params) if $params;
246     if ($mtt) {
247         $self->message_transport_types($mtt);
248     }
249
250     return $self;
251 }
252
253 =head3 store
254
255 Makes a validation before actual Koha::Object->store so that proper exceptions
256 can be thrown. See C<validate()> for documentation about exceptions.
257
258 =cut
259
260 sub store {
261     my $self = shift;
262
263     $self->validate->SUPER::store(@_);
264
265     # store message transport types
266     if (exists $self->{'_message_transport_types'}) {
267         Koha::Patron::Message::Transport::Preferences->search({
268             borrower_message_preference_id =>
269                 $self->borrower_message_preference_id,
270         })->delete;
271         foreach my $type (keys %{$self->{'_message_transport_types'}}) {
272             Koha::Patron::Message::Transport::Preference->new({
273                 borrower_message_preference_id =>
274                     $self->borrower_message_preference_id,
275                 message_transport_type => $type,
276             })->store;
277         }
278     }
279
280     return $self;
281 }
282
283 =head3 validate
284
285 Makes a basic validation for object.
286
287 Throws following exceptions regarding parameters.
288 - Koha::Exceptions::MissingParameter
289 - Koha::Exceptions::TooManyParameters
290 - Koha::Exceptions::BadParameter
291
292 See $_->parameter to identify the parameter causing the exception.
293
294 Throws Koha::Exceptions::DuplicateObject if this preference already exists.
295
296 Returns Koha::Patron::Message::Preference object.
297
298 =cut
299
300 sub validate {
301     my ($self) = @_;
302
303     if ($self->borrowernumber && $self->categorycode) {
304         Koha::Exceptions::TooManyParameters->throw(
305             error => 'Both borrowernumber and category given, only one accepted',
306         );
307     }
308     if (!$self->borrowernumber && !$self->categorycode) {
309         Koha::Exceptions::MissingParameter->throw(
310             error => 'borrowernumber or category required, none given',
311         );
312     }
313     if ($self->borrowernumber) {
314         Koha::Exceptions::BadParameter->throw(
315             error => 'Patron not found.',
316             parameter => 'borrowernumber',
317         ) unless Koha::Patrons->find($self->borrowernumber);
318     }
319     if ($self->categorycode) {
320         Koha::Exceptions::BadParameter->throw(
321             error => 'Category not found.',
322             parameter => 'categorycode',
323         ) unless Koha::Patron::Categories->find($self->categorycode);
324     }
325
326     if (!$self->in_storage) {
327         my $previous = Koha::Patron::Message::Preferences->search({
328             borrowernumber => $self->borrowernumber,
329             categorycode   => $self->categorycode,
330             message_attribute_id => $self->message_attribute_id,
331         });
332         if ($previous->count) {
333             Koha::Exceptions::DuplicateObject->throw(
334                 error => 'A preference for this borrower/category and'
335                 .' message_attribute_id already exists',
336             );
337         }
338     }
339
340     my $attr = Koha::Patron::Message::Attributes->find(
341         $self->message_attribute_id
342     );
343     unless ($attr) {
344         Koha::Exceptions::BadParameter->throw(
345             error => 'Message attribute with id '.$self->message_attribute_id
346             .' not found',
347             parameter => 'message_attribute_id'
348         );
349     }
350     if (defined $self->days_in_advance) {
351         if ($attr && $attr->takes_days == 0) {
352             Koha::Exceptions::BadParameter->throw(
353                 error => 'days_in_advance cannot be defined for '.
354                 $attr->message_name . '.',
355                 parameter => 'days_in_advance',
356             );
357         }
358         elsif ($self->days_in_advance < 0 || $self->days_in_advance > 30) {
359             Koha::Exceptions::BadParameter->throw(
360                 error => 'days_in_advance has to be a value between 0-30 for '.
361                 $attr->message_name . '.',
362                 parameter => 'days_in_advance',
363             );
364         }
365     }
366     if (defined $self->wants_digest) {
367         my $transports = Koha::Patron::Message::Transports->search({
368             message_attribute_id => $self->message_attribute_id,
369             is_digest            => $self->wants_digest ? 1 : 0,
370         });
371         Koha::Exceptions::BadParameter->throw(
372             error => (!$self->wants_digest ? 'Digest must be selected'
373                                            : 'Digest cannot be selected')
374             . ' for '.$attr->message_name.'.',
375             parameter => 'wants_digest',
376         ) if $transports->count == 0;
377     }
378
379     return $self;
380 }
381
382 sub _set_message_transport_types {
383     my $self = shift;
384
385     return unless $_[0];
386
387     $self->{'_message_transport_types'} = undef;
388     my $types = ref $_[0] eq "ARRAY" ? $_[0] : [@_];
389     return unless $types;
390     $self->_validate_message_transport_types({ message_transport_types => $types });
391     foreach my $type (@$types) {
392         unless (exists $self->{'_message_transport_types'}->{$type}) {
393             my $transport = Koha::Patron::Message::Transports->find({
394                 message_attribute_id => $self->message_attribute_id,
395                 message_transport_type => $type
396             });
397             unless ($transport) {
398                 Koha::Exceptions::BadParameter->throw(
399                     error => 'No transport configured for '.$self->message_name.
400                         " transport type $type.",
401                     parameter => 'message_transport_types'
402                 );
403             }
404             if (defined $self->borrowernumber) {
405                 my $patron = Koha::Patrons->find($self->borrowernumber);
406                 if ($type eq 'email') {
407                     if ( !$patron->email )
408                     {
409                         Koha::Exceptions::BadParameter->throw(
410                             error => 'Patron has not set email address, '.
411                                      'cannot use email as message transport',
412                             parameter => 'message_transport_types'
413                         );
414                     }
415                 }
416                 elsif ($type eq 'sms') {
417                     if ( !$patron->smsalertnumber ){
418                         Koha::Exceptions::BadParameter->throw(
419                             error => 'Patron has not set sms number, '.
420                                      'cannot set sms as message transport',
421                             parameter => 'message_transport_types'
422                         );
423                     }
424                 }
425             }
426             $self->{'_message_transport_types'}->{$type}
427                 = $transport->letter_code;
428         }
429     }
430     return $self;
431 }
432
433 sub _validate_message_transport_types {
434     my ($self, $params) = @_;
435
436     if (ref($params) eq 'HASH' && $params->{'message_transport_types'}) {
437         if (ref($params->{'message_transport_types'}) ne 'ARRAY') {
438             $params->{'message_transport_types'} = [$params->{'message_transport_types'}];
439         }
440         my $types = $params->{'message_transport_types'};
441
442         foreach my $type (@{$types}) {
443             unless (Koha::Patron::Message::Transport::Types->find({
444                 message_transport_type => $type
445             })) {
446                 Koha::Exceptions::BadParameter->throw(
447                     error => "Message transport type '$type' does not exist",
448                     parameter => 'message_transport_types',
449                 );
450             }
451         }
452         return $types;
453     }
454 }
455
456 =head3 type
457
458 =cut
459
460 sub _type {
461     return 'BorrowerMessagePreference';
462 }
463
464 =head1 AUTHOR
465
466 Lari Taskula <lari.taskula@hypernova.fi>
467
468 =cut
469
470 1;