Bug 11885: (follow-up) add a CSS class to set subfield code bold
[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 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 CGI;
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 C4::Dates qw/format_date format_date_in_iso/;
30
31 my $input = CGI->new;
32 my $dbh = C4::Context->dbh;
33
34 # my $flagsrequired;
35 # $flagsrequired->{circulation}=1;
36 my ($template, $loggedinuser, $cookie)
37     = get_template_and_user({template_name => "admin/smart-rules.tmpl",
38                             query => $input,
39                             type => "intranet",
40                             authnotrequired => 0,
41                             flagsrequired => {parameters => 'manage_circ_rules'},
42                             debug => 1,
43                             });
44
45 my $type=$input->param('type');
46 my $branch = $input->param('branch') || ( C4::Branch::onlymine() ? ( C4::Branch::mybranch() || '*' ) : '*' );
47 my $op = $input->param('op') || q{};
48
49 if ($op eq 'delete') {
50     my $itemtype     = $input->param('itemtype');
51     my $categorycode = $input->param('categorycode');
52     $debug and warn "deleting $1 $2 $branch";
53
54     my $sth_Idelete = $dbh->prepare("delete from issuingrules where branchcode=? and categorycode=? and itemtype=?");
55     $sth_Idelete->execute($branch, $categorycode, $itemtype);
56 }
57 elsif ($op eq 'delete-branch-cat') {
58     my $categorycode  = $input->param('categorycode');
59     if ($branch eq "*") {
60         if ($categorycode eq "*") {
61             my $sth_delete = $dbh->prepare("DELETE FROM default_circ_rules");
62             $sth_delete->execute();
63         } else {
64             my $sth_delete = $dbh->prepare("DELETE FROM default_borrower_circ_rules
65                                             WHERE categorycode = ?");
66             $sth_delete->execute($categorycode);
67         }
68     } elsif ($categorycode eq "*") {
69         my $sth_delete = $dbh->prepare("DELETE FROM default_branch_circ_rules
70                                         WHERE branchcode = ?");
71         $sth_delete->execute($branch);
72     } else {
73         my $sth_delete = $dbh->prepare("DELETE FROM branch_borrower_circ_rules
74                                         WHERE branchcode = ?
75                                         AND categorycode = ?");
76         $sth_delete->execute($branch, $categorycode);
77     }
78 }
79 elsif ($op eq 'delete-branch-item') {
80     my $itemtype  = $input->param('itemtype');
81     if ($branch eq "*") {
82         if ($itemtype eq "*") {
83             my $sth_delete = $dbh->prepare("DELETE FROM default_circ_rules");
84             $sth_delete->execute();
85         } else {
86             my $sth_delete = $dbh->prepare("DELETE FROM default_branch_item_rules
87                                             WHERE itemtype = ?");
88             $sth_delete->execute($itemtype);
89         }
90     } elsif ($itemtype eq "*") {
91         my $sth_delete = $dbh->prepare("DELETE FROM default_branch_circ_rules
92                                         WHERE branchcode = ?");
93         $sth_delete->execute($branch);
94     } else {
95         my $sth_delete = $dbh->prepare("DELETE FROM branch_item_rules
96                                         WHERE branchcode = ?
97                                         AND itemtype = ?");
98         $sth_delete->execute($branch, $itemtype);
99     }
100 }
101 # save the values entered
102 elsif ($op eq 'add') {
103     my $sth_search = $dbh->prepare('SELECT COUNT(*) AS total FROM issuingrules WHERE branchcode=? AND categorycode=? AND itemtype=?');
104     my $sth_insert = $dbh->prepare('INSERT INTO issuingrules (branchcode, categorycode, itemtype, maxissueqty, renewalsallowed, renewalperiod, norenewalbefore, reservesallowed, issuelength, lengthunit, hardduedate, hardduedatecompare, fine, finedays, firstremind, chargeperiod,rentaldiscount, overduefinescap) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)');
105     my $sth_update=$dbh->prepare("UPDATE issuingrules SET fine=?, finedays=?, firstremind=?, chargeperiod=?, maxissueqty=?, renewalsallowed=?, renewalperiod=?, norenewalbefore=?, reservesallowed=?, issuelength=?, lengthunit = ?, hardduedate=?, hardduedatecompare=?, rentaldiscount=?, overduefinescap=?  WHERE branchcode=? AND categorycode=? AND itemtype=?");
106     
107     my $br = $branch; # branch
108     my $bor  = $input->param('categorycode'); # borrower category
109     my $cat  = $input->param('itemtype');     # item type
110     my $fine = $input->param('fine');
111     my $finedays     = $input->param('finedays');
112     my $firstremind  = $input->param('firstremind');
113     my $chargeperiod = $input->param('chargeperiod');
114     my $maxissueqty  = $input->param('maxissueqty');
115     my $renewalsallowed  = $input->param('renewalsallowed');
116     my $renewalperiod    = $input->param('renewalperiod');
117     my $norenewalbefore  = $input->param('norenewalbefore');
118     $norenewalbefore = undef if $norenewalbefore eq '0' or $norenewalbefore =~ /^\s*$/;
119     my $reservesallowed  = $input->param('reservesallowed');
120     $maxissueqty =~ s/\s//g;
121     $maxissueqty = undef if $maxissueqty !~ /^\d+/;
122     my $issuelength  = $input->param('issuelength');
123     my $lengthunit  = $input->param('lengthunit');
124     my $hardduedate = $input->param('hardduedate');
125     $hardduedate = format_date_in_iso($hardduedate);
126     my $hardduedatecompare = $input->param('hardduedatecompare');
127     my $rentaldiscount = $input->param('rentaldiscount');
128     my $overduefinescap = $input->param('overduefinescap') || undef;
129     $debug and warn "Adding $br, $bor, $cat, $fine, $maxissueqty";
130
131     $sth_search->execute($br,$bor,$cat);
132     my $res = $sth_search->fetchrow_hashref();
133     if ($res->{total}) {
134         $sth_update->execute($fine, $finedays,$firstremind, $chargeperiod, $maxissueqty, $renewalsallowed, $renewalperiod, $norenewalbefore, $reservesallowed, $issuelength,$lengthunit, $hardduedate,$hardduedatecompare,$rentaldiscount,$overduefinescap, $br,$bor,$cat);
135     } else {
136         $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed, $renewalperiod, $norenewalbefore, $reservesallowed,$issuelength,$lengthunit,$hardduedate,$hardduedatecompare,$fine,$finedays,$firstremind,$chargeperiod,$rentaldiscount,$overduefinescap);
137     }
138
139 elsif ($op eq "set-branch-defaults") {
140     my $categorycode  = $input->param('categorycode');
141     my $maxissueqty   = $input->param('maxissueqty');
142     my $holdallowed   = $input->param('holdallowed');
143     my $returnbranch  = $input->param('returnbranch');
144     $maxissueqty =~ s/\s//g;
145     $maxissueqty = undef if $maxissueqty !~ /^\d+/;
146     $holdallowed =~ s/\s//g;
147     $holdallowed = undef if $holdallowed !~ /^\d+/;
148
149     if ($branch eq "*") {
150         my $sth_search = $dbh->prepare("SELECT count(*) AS total
151                                         FROM default_circ_rules");
152         my $sth_insert = $dbh->prepare("INSERT INTO default_circ_rules
153                                         (maxissueqty, holdallowed, returnbranch)
154                                         VALUES (?, ?, ?)");
155         my $sth_update = $dbh->prepare("UPDATE default_circ_rules
156                                         SET maxissueqty = ?, holdallowed = ?, returnbranch = ?");
157
158         $sth_search->execute();
159         my $res = $sth_search->fetchrow_hashref();
160         if ($res->{total}) {
161             $sth_update->execute($maxissueqty, $holdallowed, $returnbranch);
162         } else {
163             $sth_insert->execute($maxissueqty, $holdallowed, $returnbranch);
164         }
165     } else {
166         my $sth_search = $dbh->prepare("SELECT count(*) AS total
167                                         FROM default_branch_circ_rules
168                                         WHERE branchcode = ?");
169         my $sth_insert = $dbh->prepare("INSERT INTO default_branch_circ_rules
170                                         (branchcode, maxissueqty, holdallowed, returnbranch)
171                                         VALUES (?, ?, ?, ?)");
172         my $sth_update = $dbh->prepare("UPDATE default_branch_circ_rules
173                                         SET maxissueqty = ?, holdallowed = ?, returnbranch = ?
174                                         WHERE branchcode = ?");
175         $sth_search->execute($branch);
176         my $res = $sth_search->fetchrow_hashref();
177         if ($res->{total}) {
178             $sth_update->execute($maxissueqty, $holdallowed, $returnbranch, $branch);
179         } else {
180             $sth_insert->execute($branch, $maxissueqty, $holdallowed, $returnbranch);
181         }
182     }
183 }
184 elsif ($op eq "add-branch-cat") {
185     my $categorycode  = $input->param('categorycode');
186     my $maxissueqty   = $input->param('maxissueqty');
187     $maxissueqty =~ s/\s//g;
188     $maxissueqty = undef if $maxissueqty !~ /^\d+/;
189
190     if ($branch eq "*") {
191         if ($categorycode eq "*") {
192             my $sth_search = $dbh->prepare("SELECT count(*) AS total
193                                             FROM default_circ_rules");
194             my $sth_insert = $dbh->prepare("INSERT INTO default_circ_rules
195                                             (maxissueqty)
196                                             VALUES (?)");
197             my $sth_update = $dbh->prepare("UPDATE default_circ_rules
198                                             SET maxissueqty = ?");
199
200             $sth_search->execute();
201             my $res = $sth_search->fetchrow_hashref();
202             if ($res->{total}) {
203                 $sth_update->execute($maxissueqty);
204             } else {
205                 $sth_insert->execute($maxissueqty);
206             }
207         } else {
208             my $sth_search = $dbh->prepare("SELECT count(*) AS total
209                                             FROM default_borrower_circ_rules
210                                             WHERE categorycode = ?");
211             my $sth_insert = $dbh->prepare("INSERT INTO default_borrower_circ_rules
212                                             (categorycode, maxissueqty)
213                                             VALUES (?, ?)");
214             my $sth_update = $dbh->prepare("UPDATE default_borrower_circ_rules
215                                             SET maxissueqty = ?
216                                             WHERE categorycode = ?");
217             $sth_search->execute($branch);
218             my $res = $sth_search->fetchrow_hashref();
219             if ($res->{total}) {
220                 $sth_update->execute($maxissueqty, $categorycode);
221             } else {
222                 $sth_insert->execute($categorycode, $maxissueqty);
223             }
224         }
225     } elsif ($categorycode eq "*") {
226         my $sth_search = $dbh->prepare("SELECT count(*) AS total
227                                         FROM default_branch_circ_rules
228                                         WHERE branchcode = ?");
229         my $sth_insert = $dbh->prepare("INSERT INTO default_branch_circ_rules
230                                         (branchcode, maxissueqty)
231                                         VALUES (?, ?)");
232         my $sth_update = $dbh->prepare("UPDATE default_branch_circ_rules
233                                         SET maxissueqty = ?
234                                         WHERE branchcode = ?");
235         $sth_search->execute($branch);
236         my $res = $sth_search->fetchrow_hashref();
237         if ($res->{total}) {
238             $sth_update->execute($maxissueqty, $branch);
239         } else {
240             $sth_insert->execute($branch, $maxissueqty);
241         }
242     } else {
243         my $sth_search = $dbh->prepare("SELECT count(*) AS total
244                                         FROM branch_borrower_circ_rules
245                                         WHERE branchcode = ?
246                                         AND   categorycode = ?");
247         my $sth_insert = $dbh->prepare("INSERT INTO branch_borrower_circ_rules
248                                         (branchcode, categorycode, maxissueqty)
249                                         VALUES (?, ?, ?)");
250         my $sth_update = $dbh->prepare("UPDATE branch_borrower_circ_rules
251                                         SET maxissueqty = ?
252                                         WHERE branchcode = ?
253                                         AND categorycode = ?");
254
255         $sth_search->execute($branch, $categorycode);
256         my $res = $sth_search->fetchrow_hashref();
257         if ($res->{total}) {
258             $sth_update->execute($maxissueqty, $branch, $categorycode);
259         } else {
260             $sth_insert->execute($branch, $categorycode, $maxissueqty);
261         }
262     }
263 }
264 elsif ($op eq "add-branch-item") {
265     my $itemtype  = $input->param('itemtype');
266     my $holdallowed   = $input->param('holdallowed');
267     my $returnbranch  = $input->param('returnbranch');
268     $holdallowed =~ s/\s//g;
269     $holdallowed = undef if $holdallowed !~ /^\d+/;
270
271     if ($branch eq "*") {
272         if ($itemtype eq "*") {
273             my $sth_search = $dbh->prepare("SELECT count(*) AS total
274                                             FROM default_circ_rules");
275             my $sth_insert = $dbh->prepare("INSERT INTO default_circ_rules
276                                             (holdallowed, returnbranch)
277                                             VALUES (?, ?)");
278             my $sth_update = $dbh->prepare("UPDATE default_circ_rules
279                                             SET holdallowed = ?, returnbranch = ?");
280
281             $sth_search->execute();
282             my $res = $sth_search->fetchrow_hashref();
283             if ($res->{total}) {
284                 $sth_update->execute($holdallowed, $returnbranch);
285             } else {
286                 $sth_insert->execute($holdallowed, $returnbranch);
287             }
288         } else {
289             my $sth_search = $dbh->prepare("SELECT count(*) AS total
290                                             FROM default_branch_item_rules
291                                             WHERE itemtype = ?");
292             my $sth_insert = $dbh->prepare("INSERT INTO default_branch_item_rules
293                                             (itemtype, holdallowed, returnbranch)
294                                             VALUES (?, ?, ?)");
295             my $sth_update = $dbh->prepare("UPDATE default_branch_item_rules
296                                             SET holdallowed = ?, returnbranch = ?
297                                             WHERE itemtype = ?");
298             $sth_search->execute($itemtype);
299             my $res = $sth_search->fetchrow_hashref();
300             if ($res->{total}) {
301                 $sth_update->execute($holdallowed, $returnbranch, $itemtype);
302             } else {
303                 $sth_insert->execute($itemtype, $holdallowed, $returnbranch);
304             }
305         }
306     } elsif ($itemtype eq "*") {
307         my $sth_search = $dbh->prepare("SELECT count(*) AS total
308                                         FROM default_branch_circ_rules
309                                         WHERE branchcode = ?");
310         my $sth_insert = $dbh->prepare("INSERT INTO default_branch_circ_rules
311                                         (branchcode, holdallowed, returnbranch)
312                                         VALUES (?, ?, ?)");
313         my $sth_update = $dbh->prepare("UPDATE default_branch_circ_rules
314                                         SET holdallowed = ?, returnbranch = ?
315                                         WHERE branchcode = ?");
316         $sth_search->execute($branch);
317         my $res = $sth_search->fetchrow_hashref();
318         if ($res->{total}) {
319             $sth_update->execute($holdallowed, $returnbranch, $branch);
320         } else {
321             $sth_insert->execute($branch, $holdallowed, $returnbranch);
322         }
323     } else {
324         my $sth_search = $dbh->prepare("SELECT count(*) AS total
325                                         FROM branch_item_rules
326                                         WHERE branchcode = ?
327                                         AND   itemtype = ?");
328         my $sth_insert = $dbh->prepare("INSERT INTO branch_item_rules
329                                         (branchcode, itemtype, holdallowed, returnbranch)
330                                         VALUES (?, ?, ?, ?)");
331         my $sth_update = $dbh->prepare("UPDATE branch_item_rules
332                                         SET holdallowed = ?, returnbranch = ?
333                                         WHERE branchcode = ?
334                                         AND itemtype = ?");
335
336         $sth_search->execute($branch, $itemtype);
337         my $res = $sth_search->fetchrow_hashref();
338         if ($res->{total}) {
339             $sth_update->execute($holdallowed, $returnbranch, $branch, $itemtype);
340         } else {
341             $sth_insert->execute($branch, $itemtype, $holdallowed, $returnbranch);
342         }
343     }
344 }
345
346 my $branches = GetBranches();
347 my @branchloop;
348 for my $thisbranch (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %$branches) {
349     push @branchloop, {
350         value      => $thisbranch,
351         selected   => $thisbranch eq $branch,
352         branchname => $branches->{$thisbranch}->{'branchname'},
353     };
354 }
355
356 my $sth=$dbh->prepare("SELECT description,categorycode FROM categories ORDER BY description");
357 $sth->execute;
358 my @category_loop;
359 while (my $data=$sth->fetchrow_hashref){
360     push @category_loop,$data;
361 }
362
363 $sth->finish;
364 $sth=$dbh->prepare("SELECT description,itemtype FROM itemtypes ORDER BY description");
365 $sth->execute;
366 # $i=0;
367 my @row_loop;
368 my @itemtypes;
369 while (my $row=$sth->fetchrow_hashref){
370     push @itemtypes,$row;
371 }
372
373 my $sth2 = $dbh->prepare("
374     SELECT issuingrules.*, itemtypes.description AS humanitemtype, categories.description AS humancategorycode
375     FROM issuingrules
376     LEFT JOIN itemtypes
377         ON (itemtypes.itemtype = issuingrules.itemtype)
378     LEFT JOIN categories
379         ON (categories.categorycode = issuingrules.categorycode)
380     WHERE issuingrules.branchcode = ?
381 ");
382 $sth2->execute($branch);
383
384 while (my $row = $sth2->fetchrow_hashref) {
385     $row->{'current_branch'} ||= $row->{'branchcode'};
386     $row->{'humanitemtype'} ||= $row->{'itemtype'};
387     $row->{'default_humanitemtype'} = 1 if $row->{'humanitemtype'} eq '*';
388     $row->{'humancategorycode'} ||= $row->{'categorycode'};
389     $row->{'default_humancategorycode'} = 1 if $row->{'humancategorycode'} eq '*';
390     $row->{'fine'} = sprintf('%.2f', $row->{'fine'});
391     if ($row->{'hardduedate'} ne '0000-00-00') {
392        $row->{'hardduedate'} = format_date( $row->{'hardduedate'});
393        $row->{'hardduedatebefore'} = 1 if ($row->{'hardduedatecompare'} == -1);
394        $row->{'hardduedateexact'} = 1 if ($row->{'hardduedatecompare'} ==  0);
395        $row->{'hardduedateafter'} = 1 if ($row->{'hardduedatecompare'} ==  1);
396     } else {
397        $row->{'hardduedate'} = 0;
398     }
399     push @row_loop, $row;
400 }
401 $sth->finish;
402
403 my @sorted_row_loop = sort by_category_and_itemtype @row_loop;
404
405 my $sth_branch_cat;
406 if ($branch eq "*") {
407     $sth_branch_cat = $dbh->prepare("
408         SELECT default_borrower_circ_rules.*, categories.description AS humancategorycode
409         FROM default_borrower_circ_rules
410         JOIN categories USING (categorycode)
411         
412     ");
413     $sth_branch_cat->execute();
414 } else {
415     $sth_branch_cat = $dbh->prepare("
416         SELECT branch_borrower_circ_rules.*, categories.description AS humancategorycode
417         FROM branch_borrower_circ_rules
418         JOIN categories USING (categorycode)
419         WHERE branch_borrower_circ_rules.branchcode = ?
420     ");
421     $sth_branch_cat->execute($branch);
422 }
423
424 my @branch_cat_rules = ();
425 while (my $row = $sth_branch_cat->fetchrow_hashref) {
426     push @branch_cat_rules, $row;
427 }
428 my @sorted_branch_cat_rules = sort { $a->{'humancategorycode'} cmp $b->{'humancategorycode'} } @branch_cat_rules;
429
430 # note undef maxissueqty so that template can deal with them
431 foreach my $entry (@sorted_branch_cat_rules, @sorted_row_loop) {
432     $entry->{unlimited_maxissueqty} = 1 unless defined($entry->{maxissueqty});
433 }
434
435 @sorted_row_loop = sort by_category_and_itemtype @row_loop;
436
437 my $sth_branch_item;
438 if ($branch eq "*") {
439     $sth_branch_item = $dbh->prepare("
440         SELECT default_branch_item_rules.*, itemtypes.description AS humanitemtype
441         FROM default_branch_item_rules
442         JOIN itemtypes USING (itemtype)
443     ");
444     $sth_branch_item->execute();
445 } else {
446     $sth_branch_item = $dbh->prepare("
447         SELECT branch_item_rules.*, itemtypes.description AS humanitemtype
448         FROM branch_item_rules
449         JOIN itemtypes USING (itemtype)
450         WHERE branch_item_rules.branchcode = ?
451     ");
452     $sth_branch_item->execute($branch);
453 }
454
455 my @branch_item_rules = ();
456 while (my $row = $sth_branch_item->fetchrow_hashref) {
457     push @branch_item_rules, $row;
458 }
459 my @sorted_branch_item_rules = sort { $a->{'humanitemtype'} cmp $b->{'humanitemtype'} } @branch_item_rules;
460
461 # note undef holdallowed so that template can deal with them
462 foreach my $entry (@sorted_branch_item_rules) {
463     $entry->{holdallowed_any} = 1 if($entry->{holdallowed} == 2);
464     $entry->{holdallowed_same} = 1 if($entry->{holdallowed} == 1);
465 }
466
467 $template->param(show_branch_cat_rule_form => 1);
468 $template->param(branch_item_rule_loop => \@sorted_branch_item_rules);
469 $template->param(branch_cat_rule_loop => \@sorted_branch_cat_rules);
470
471 my $sth_defaults;
472 if ($branch eq "*") {
473     $sth_defaults = $dbh->prepare("
474         SELECT *
475         FROM default_circ_rules
476     ");
477     $sth_defaults->execute();
478 } else {
479     $sth_defaults = $dbh->prepare("
480         SELECT *
481         FROM default_branch_circ_rules
482         WHERE branchcode = ?
483     ");
484     $sth_defaults->execute($branch);
485 }
486
487 my $defaults = $sth_defaults->fetchrow_hashref;
488
489 if ($defaults) {
490     $template->param(default_holdallowed_none => 1) if($defaults->{holdallowed} == 0);
491     $template->param(default_holdallowed_same => 1) if($defaults->{holdallowed} == 1);
492     $template->param(default_holdallowed_any => 1) if($defaults->{holdallowed} == 2);
493     $template->param(default_maxissueqty => $defaults->{maxissueqty});
494     $template->param(default_returnbranch => $defaults->{returnbranch});
495 }
496
497 $template->param(default_rules => ($defaults ? 1 : 0));
498
499 $template->param(categoryloop => \@category_loop,
500                         itemtypeloop => \@itemtypes,
501                         rules => \@sorted_row_loop,
502                         branchloop => \@branchloop,
503                         humanbranch => ($branch ne '*' ? $branches->{$branch}->{branchname} : ''),
504                         current_branch => $branch,
505                         definedbranch => scalar(@sorted_row_loop)>0 
506                         );
507 output_html_with_http_headers $input, $cookie, $template->output;
508
509 exit 0;
510
511 # sort by patron category, then item type, putting
512 # default entries at the bottom
513 sub by_category_and_itemtype {
514     unless (by_category($a, $b)) {
515         return by_itemtype($a, $b);
516     }
517 }
518
519 sub by_category {
520     my ($a, $b) = @_;
521     if ($a->{'default_humancategorycode'}) {
522         return ($b->{'default_humancategorycode'} ? 0 : 1);
523     } elsif ($b->{'default_humancategorycode'}) {
524         return -1;
525     } else {
526         return $a->{'humancategorycode'} cmp $b->{'humancategorycode'};
527     }
528 }
529
530 sub by_itemtype {
531     my ($a, $b) = @_;
532     if ($a->{'default_humanitemtype'}) {
533         return ($b->{'default_humanitemtype'} ? 0 : 1);
534     } elsif ($b->{'default_humanitemtype'}) {
535         return -1;
536     } else {
537         return $a->{'humanitemtype'} cmp $b->{'humanitemtype'};
538     }
539 }