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