Bug 108661: (follow-up) enshrine letting CardnumberLength specify just a maximum
[koha.git] / C4 / ItemCirculationAlertPreference.pm
1 package C4::ItemCirculationAlertPreference;
2
3 # Copyright Liblime 2009
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 use strict;
21 use warnings;
22 use C4::Context;
23 use C4::Category;
24 use C4::ItemType;
25 use Carp qw(carp croak);
26
27 our $AUTOLOAD;
28
29 # helper function for validating \%opts
30 our $valid = sub {
31     my $opts = shift;
32     for (qw(branchcode categorycode item_type notification)) {
33         exists($opts->{$_}) || croak("'$_' is a required parameter.");
34     }
35 };
36
37
38
39
40 =head1 NAME
41
42 C4::ItemCirculationAlertPreference - manage preferences for sending alerts
43
44 =head1 SYNOPSIS
45
46 Basics:
47
48     use C4::ItemCirculationAlertPreference;
49
50     # a short-cut to reduce typing the long package name over and over again
51     my $preferences = 'C4::ItemCirculationAlertPreference';
52
53 Creating a restriction on sending messages:
54
55     my $pref = $preferences->create({
56         branchcode   => 'CPL',
57         categorycode => 'YA',
58         item_type    => 'BK',
59         notification => 'CHECKOUT',
60     });
61
62 Removing a restriction on sending messages:
63
64     $preferences->delete({
65         branchcode   => 'CPL',
66         categorycode => 'YA',
67         item_type    => 'BK',
68         notification => 'CHECKOUT',
69     });
70
71 =head1 DESCRIPTION
72
73 This class is used to manage the preferences for when an alert may be sent.  By
74 default, item circulation alerts are enabled for every B<branch>, B<patron
75 category> and B<item type>.
76
77 However, if you would like to prevent item circulation alerts from being sent
78 for any combination of these 3 variables, a preference can be inserted into the
79 C<item_circulation_alert_preferences> table to make that a policy.
80
81 =head1 API
82
83 =head2 Class Methods
84
85 =cut
86
87 =head3 C4::ItemCirculationAlertPreference->new(\%opts)
88
89 This is a constructor for an in-memory C4::ItemCirculationAlertPreference
90 object.  The database is not affected by this method.
91
92 =cut
93
94 sub new {
95     my ($class, $opts) = @_;
96     bless $opts => $class;
97 }
98
99
100
101
102 =head3 C4::ItemCirculationAlertPreference->create(\%opts)
103
104 This will find or create an item circulation alert preference.  You must pass
105 it a B<branchcode>, B<categorycode>, B<item_type>, and B<notification>.  Valid
106 values for these attributes are as follows:
107
108 =over 4
109
110 =item branchcode
111
112 branches.branchcode
113
114 =item categorycode
115
116 category.categorycode
117
118 =item item_type
119
120 itemtypes.itemtype
121
122 =item notification
123
124 This can be "CHECKIN" or "CHECKOUT"
125
126 =back
127
128 =cut
129
130 sub create {
131     my ($class, $opts) = @_;
132     $valid->($opts);
133     my $dbh = C4::Context->dbh;
134     my $prefs = $dbh->selectall_arrayref(
135         "SELECT id, branchcode, categorycode, item_type
136         FROM  item_circulation_alert_preferences
137         WHERE branchcode   = ?
138         AND   categorycode = ?
139         AND   item_type    = ?
140         AND   notification = ?",
141         { Slice => {} },
142         $opts->{branchcode},
143         $opts->{categorycode},
144         $opts->{item_type},
145         $opts->{notification},
146     );
147     if (@$prefs) {
148         return $class->new($prefs->[0]);
149     } else {
150         my $success = $dbh->do(
151             "INSERT INTO item_circulation_alert_preferences
152             (branchcode, categorycode, item_type, notification) VALUES (?, ?, ?, ?)",
153             {},
154             $opts->{branchcode},
155             $opts->{categorycode},
156             $opts->{item_type},
157             $opts->{notification},
158         );
159         if ($success) {
160             my $self = {
161                 id           => $dbh->last_insert_id(undef, undef, undef, undef),
162                 branchcode   => $opts->{branchcode},
163                 categorycode => $opts->{categorycode},
164                 item_type    => $opts->{item_type},
165                 notification => $opts->{notification},
166             };
167             return $class->new($self);
168         } else {
169             carp $dbh->errstr;
170             return;
171         }
172     }
173 }
174
175
176
177
178 =head3 C4::ItemCirculationAlertPreference->delete(\%opts)
179
180 Delete an item circulation alert preference.  You can delete by either passing
181 in an B<id> or passing in a B<branchcode>, B<categorycode>, B<item_type>
182 triplet.
183
184 =cut
185
186 sub delete {
187     my ($class, $opts) = @_;
188     my $dbh = C4::Context->dbh;
189     if ($opts->{id}) {
190         $dbh->do(
191             "DELETE FROM item_circulation_alert_preferences WHERE id = ?",
192             {},
193             $opts->{id}
194         );
195     } else {
196         $valid->($opts);
197         my $sql =
198             "DELETE FROM item_circulation_alert_preferences
199             WHERE branchcode   = ?
200             AND   categorycode = ?
201             AND   item_type    = ?
202             AND   notification = ?";
203         $dbh->do(
204             $sql,
205             {},
206             $opts->{branchcode},
207             $opts->{categorycode},
208             $opts->{item_type},
209             $opts->{notification},
210         );
211     }
212 }
213
214
215
216
217 =head3 C4::ItemCirculationAlertPreference->is_enabled_for(\%opts)
218
219 Based on the existing preferences in the C<item_circulation_alert_preferences>
220 table, can an alert be sent for the given B<branchcode>, B<categorycode>, and
221 B<itemtype>?
222
223 B<Example>:
224
225     my $alert = 'C4::ItemCirculationAlertPreference';
226     my $conditions = {
227         branchcode   => 'CPL',
228         categorycode => 'IL',
229         item_type    => 'MU',
230     };
231
232     if ($alert->is_enabled_for($conditions)) {
233         # ...
234     }
235
236 =cut
237
238 sub is_disabled_for {
239     my ($class, $opts) = @_;
240     $valid->($opts);
241     my $dbh = C4::Context->dbh;
242
243     # Does a preference exist to block this alert?
244     my $query = qq{
245         SELECT id, branchcode, categorycode, item_type, notification
246           FROM item_circulation_alert_preferences
247          WHERE (branchcode   = ? OR branchcode   = '*')
248            AND (categorycode = ? OR categorycode = '*')
249            AND (item_type    = ? OR item_type    = '*')
250            AND (notification = ? OR notification = '*')
251     };
252
253     my $preferences = $dbh->selectall_arrayref(
254         $query,
255         { Slice => {} },
256         $opts->{branchcode},
257         $opts->{categorycode},
258         $opts->{item_type},
259         $opts->{notification},
260     );
261
262     # If any preferences showed up, we are NOT enabled.
263     return @$preferences;
264 }
265
266 sub is_enabled_for {
267     my ($class, $opts) = @_;
268     return not $class->is_disabled_for($opts);
269 }
270
271
272
273
274 =head3 C4::ItemCirculationAlertPreference->find({ branchcode => $bc, notification => $type })
275
276 This method returns all the item circulation alert preferences for a given
277 branch and notification.
278
279 B<Example>:
280
281     my @branch_prefs = C4::ItemCirculationAlertPreference->find({
282         branchcode   => 'CPL',
283         notification => 'CHECKIN',
284     });
285
286 =cut
287
288 sub find {
289     my ($class, $where) = @_;
290     my $dbh = C4::Context->dbh;
291     my $query = qq{
292         SELECT id, branchcode, categorycode, item_type, notification
293           FROM item_circulation_alert_preferences
294          WHERE branchcode = ? AND notification = ?
295          ORDER BY categorycode, item_type
296     };
297     return    map { $class->new($_) }    @{$dbh->selectall_arrayref(
298         $query,
299         { Slice => {} },
300         $where->{branchcode},
301         $where->{notification},
302     )};
303 }
304
305
306
307
308 =head3 C4::ItemCirculationAlertPreference->grid({ branchcode => $c, notification => $type })
309
310 Return a 2D arrayref for the grid view in F<admin/item_circulation_alert_preferences.pl>.
311 Each row represents a category (like 'Patron' or 'Young Adult') and
312 each column represents an itemtype (like 'Book' or 'Music').
313
314 Each cell contains...
315
316 B<Example>:
317
318     use Data::Dump 'pp';
319     my $grid = C4::ItemCirculationAlertPreference->grid({
320         branchcode   => 'CPL',
321         notification => 'CHECKOUT',
322     });
323     warn pp($grid);
324
325 See F<admin/item_circulation_alerts.pl> to see how this method is used.
326
327 =cut
328
329 sub grid {
330     my ($class, $where) = @_;
331     my @branch_prefs = $class->find($where);
332     my @default_prefs = $class->find({ branchcode => '*', notification => $where->{notification} });
333     my @cc = C4::Category->all;
334     my @it = C4::ItemType->all;
335     my $notification = $where->{notification};
336     my %disabled = map {
337         my $key = $_->categorycode . "-" . $_->item_type . "-" . $notification;
338         $key =~ s/\*/_/g;
339         ($key => 1);
340     } @branch_prefs;
341     my %default = map {
342         my $key = $_->categorycode . "-" . $_->item_type . "-" . $notification;
343         $key =~ s/\*/_/g;
344         ($key => 1);
345     } @default_prefs;
346     my @grid;
347     for my $c (@cc) {
348         my $row = { description => $c->description, items => [] };
349         push @grid, $row;
350         for my $i (@it) {
351             my $key = $c->categorycode . "-" . $i->itemtype . "-" . $notification;
352             $key =~ s/\*/_/g;
353             my @classes;
354             my $text = " ";
355             if ($disabled{$key}) {
356                 push @classes, 'disabled';
357                 $text = "Disabled for $where->{branchcode}";
358             }
359             if ($default{$key}) {
360                 push @classes, 'default';
361                 $text = "Disabled for all";
362             }
363             push @{$row->{items}}, {
364                 class => join(' ', @classes),
365                 id    => $key,
366                 text  => $text,
367             };
368         }
369     }
370     return \@grid;
371 }
372
373
374
375
376 =head2 Object Methods
377
378 These are read-only accessors for the various attributes of a preference.
379
380 =head3 $pref->id
381
382 =cut
383
384 =head3 $pref->branchcode
385
386 =cut
387
388 =head3 $pref->categorycode
389
390 =cut
391
392 =head3 $pref->item_type
393
394 =cut
395
396 =head3 $pref->notification
397
398 =cut
399
400 sub AUTOLOAD {
401     my $self = shift;
402     my $attr = $AUTOLOAD;
403     $attr =~ s/.*://;
404     if (exists $self->{$attr}) {
405         return $self->{$attr};
406     } else {
407         return;
408     }
409 }
410
411 sub DESTROY { }
412
413
414
415 =head1 SEE ALSO
416
417 L<C4::Circulation>, F<admin/item_circulation_alerts.pl>
418
419 =head1 AUTHOR
420
421 John Beppu <john.beppu@liblime.com>
422
423 =cut
424
425 1;