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