Bug 15532: Add ability to allow only items whose home/holding branch matches the...
[koha.git] / admin / smart-rules.pl
1 #!/usr/bin/perl
2 # Copyright 2000-2002 Katipo Communications
3 # copyright 2010 BibLibre
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 CGI qw ( -utf8 );
23 use C4::Context;
24 use C4::Output;
25 use C4::Auth;
26 use C4::Koha;
27 use C4::Debug;
28 use C4::Branch; # GetBranches
29 use Koha::DateUtils;
30 use Koha::Database;
31 use Koha::IssuingRule;
32 use Koha::IssuingRules;
33 use Koha::Libraries;
34
35 my $input = CGI->new;
36 my $dbh = C4::Context->dbh;
37
38 # my $flagsrequired;
39 # $flagsrequired->{circulation}=1;
40 my ($template, $loggedinuser, $cookie)
41     = get_template_and_user({template_name => "admin/smart-rules.tt",
42                             query => $input,
43                             type => "intranet",
44                             authnotrequired => 0,
45                             flagsrequired => {parameters => 'manage_circ_rules'},
46                             debug => 1,
47                             });
48
49 my $type=$input->param('type');
50
51 my $branch = $input->param('branch');
52 unless ( $branch ) {
53     if ( C4::Context->preference('DefaultToLoggedInLibraryCircRules') ) {
54         $branch = Koha::Libraries->search->count() == 1 ? undef : C4::Branch::mybranch();
55     }
56     else {
57         $branch = C4::Branch::onlymine() ? ( C4::Branch::mybranch() || '*' ) : '*';
58     }
59 }
60 $branch = '*' if $branch eq 'NO_LIBRARY_SET';
61
62 my $op = $input->param('op') || q{};
63 my $language = C4::Languages::getlanguage();
64
65 if ($op eq 'delete') {
66     my $itemtype     = $input->param('itemtype');
67     my $categorycode = $input->param('categorycode');
68     $debug and warn "deleting $1 $2 $branch";
69
70     my $sth_Idelete = $dbh->prepare("delete from issuingrules where branchcode=? and categorycode=? and itemtype=?");
71     $sth_Idelete->execute($branch, $categorycode, $itemtype);
72 }
73 elsif ($op eq 'delete-branch-cat') {
74     my $categorycode  = $input->param('categorycode');
75     if ($branch eq "*") {
76         if ($categorycode eq "*") {
77             my $sth_delete = $dbh->prepare("DELETE FROM default_circ_rules");
78             $sth_delete->execute();
79         } else {
80             my $sth_delete = $dbh->prepare("DELETE FROM default_borrower_circ_rules
81                                             WHERE categorycode = ?");
82             $sth_delete->execute($categorycode);
83         }
84     } elsif ($categorycode eq "*") {
85         my $sth_delete = $dbh->prepare("DELETE FROM default_branch_circ_rules
86                                         WHERE branchcode = ?");
87         $sth_delete->execute($branch);
88     } else {
89         my $sth_delete = $dbh->prepare("DELETE FROM branch_borrower_circ_rules
90                                         WHERE branchcode = ?
91                                         AND categorycode = ?");
92         $sth_delete->execute($branch, $categorycode);
93     }
94 }
95 elsif ($op eq 'delete-branch-item') {
96     my $itemtype  = $input->param('itemtype');
97     if ($branch eq "*") {
98         if ($itemtype eq "*") {
99             my $sth_delete = $dbh->prepare("DELETE FROM default_circ_rules");
100             $sth_delete->execute();
101         } else {
102             my $sth_delete = $dbh->prepare("DELETE FROM default_branch_item_rules
103                                             WHERE itemtype = ?");
104             $sth_delete->execute($itemtype);
105         }
106     } elsif ($itemtype eq "*") {
107         my $sth_delete = $dbh->prepare("DELETE FROM default_branch_circ_rules
108                                         WHERE branchcode = ?");
109         $sth_delete->execute($branch);
110     } else {
111         my $sth_delete = $dbh->prepare("DELETE FROM branch_item_rules
112                                         WHERE branchcode = ?
113                                         AND itemtype = ?");
114         $sth_delete->execute($branch, $itemtype);
115     }
116 }
117 # save the values entered
118 elsif ($op eq 'add') {
119     my $br = $branch; # branch
120     my $bor  = $input->param('categorycode'); # borrower category
121     my $itemtype  = $input->param('itemtype');     # item type
122     my $fine = $input->param('fine');
123     my $finedays     = $input->param('finedays');
124     my $maxsuspensiondays = $input->param('maxsuspensiondays');
125     $maxsuspensiondays = undef if $maxsuspensiondays eq q||;
126     my $firstremind  = $input->param('firstremind');
127     my $chargeperiod = $input->param('chargeperiod');
128     my $chargeperiod_charge_at = $input->param('chargeperiod_charge_at');
129     my $maxissueqty  = $input->param('maxissueqty');
130     my $maxonsiteissueqty  = $input->param('maxonsiteissueqty');
131     my $renewalsallowed  = $input->param('renewalsallowed');
132     my $renewalperiod    = $input->param('renewalperiod');
133     my $norenewalbefore  = $input->param('norenewalbefore');
134     $norenewalbefore = undef if $norenewalbefore =~ /^\s*$/;
135     my $auto_renew = $input->param('auto_renew') eq 'yes' ? 1 : 0;
136     my $reservesallowed  = $input->param('reservesallowed');
137     my $onshelfholds     = $input->param('onshelfholds') || 0;
138     $maxissueqty =~ s/\s//g;
139     $maxissueqty = undef if $maxissueqty !~ /^\d+/;
140     $maxonsiteissueqty =~ s/\s//g;
141     $maxonsiteissueqty = undef if $maxonsiteissueqty !~ /^\d+/;
142     my $issuelength  = $input->param('issuelength');
143     $issuelength = $issuelength eq q{} ? undef : $issuelength;
144     my $lengthunit  = $input->param('lengthunit');
145     my $hardduedate = $input->param('hardduedate') || undef;
146     $hardduedate = eval { dt_from_string( $input->param('hardduedate') ) } if ( $hardduedate );
147     $hardduedate = output_pref( { dt => $hardduedate, dateonly => 1, dateformat => 'iso' } ) if ( $hardduedate );
148     my $hardduedatecompare = $input->param('hardduedatecompare');
149     my $rentaldiscount = $input->param('rentaldiscount');
150     my $opacitemholds = $input->param('opacitemholds') || 0;
151     my $overduefinescap = $input->param('overduefinescap') || undef;
152     my $cap_fine_to_replacement_price = $input->param('cap_fine_to_replacement_price') eq 'on';
153     $debug and warn "Adding $br, $bor, $itemtype, $fine, $maxissueqty, $maxonsiteissueqty, $cap_fine_to_replacement_price";
154
155     my $params = {
156         branchcode                    => $br,
157         categorycode                  => $bor,
158         itemtype                      => $itemtype,
159         fine                          => $fine,
160         finedays                      => $finedays,
161         maxsuspensiondays             => $maxsuspensiondays,
162         firstremind                   => $firstremind,
163         chargeperiod                  => $chargeperiod,
164         chargeperiod_charge_at        => $chargeperiod_charge_at,
165         maxissueqty                   => $maxissueqty,
166         maxonsiteissueqty             => $maxonsiteissueqty,
167         renewalsallowed               => $renewalsallowed,
168         renewalperiod                 => $renewalperiod,
169         norenewalbefore               => $norenewalbefore,
170         auto_renew                    => $auto_renew,
171         reservesallowed               => $reservesallowed,
172         issuelength                   => $issuelength,
173         lengthunit                    => $lengthunit,
174         hardduedate                   => $hardduedate,
175         hardduedatecompare            => $hardduedatecompare,
176         rentaldiscount                => $rentaldiscount,
177         onshelfholds                  => $onshelfholds,
178         opacitemholds                 => $opacitemholds,
179         overduefinescap               => $overduefinescap,
180         cap_fine_to_replacement_price => $cap_fine_to_replacement_price,
181     };
182
183     my $issuingrule = Koha::IssuingRules->find({categorycode => $bor, itemtype => $itemtype, branchcode => $br});
184     if ($issuingrule) {
185         $issuingrule->set($params)->store();
186     } else {
187         Koha::IssuingRule->new()->set($params)->store();
188     }
189
190 }
191 elsif ($op eq "set-branch-defaults") {
192     my $categorycode  = $input->param('categorycode');
193     my $maxissueqty   = $input->param('maxissueqty');
194     my $maxonsiteissueqty = $input->param('maxonsiteissueqty');
195     my $holdallowed   = $input->param('holdallowed');
196     my $hold_fulfillment_policy = $input->param('hold_fulfillment_policy');
197     my $returnbranch  = $input->param('returnbranch');
198     $maxissueqty =~ s/\s//g;
199     $maxissueqty = undef if $maxissueqty !~ /^\d+/;
200     $maxonsiteissueqty =~ s/\s//g;
201     $maxonsiteissueqty = undef if $maxonsiteissueqty !~ /^\d+/;
202     $holdallowed =~ s/\s//g;
203     $holdallowed = undef if $holdallowed !~ /^\d+/;
204
205     if ($branch eq "*") {
206         my $sth_search = $dbh->prepare("SELECT count(*) AS total
207                                         FROM default_circ_rules");
208         my $sth_insert = $dbh->prepare("INSERT INTO default_circ_rules
209                                         (maxissueqty, maxonsiteissueqty, holdallowed, hold_fulfillment_policy, returnbranch)
210                                         VALUES (?, ?, ?, ?, ?)");
211         my $sth_update = $dbh->prepare("UPDATE default_circ_rules
212                                         SET maxissueqty = ?, maxonsiteissueqty = ?, holdallowed = ?, hold_fulfillment_policy = ?, returnbranch = ?");
213
214         $sth_search->execute();
215         my $res = $sth_search->fetchrow_hashref();
216         if ($res->{total}) {
217             $sth_update->execute($maxissueqty, $maxonsiteissueqty, $holdallowed, $hold_fulfillment_policy, $returnbranch);
218         } else {
219             $sth_insert->execute($maxissueqty, $maxonsiteissueqty, $holdallowed, $hold_fulfillment_policy, $returnbranch);
220         }
221     } else {
222         my $sth_search = $dbh->prepare("SELECT count(*) AS total
223                                         FROM default_branch_circ_rules
224                                         WHERE branchcode = ?");
225         my $sth_insert = $dbh->prepare("INSERT INTO default_branch_circ_rules
226                                         (branchcode, maxissueqty, maxonsiteissueqty, holdallowed, hold_fulfillment_policy, returnbranch)
227                                         VALUES (?, ?, ?, ?, ?, ?)");
228         my $sth_update = $dbh->prepare("UPDATE default_branch_circ_rules
229                                         SET maxissueqty = ?, maxonsiteissueqty = ?, holdallowed = ?, hold_fulfillment_policy = ?, returnbranch = ?
230                                         WHERE branchcode = ?");
231         $sth_search->execute($branch);
232         my $res = $sth_search->fetchrow_hashref();
233         if ($res->{total}) {
234             $sth_update->execute($maxissueqty, $maxonsiteissueqty, $holdallowed, $hold_fulfillment_policy, $returnbranch, $branch);
235         } else {
236             $sth_insert->execute($branch, $maxissueqty, $maxonsiteissueqty, $holdallowed, $hold_fulfillment_policy, $returnbranch);
237         }
238     }
239 }
240 elsif ($op eq "add-branch-cat") {
241     my $categorycode  = $input->param('categorycode');
242     my $maxissueqty   = $input->param('maxissueqty');
243     my $maxonsiteissueqty = $input->param('maxonsiteissueqty');
244     $maxissueqty =~ s/\s//g;
245     $maxissueqty = undef if $maxissueqty !~ /^\d+/;
246     $maxonsiteissueqty =~ s/\s//g;
247     $maxonsiteissueqty = undef if $maxonsiteissueqty !~ /^\d+/;
248
249     if ($branch eq "*") {
250         if ($categorycode eq "*") {
251             my $sth_search = $dbh->prepare("SELECT count(*) AS total
252                                             FROM default_circ_rules");
253             my $sth_insert = $dbh->prepare(q|
254                 INSERT INTO default_circ_rules
255                     (maxissueqty, maxonsiteissueqty)
256                     VALUES (?, ?)
257             |);
258             my $sth_update = $dbh->prepare(q|
259                 UPDATE default_circ_rules
260                 SET maxissueqty = ?,
261                     maxonsiteissueqty = ?
262             |);
263
264             $sth_search->execute();
265             my $res = $sth_search->fetchrow_hashref();
266             if ($res->{total}) {
267                 $sth_update->execute($maxissueqty, $maxonsiteissueqty);
268             } else {
269                 $sth_insert->execute($maxissueqty, $maxonsiteissueqty);
270             }
271         } else {
272             my $sth_search = $dbh->prepare("SELECT count(*) AS total
273                                             FROM default_borrower_circ_rules
274                                             WHERE categorycode = ?");
275             my $sth_insert = $dbh->prepare(q|
276                 INSERT INTO default_borrower_circ_rules
277                     (categorycode, maxissueqty, maxonsiteissueqty)
278                     VALUES (?, ?, ?)
279             |);
280             my $sth_update = $dbh->prepare(q|
281                 UPDATE default_borrower_circ_rules
282                 SET maxissueqty = ?,
283                     maxonsiteissueqty = ?
284                 WHERE categorycode = ?
285             |);
286             $sth_search->execute($branch);
287             my $res = $sth_search->fetchrow_hashref();
288             if ($res->{total}) {
289                 $sth_update->execute($maxissueqty, $maxonsiteissueqty, $categorycode);
290             } else {
291                 $sth_insert->execute($categorycode, $maxissueqty, $maxonsiteissueqty);
292             }
293         }
294     } elsif ($categorycode eq "*") {
295         my $sth_search = $dbh->prepare("SELECT count(*) AS total
296                                         FROM default_branch_circ_rules
297                                         WHERE branchcode = ?");
298         my $sth_insert = $dbh->prepare(q|
299             INSERT INTO default_branch_circ_rules
300             (branchcode, maxissueqty, maxonsiteissueqty)
301             VALUES (?, ?, ?)
302         |);
303         my $sth_update = $dbh->prepare(q|
304             UPDATE default_branch_circ_rules
305             SET maxissueqty = ?,
306                 maxonsiteissueqty = ?
307             WHERE branchcode = ?
308         |);
309         $sth_search->execute($branch);
310         my $res = $sth_search->fetchrow_hashref();
311         if ($res->{total}) {
312             $sth_update->execute($maxissueqty, $maxonsiteissueqty, $branch);
313         } else {
314             $sth_insert->execute($branch, $maxissueqty, $maxonsiteissueqty);
315         }
316     } else {
317         my $sth_search = $dbh->prepare("SELECT count(*) AS total
318                                         FROM branch_borrower_circ_rules
319                                         WHERE branchcode = ?
320                                         AND   categorycode = ?");
321         my $sth_insert = $dbh->prepare(q|
322             INSERT INTO branch_borrower_circ_rules
323             (branchcode, categorycode, maxissueqty, maxonsiteissueqty)
324             VALUES (?, ?, ?, ?)
325         |);
326         my $sth_update = $dbh->prepare(q|
327             UPDATE branch_borrower_circ_rules
328             SET maxissueqty = ?,
329                 maxonsiteissueqty = ?
330             WHERE branchcode = ?
331             AND categorycode = ?
332         |);
333
334         $sth_search->execute($branch, $categorycode);
335         my $res = $sth_search->fetchrow_hashref();
336         if ($res->{total}) {
337             $sth_update->execute($maxissueqty, $maxonsiteissueqty, $branch, $categorycode);
338         } else {
339             $sth_insert->execute($branch, $categorycode, $maxissueqty, $maxonsiteissueqty);
340         }
341     }
342 }
343 elsif ($op eq "add-branch-item") {
344     my $itemtype                = $input->param('itemtype');
345     my $holdallowed             = $input->param('holdallowed');
346     my $hold_fulfillment_policy = $input->param('hold_fulfillment_policy');
347     my $returnbranch            = $input->param('returnbranch');
348
349     $holdallowed =~ s/\s//g;
350     $holdallowed = undef if $holdallowed !~ /^\d+/;
351
352     if ($branch eq "*") {
353         if ($itemtype eq "*") {
354             my $sth_search = $dbh->prepare("SELECT count(*) AS total
355                                             FROM default_circ_rules");
356             my $sth_insert = $dbh->prepare("INSERT INTO default_circ_rules
357                                             (holdallowed, hold_fulfillment_policy, returnbranch)
358                                             VALUES (?, ?, ?)");
359             my $sth_update = $dbh->prepare("UPDATE default_circ_rules
360                                             SET holdallowed = ?, hold_fulfillment_policy = ?, returnbranch = ?");
361
362             $sth_search->execute();
363             my $res = $sth_search->fetchrow_hashref();
364             if ($res->{total}) {
365                 $sth_update->execute($holdallowed, $hold_fulfillment_policy, $returnbranch);
366             } else {
367                 $sth_insert->execute($holdallowed, $hold_fulfillment_policy, $returnbranch);
368             }
369         } else {
370             my $sth_search = $dbh->prepare("SELECT count(*) AS total
371                                             FROM default_branch_item_rules
372                                             WHERE itemtype = ?");
373             my $sth_insert = $dbh->prepare("INSERT INTO default_branch_item_rules
374                                             (itemtype, holdallowed, hold_fulfillment_policy, returnbranch)
375                                             VALUES (?, ?, ?, ?)");
376             my $sth_update = $dbh->prepare("UPDATE default_branch_item_rules
377                                             SET holdallowed = ?, hold_fulfillment_policy = ?, returnbranch = ?
378                                             WHERE itemtype = ?");
379             $sth_search->execute($itemtype);
380             my $res = $sth_search->fetchrow_hashref();
381             if ($res->{total}) {
382                 $sth_update->execute($holdallowed, $hold_fulfillment_policy, $returnbranch, $itemtype);
383             } else {
384                 $sth_insert->execute($itemtype, $holdallowed, $hold_fulfillment_policy, $returnbranch);
385             }
386         }
387     } elsif ($itemtype eq "*") {
388         my $sth_search = $dbh->prepare("SELECT count(*) AS total
389                                         FROM default_branch_circ_rules
390                                         WHERE branchcode = ?");
391         my $sth_insert = $dbh->prepare("INSERT INTO default_branch_circ_rules
392                                         (branchcode, holdallowed, hold_fulfillment_policy, returnbranch)
393                                         VALUES (?, ?, ?, ?)");
394         my $sth_update = $dbh->prepare("UPDATE default_branch_circ_rules
395                                         SET holdallowed = ?, hold_fulfillment_policy = ?, returnbranch = ?
396                                         WHERE branchcode = ?");
397         $sth_search->execute($branch);
398         my $res = $sth_search->fetchrow_hashref();
399         if ($res->{total}) {
400             $sth_update->execute($holdallowed, $hold_fulfillment_policy, $returnbranch, $branch);
401         } else {
402             $sth_insert->execute($branch, $holdallowed, $hold_fulfillment_policy, $returnbranch);
403         }
404     } else {
405         my $sth_search = $dbh->prepare("SELECT count(*) AS total
406                                         FROM branch_item_rules
407                                         WHERE branchcode = ?
408                                         AND   itemtype = ?");
409         my $sth_insert = $dbh->prepare("INSERT INTO branch_item_rules
410                                         (branchcode, itemtype, holdallowed, hold_fulfillment_policy, returnbranch)
411                                         VALUES (?, ?, ?, ?, ?)");
412         my $sth_update = $dbh->prepare("UPDATE branch_item_rules
413                                         SET holdallowed = ?, hold_fulfillment_policy = ?, returnbranch = ?
414                                         WHERE branchcode = ?
415                                         AND itemtype = ?");
416
417         $sth_search->execute($branch, $itemtype);
418         my $res = $sth_search->fetchrow_hashref();
419         if ($res->{total}) {
420             $sth_update->execute($holdallowed, $hold_fulfillment_policy, $returnbranch, $branch, $itemtype);
421         } else {
422             $sth_insert->execute($branch, $itemtype, $holdallowed, $hold_fulfillment_policy, $returnbranch);
423         }
424     }
425 }
426
427 my $branches = GetBranches();
428 my @branchloop;
429 for my $thisbranch (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %$branches) {
430     push @branchloop, {
431         value      => $thisbranch,
432         selected   => $thisbranch eq $branch,
433         branchname => $branches->{$thisbranch}->{'branchname'},
434     };
435 }
436
437 my $sth=$dbh->prepare("SELECT description,categorycode FROM categories ORDER BY description");
438 $sth->execute;
439 my @category_loop;
440 while (my $data=$sth->fetchrow_hashref){
441     push @category_loop,$data;
442 }
443
444 $sth->finish;
445 my @row_loop;
446 my @itemtypes = @{ GetItemTypes( style => 'array' ) };
447 @itemtypes = sort { lc $a->{translated_description} cmp lc $b->{translated_description} } @itemtypes;
448
449 my $sth2 = $dbh->prepare("
450     SELECT  issuingrules.*,
451             itemtypes.description AS humanitemtype,
452             categories.description AS humancategorycode,
453             COALESCE( localization.translation, itemtypes.description ) AS translated_description
454     FROM issuingrules
455     LEFT JOIN itemtypes
456         ON (itemtypes.itemtype = issuingrules.itemtype)
457     LEFT JOIN categories
458         ON (categories.categorycode = issuingrules.categorycode)
459     LEFT JOIN localization ON issuingrules.itemtype = localization.code
460         AND localization.entity = 'itemtypes'
461         AND localization.lang = ?
462     WHERE issuingrules.branchcode = ?
463 ");
464 $sth2->execute($language, $branch);
465
466 while (my $row = $sth2->fetchrow_hashref) {
467     $row->{'current_branch'} ||= $row->{'branchcode'};
468     $row->{humanitemtype} ||= $row->{itemtype};
469     $row->{default_translated_description} = 1 if $row->{humanitemtype} eq '*';
470     $row->{'humancategorycode'} ||= $row->{'categorycode'};
471     $row->{'default_humancategorycode'} = 1 if $row->{'humancategorycode'} eq '*';
472     $row->{'fine'} = sprintf('%.2f', $row->{'fine'});
473     if ($row->{'hardduedate'} && $row->{'hardduedate'} ne '0000-00-00') {
474        my $harddue_dt = eval { dt_from_string( $row->{'hardduedate'} ) };
475        $row->{'hardduedate'} = eval { output_pref( { dt => $harddue_dt, dateonly => 1 } ) } if ( $harddue_dt );
476        $row->{'hardduedatebefore'} = 1 if ($row->{'hardduedatecompare'} == -1);
477        $row->{'hardduedateexact'} = 1 if ($row->{'hardduedatecompare'} ==  0);
478        $row->{'hardduedateafter'} = 1 if ($row->{'hardduedatecompare'} ==  1);
479     } else {
480        $row->{'hardduedate'} = 0;
481     }
482     push @row_loop, $row;
483 }
484 $sth->finish;
485
486 my @sorted_row_loop = sort by_category_and_itemtype @row_loop;
487
488 my $sth_branch_cat;
489 if ($branch eq "*") {
490     $sth_branch_cat = $dbh->prepare("
491         SELECT default_borrower_circ_rules.*, categories.description AS humancategorycode
492         FROM default_borrower_circ_rules
493         JOIN categories USING (categorycode)
494
495     ");
496     $sth_branch_cat->execute();
497 } else {
498     $sth_branch_cat = $dbh->prepare("
499         SELECT branch_borrower_circ_rules.*, categories.description AS humancategorycode
500         FROM branch_borrower_circ_rules
501         JOIN categories USING (categorycode)
502         WHERE branch_borrower_circ_rules.branchcode = ?
503     ");
504     $sth_branch_cat->execute($branch);
505 }
506
507 my @branch_cat_rules = ();
508 while (my $row = $sth_branch_cat->fetchrow_hashref) {
509     push @branch_cat_rules, $row;
510 }
511 my @sorted_branch_cat_rules = sort { $a->{'humancategorycode'} cmp $b->{'humancategorycode'} } @branch_cat_rules;
512
513 # note undef maxissueqty so that template can deal with them
514 foreach my $entry (@sorted_branch_cat_rules, @sorted_row_loop) {
515     $entry->{unlimited_maxissueqty} = 1 unless defined($entry->{maxissueqty});
516     $entry->{unlimited_maxonsiteissueqty} = 1 unless defined($entry->{maxonsiteissueqty});
517 }
518
519 @sorted_row_loop = sort by_category_and_itemtype @row_loop;
520
521 my $sth_branch_item;
522 if ($branch eq "*") {
523     $sth_branch_item = $dbh->prepare("
524         SELECT default_branch_item_rules.*,
525             COALESCE( localization.translation, itemtypes.description ) AS translated_description
526         FROM default_branch_item_rules
527         JOIN itemtypes USING (itemtype)
528         LEFT JOIN localization ON itemtypes.itemtype = localization.code
529             AND localization.entity = 'itemtypes'
530             AND localization.lang = ?
531     ");
532     $sth_branch_item->execute($language);
533 } else {
534     $sth_branch_item = $dbh->prepare("
535         SELECT branch_item_rules.*,
536             COALESCE( localization.translation, itemtypes.description ) AS translated_description
537         FROM branch_item_rules
538         JOIN itemtypes USING (itemtype)
539         LEFT JOIN localization ON itemtypes.itemtype = localization.code
540             AND localization.entity = 'itemtypes'
541             AND localization.lang = ?
542         WHERE branch_item_rules.branchcode = ?
543     ");
544     $sth_branch_item->execute($language, $branch);
545 }
546
547 my @branch_item_rules = ();
548 while (my $row = $sth_branch_item->fetchrow_hashref) {
549     push @branch_item_rules, $row;
550 }
551 my @sorted_branch_item_rules = sort { lc $a->{translated_description} cmp lc $b->{translated_description} } @branch_item_rules;
552
553 # note undef holdallowed so that template can deal with them
554 foreach my $entry (@sorted_branch_item_rules) {
555     $entry->{holdallowed_any}  = 1 if ( $entry->{holdallowed} == 2 );
556     $entry->{holdallowed_same} = 1 if ( $entry->{holdallowed} == 1 );
557 }
558
559 $template->param(show_branch_cat_rule_form => 1);
560 $template->param(branch_item_rule_loop => \@sorted_branch_item_rules);
561 $template->param(branch_cat_rule_loop => \@sorted_branch_cat_rules);
562
563 my $sth_defaults;
564 if ($branch eq "*") {
565     $sth_defaults = $dbh->prepare("
566         SELECT *
567         FROM default_circ_rules
568     ");
569     $sth_defaults->execute();
570 } else {
571     $sth_defaults = $dbh->prepare("
572         SELECT *
573         FROM default_branch_circ_rules
574         WHERE branchcode = ?
575     ");
576     $sth_defaults->execute($branch);
577 }
578
579 my $defaults = $sth_defaults->fetchrow_hashref;
580
581 if ($defaults) {
582     $template->param( default_holdallowed_none => 1 ) if ( $defaults->{holdallowed} == 0 );
583     $template->param( default_holdallowed_same => 1 ) if ( $defaults->{holdallowed} == 1 );
584     $template->param( default_holdallowed_any  => 1 ) if ( $defaults->{holdallowed} == 2 );
585     $template->param( default_hold_fulfillment_policy => $defaults->{hold_fulfillment_policy} );
586     $template->param( default_maxissueqty      => $defaults->{maxissueqty} );
587     $template->param( default_maxonsiteissueqty => $defaults->{maxonsiteissueqty} );
588     $template->param( default_returnbranch      => $defaults->{returnbranch} );
589 }
590
591 $template->param(default_rules => ($defaults ? 1 : 0));
592
593 $template->param(categoryloop => \@category_loop,
594                         itemtypeloop => \@itemtypes,
595                         rules => \@sorted_row_loop,
596                         branchloop => \@branchloop,
597                         humanbranch => ($branch ne '*' ? $branches->{$branch}->{branchname} : ''),
598                         current_branch => $branch,
599                         definedbranch => scalar(@sorted_row_loop)>0
600                         );
601 output_html_with_http_headers $input, $cookie, $template->output;
602
603 exit 0;
604
605 # sort by patron category, then item type, putting
606 # default entries at the bottom
607 sub by_category_and_itemtype {
608     unless (by_category($a, $b)) {
609         return by_itemtype($a, $b);
610     }
611 }
612
613 sub by_category {
614     my ($a, $b) = @_;
615     if ($a->{'default_humancategorycode'}) {
616         return ($b->{'default_humancategorycode'} ? 0 : 1);
617     } elsif ($b->{'default_humancategorycode'}) {
618         return -1;
619     } else {
620         return $a->{'humancategorycode'} cmp $b->{'humancategorycode'};
621     }
622 }
623
624 sub by_itemtype {
625     my ($a, $b) = @_;
626     if ($a->{default_translated_description}) {
627         return ($b->{'default_translated_description'} ? 0 : 1);
628     } elsif ($b->{'default_translated_description'}) {
629         return -1;
630     } else {
631         return lc $a->{'translated_description'} cmp lc $b->{'translated_description'};
632     }
633 }