View | Details | Raw Unified | Return to bug 5872
Collapse All | Expand All

(-)a/.gitmodules (+3 lines)
Line 0 Link Here
1
[submodule "koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/jeditable"]
2
	path = koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/jeditable
3
	url = https://github.com/tuupola/jquery_jeditable.git
(-)a/C4/Circulation.pm (-566 / +328 lines)
Lines 28-40 use C4::Koha; Link Here
28
use C4::Biblio;
28
use C4::Biblio;
29
use C4::Items;
29
use C4::Items;
30
use C4::Members;
30
use C4::Members;
31
use C4::Dates;
31
use C4::IssuingRules;
32
use C4::Dates qw/format_date/;
32
use C4::Calendar;
33
use C4::Calendar;
33
use C4::Accounts;
34
use C4::Accounts;
35
use C4::Overdues ;
34
use C4::ItemCirculationAlertPreference;
36
use C4::ItemCirculationAlertPreference;
35
use C4::Dates qw(format_date);
37
use C4::Dates qw(format_date);
36
use C4::Message;
38
use C4::Message;
37
use C4::Debug;
39
use C4::Debug;
40
use YAML;
38
use Date::Calc qw(
41
use Date::Calc qw(
39
  Today
42
  Today
40
  Today_and_Now
43
  Today_and_Now
Lines 43-48 use Date::Calc qw( Link Here
43
  Date_to_Days
46
  Date_to_Days
44
  Day_of_Week
47
  Day_of_Week
45
  Add_Delta_Days	
48
  Add_Delta_Days	
49
  Delta_Days
50
  check_date
51
  Add_Delta_Days
46
);
52
);
47
use POSIX qw(strftime);
53
use POSIX qw(strftime);
48
use C4::Branch; # GetBranches
54
use C4::Branch; # GetBranches
Lines 74-82 BEGIN { Link Here
74
		&GetItemIssues
80
		&GetItemIssues
75
		&GetBorrowerIssues
81
		&GetBorrowerIssues
76
		&GetIssuingCharges
82
		&GetIssuingCharges
77
		&GetIssuingRule
78
        &GetBranchBorrowerCircRule
79
        &GetBranchItemRule
80
		&GetBiblioIssues
83
		&GetBiblioIssues
81
		&GetOpenIssue
84
		&GetOpenIssue
82
		&AnonymiseIssueHistory
85
		&AnonymiseIssueHistory
Lines 99-104 BEGIN { Link Here
99
                &CreateBranchTransferLimit
102
                &CreateBranchTransferLimit
100
                &DeleteBranchTransferLimits
103
                &DeleteBranchTransferLimits
101
	);
104
	);
105
	
102
}
106
}
103
107
104
=head1 NAME
108
=head1 NAME
Lines 347-462 sub TooMany { Link Here
347
	my $item		= shift;
351
	my $item		= shift;
348
    my $cat_borrower    = $borrower->{'categorycode'};
352
    my $cat_borrower    = $borrower->{'categorycode'};
349
    my $dbh             = C4::Context->dbh;
353
    my $dbh             = C4::Context->dbh;
350
	my $branch;
354
	my $exactbranch;
351
	# Get which branchcode we need
355
	# Get which branchcode we need
352
	$branch = _GetCircControlBranch($item,$borrower);
356
	$exactbranch = _GetCircControlBranch($item,$borrower);
353
	my $type = (C4::Context->preference('item-level_itypes')) 
357
	my $itype = (C4::Context->preference('item-level_itypes')) 
354
  			? $item->{'itype'}         # item-level
358
  			? $item->{'itype'}         # item-level
355
			: $item->{'itemtype'};     # biblio-level
359
			: $item->{'itemtype'};     # biblio-level
356
 
360
 
357
    # given branch, patron category, and item type, determine
361
    # given branch, patron category, and item type, determine
358
    # applicable issuing rule
362
    # applicable issuing rule
359
    my $issuing_rule = GetIssuingRule($cat_borrower, $type, $branch);
363
    my $branchfield = C4::Context->Preference('HomeOrHoldingBranch') || "homebranch";
360
364
    #By default, Patron is supposed not to be able to borrow
361
    # if a rule is found and has a loan limit set, count
365
    my $toomany = 1;
362
    # how many loans the patron already has that meet that
366
363
    # rule
367
    foreach my $branch ( $exactbranch, '*' ) {
364
    if (defined($issuing_rule) and defined($issuing_rule->{'maxissueqty'})) {
368
        foreach my $type ( $itype, '*' ) {
365
        my @bind_params;
369
            my $issuing_rule = GetIssuingRule( $cat_borrower, $type, $branch );
366
        my $count_query = "SELECT COUNT(*) FROM issues
370
367
                           JOIN items USING (itemnumber) ";
371
            # if a rule is found and has a loan limit set, count
368
372
            # how many loans the patron already has that meet that
369
        my $rule_itemtype = $issuing_rule->{itemtype};
373
            # rule
370
        if ($rule_itemtype eq "*") {
374
            if ( defined($issuing_rule) and defined( $issuing_rule->{'maxissueqty'} ) ) {
371
            # matching rule has the default item type, so count only
375
                my @bind_params;
372
            # those existing loans that don't fall under a more
376
                my $count_query = "SELECT COUNT(*) FROM issues
373
            # specific rule
377
                                   JOIN items USING (itemnumber) ";
374
            if (C4::Context->preference('item-level_itypes')) {
378
375
                $count_query .= " WHERE items.itype NOT IN (
379
                my $rule_itemtype = $issuing_rule->{itemtype};
376
                                    SELECT itemtype FROM issuingrules
380
                if ($rule_itemtype eq "*") {
377
                                    WHERE branchcode = ?
381
                    # matching rule has the default item type, so count all the items issued for that branch no
378
                                    AND   (categorycode = ? OR categorycode = ?)
382
                    # those existing loans that don't fall under a more
379
                                    AND   itemtype <> '*'
383
                    # specific rule Not QUITE
380
                                  ) ";
384
                    if (C4::Context->preference('item-level_itypes')) {
381
            } else { 
385
                        $count_query .= " WHERE items.itype NOT IN (
382
                $count_query .= " JOIN  biblioitems USING (biblionumber) 
386
                                                SELECT itemtype FROM issuingrules
383
                                  WHERE biblioitems.itemtype NOT IN (
387
                                                WHERE branchcode = ?
384
                                    SELECT itemtype FROM issuingrules
388
                                                AND   (categorycode = ? OR categorycode = ?)
385
                                    WHERE branchcode = ?
389
                                                AND   itemtype <> '*'
386
                                    AND   (categorycode = ? OR categorycode = ?)
390
                                           )";
387
                                    AND   itemtype <> '*'
391
                    } else {
388
                                  ) ";
392
                        $count_query .= " JOIN  biblioitems USING (biblionumber)
389
            }
393
                                            WHERE biblioitems.itemtype NOT IN (
390
            push @bind_params, $issuing_rule->{branchcode};
394
                                                SELECT itemtype FROM issuingrules
391
            push @bind_params, $issuing_rule->{categorycode};
395
                                                WHERE branchcode = ?
392
            push @bind_params, $cat_borrower;
396
                                                AND   (categorycode = ? OR categorycode = ?)
393
        } else {
397
                                                AND   itemtype <> '*'
394
            # rule has specific item type, so count loans of that
398
                                           )";
395
            # specific item type
399
                    }
396
            if (C4::Context->preference('item-level_itypes')) {
400
                    push @bind_params, $issuing_rule->{branchcode};
397
                $count_query .= " WHERE items.itype = ? ";
401
                    push @bind_params, $issuing_rule->{categorycode};
398
            } else { 
402
                    push @bind_params, $cat_borrower;
399
                $count_query .= " JOIN  biblioitems USING (biblionumber) 
403
                } else {
400
                                  WHERE biblioitems.itemtype= ? ";
404
                    # rule has specific item type, so count loans of that
401
            }
405
                    # specific item type
402
            push @bind_params, $type;
406
                    if (C4::Context->preference('item-level_itypes')) {
403
        }
407
                        $count_query .= " WHERE items.itype = ? ";
404
408
                    } else { 
405
        $count_query .= " AND borrowernumber = ? ";
409
                        $count_query .= " JOIN  biblioitems USING (biblionumber) 
406
        push @bind_params, $borrower->{'borrowernumber'};
410
                                      WHERE biblioitems.itemtype= ? ";
407
        my $rule_branch = $issuing_rule->{branchcode};
411
                    }
408
        if ($rule_branch ne "*") {
412
                    push @bind_params, $type;
409
            if (C4::Context->preference('CircControl') eq 'PickupLibrary') {
413
                }
410
                $count_query .= " AND issues.branchcode = ? ";
411
                push @bind_params, $branch;
412
            } elsif (C4::Context->preference('CircControl') eq 'PatronLibrary') {
413
                ; # if branch is the patron's home branch, then count all loans by patron
414
            } else {
415
                $count_query .= " AND items.homebranch = ? ";
416
                push @bind_params, $branch;
417
            }
418
        }
419
420
        my $count_sth = $dbh->prepare($count_query);
421
        $count_sth->execute(@bind_params);
422
        my ($current_loan_count) = $count_sth->fetchrow_array;
423
414
424
        my $max_loans_allowed = $issuing_rule->{'maxissueqty'};
415
                $count_query .= " AND borrowernumber = ? ";
425
        if ($current_loan_count >= $max_loans_allowed) {
416
                push @bind_params, $borrower->{'borrowernumber'};
426
            return ($current_loan_count, $max_loans_allowed);
417
                my $rule_branch = $issuing_rule->{branchcode};
427
        }
418
                if ( $rule_branch ne "*" ) {
428
    }
419
                    if ( C4::Context->preference('CircControl') eq 'PickupLibrary' ) {
420
                        $count_query .= " AND issues.branchcode = ? ";
421
                        push @bind_params, $branch;
422
                    } elsif ( C4::Context->preference('CircControl') eq 'PatronLibrary' ) {
423
                        ;    # if branch is the patron's home branch, then count all loans by patron
424
                    } else {
425
                        $count_query .= " AND items.$branchfield = ? ";
426
                        push @bind_params, $branch;
427
                    }
428
                }
429
429
430
    # Now count total loans against the limit for the branch
430
                my $count_sth = $dbh->prepare($count_query);
431
    my $branch_borrower_circ_rule = GetBranchBorrowerCircRule($branch, $cat_borrower);
431
                $count_sth->execute(@bind_params);
432
    if (defined($branch_borrower_circ_rule->{maxissueqty})) {
432
                my ($current_loan_count) = $count_sth->fetchrow_array;
433
        my @bind_params = ();
434
        my $branch_count_query = "SELECT COUNT(*) FROM issues 
435
                                  JOIN items USING (itemnumber)
436
                                  WHERE borrowernumber = ? ";
437
        push @bind_params, $borrower->{borrowernumber};
438
439
        if (C4::Context->preference('CircControl') eq 'PickupLibrary') {
440
            $branch_count_query .= " AND issues.branchcode = ? ";
441
            push @bind_params, $branch;
442
        } elsif (C4::Context->preference('CircControl') eq 'PatronLibrary') {
443
            ; # if branch is the patron's home branch, then count all loans by patron
444
        } else {
445
            $branch_count_query .= " AND items.homebranch = ? ";
446
            push @bind_params, $branch;
447
        }
448
        my $branch_count_sth = $dbh->prepare($branch_count_query);
449
        $branch_count_sth->execute(@bind_params);
450
        my ($current_loan_count) = $branch_count_sth->fetchrow_array;
451
433
452
        my $max_loans_allowed = $branch_borrower_circ_rule->{maxissueqty};
434
                my $max_loans_allowed = $issuing_rule->{'maxissueqty'};
453
        if ($current_loan_count >= $max_loans_allowed) {
435
                if ( $current_loan_count >= $max_loans_allowed ) {
454
            return ($current_loan_count, $max_loans_allowed);
436
                    return 1,$current_loan_count,$max_loans_allowed;
437
                }
438
                else {
439
                    $toomany=0;
440
                }
441
            }
455
        }
442
        }
456
    }
443
    }
457
444
    return $toomany;
458
    # OK, the patron can issue !!!
459
    return;
460
}
445
}
461
446
462
=head2 itemissues
447
=head2 itemissues
Lines 684-690 sub CanBookBeIssued { Link Here
684
669
685
        my $branch = _GetCircControlBranch($item,$borrower);
670
        my $branch = _GetCircControlBranch($item,$borrower);
686
        my $itype = ( C4::Context->preference('item-level_itypes') ) ? $item->{'itype'} : $biblioitem->{'itemtype'};
671
        my $itype = ( C4::Context->preference('item-level_itypes') ) ? $item->{'itype'} : $biblioitem->{'itemtype'};
687
        $duedate = CalcDateDue( C4::Dates->new( $issuedate, 'iso' ), $itype, $branch, $borrower );
672
        my $loanlength = GetLoanLength( $borrower->{'categorycode'}, $itype, $branch );
673
        unless ($loanlength or C4::Context->preference("AllowNotForLoanOverride")) {
674
             $issuingimpossible{LOAN_LENGTH_UNDEFINED} = "$borrower->{'categorycode'}, $itype, $branch";
675
        }
676
        $duedate = CalcDateDue( C4::Dates->new( $issuedate, 'iso' ), $itype, $branch, $borrower ) ;
688
677
689
        # Offline circ calls AddIssue directly, doesn't run through here
678
        # Offline circ calls AddIssue directly, doesn't run through here
690
        #  So issuingimpossible should be ok.
679
        #  So issuingimpossible should be ok.
Lines 712-726 sub CanBookBeIssued { Link Here
712
        $issuingimpossible{CARD_LOST} = 1;
701
        $issuingimpossible{CARD_LOST} = 1;
713
    }
702
    }
714
    if ( $borrower->{flags}->{'DBARRED'} ) {
703
    if ( $borrower->{flags}->{'DBARRED'} ) {
715
        $issuingimpossible{DEBARRED} = 1;
704
		if (my $dateenddebarred=$borrower->{flags}->{'DBARRED'}->{'dateend'}){
705
        	$issuingimpossible{DEBARRED} = format_date($dateenddebarred);
706
		}
707
		else {
708
        	$issuingimpossible{DEBARRED} = 1;
709
		}
716
    }
710
    }
717
    if ( $borrower->{'dateexpiry'} eq '0000-00-00') {
711
    if ( $borrower->{'dateexpiry'} eq '0000-00-00') {
718
        $issuingimpossible{EXPIRED} = 1;
712
        $issuingimpossible{EXPIRED} = 1;
719
    } else {
713
    } else {
720
        my @expirydate=  split /-/,$borrower->{'dateexpiry'};
714
        my @expirydate = split (/-/, $borrower->{'dateexpiry'});
721
        if($expirydate[0]==0 || $expirydate[1]==0|| $expirydate[2]==0 ||
715
        if (   $expirydate[0] == 0
722
            Date_to_Days(Today) > Date_to_Days( @expirydate )) {
716
            || $expirydate[1] == 0
723
            $issuingimpossible{EXPIRED} = 1;                                   
717
            || $expirydate[2] == 0
718
            || Date_to_Days(Today) > Date_to_Days(@expirydate) ) {
719
            $issuingimpossible{EXPIRED} = 1;
724
        }
720
        }
725
    }
721
    }
726
    #
722
    #
Lines 769-786 sub CanBookBeIssued { Link Here
769
#
765
#
770
    # JB34 CHECKS IF BORROWERS DONT HAVE ISSUE TOO MANY BOOKS
766
    # JB34 CHECKS IF BORROWERS DONT HAVE ISSUE TOO MANY BOOKS
771
    #
767
    #
772
	my ($current_loan_count, $max_loans_allowed) = TooMany( $borrower, $item->{biblionumber}, $item );
768
    my @toomany = TooMany( $borrower, $item->{biblionumber}, $item );
773
    # if TooMany max_loans_allowed returns 0 the user doesn't have permission to check out this book
769
774
    if ($max_loans_allowed eq 0) {
770
    if ( $toomany[0] == 1 && scalar(@toomany)<3) {
775
        $needsconfirmation{PATRON_CANT} = 1;
771
        $needsconfirmation{PATRON_CANT} = 1;
776
    } else {
772
    } elsif (scalar(@toomany)==3) {
777
        if($max_loans_allowed){
773
        $needsconfirmation{TOO_MANY} = "$toomany[1] / $toomany[2]";
778
            $needsconfirmation{TOO_MANY} = 1;
779
            $needsconfirmation{current_loan_count} = $current_loan_count;
780
            $needsconfirmation{max_loans_allowed} = $max_loans_allowed;
781
        }
782
    }
774
    }
783
775
776
784
    #
777
    #
785
    # ITEM CHECKING
778
    # ITEM CHECKING
786
    #
779
    #
Lines 817-824 sub CanBookBeIssued { Link Here
817
            }
810
            }
818
        }
811
        }
819
    }
812
    }
820
    if ( $item->{'wthdrawn'} && $item->{'wthdrawn'} == 1 )
813
    if ( $item->{'damaged'} && $item->{'damaged'} > 0 ){
821
    {
814
        $needsconfirmation{DAMAGED} = $item->{'damaged'};
815
        my $fw                      = GetFrameworkCode($item->{biblionumber});
816
        my $category                = GetAuthValCode('items.damaged',$fw);
817
        my $authorizedvalues        = GetAuthorisedValues($category, $item->{damaged});
818
        
819
        foreach my $authvalue (@$authorizedvalues){
820
            $needsconfirmation{DAMAGED} = $authvalue->{lib} if $authvalue->{'authorised_value'} eq $item->{'damaged'};
821
        }
822
        
823
    }
824
    if ( $item->{'wthdrawn'} && $item->{'wthdrawn'} == 1 ) {
822
        $issuingimpossible{WTHDRAWN} = 1;
825
        $issuingimpossible{WTHDRAWN} = 1;
823
    }
826
    }
824
    if (   $item->{'restricted'}
827
    if (   $item->{'restricted'}
Lines 826-840 sub CanBookBeIssued { Link Here
826
    {
829
    {
827
        $issuingimpossible{RESTRICTED} = 1;
830
        $issuingimpossible{RESTRICTED} = 1;
828
    }
831
    }
832
    my $userenv = C4::Context->userenv;
833
    my $branch=$userenv->{branch};
834
    my $hbr= $item->{ C4::Context->preference("HomeOrHoldingBranch") };
829
    if ( C4::Context->preference("IndependantBranches") ) {
835
    if ( C4::Context->preference("IndependantBranches") ) {
830
        my $userenv = C4::Context->userenv;
831
        if ( ($userenv) && ( $userenv->{flags} % 2 != 1 ) ) {
836
        if ( ($userenv) && ( $userenv->{flags} % 2 != 1 ) ) {
832
            $issuingimpossible{ITEMNOTSAMEBRANCH} = 1
837
            $issuingimpossible{ITEMNOTSAMEBRANCH} = 1
833
              if ( $item->{C4::Context->preference("HomeOrHoldingBranch")} ne $userenv->{branch} );
838
              if ( $hbr ne $branch );
834
            $needsconfirmation{BORRNOTSAMEBRANCH} = GetBranchName( $borrower->{'branchcode'} )
839
            $needsconfirmation{BORRNOTSAMEBRANCH} = GetBranchName( $borrower->{'branchcode'} )
835
              if ( $borrower->{'branchcode'} ne $userenv->{branch} );
840
              if ( $borrower->{'branchcode'} ne $userenv->{branch} );
836
        }
841
        }
837
    }
842
    }
843
    my $branchtransferfield=C4::Context->preference("BranchTransferLimitsType") eq "ccode" ? "ccode" : "itype";
844
    if  ( C4::Context->preference("UseBranchTransferLimits")
845
                and !IsBranchTransferAllowed( $branch, $hbr, $item->{ $branchtransferfield } ) ) {
846
        $needsconfirmation{BRANCH_TRANSFER_NOT_ALLOWED} = $hbr;
847
    }
848
838
849
839
    #
850
    #
840
    # CHECK IF BOOK ALREADY ISSUED TO THIS BORROWER
851
    # CHECK IF BOOK ALREADY ISSUED TO THIS BORROWER
Lines 875-904 sub CanBookBeIssued { Link Here
875
		my ( $resborrower ) = C4::Members::GetMemberDetails( $resbor, 0 );
886
		my ( $resborrower ) = C4::Members::GetMemberDetails( $resbor, 0 );
876
		my $branches  = GetBranches();
887
		my $branches  = GetBranches();
877
		my $branchname = $branches->{ $res->{'branchcode'} }->{'branchname'};
888
		my $branchname = $branches->{ $res->{'branchcode'} }->{'branchname'};
878
        if ( $resbor ne $borrower->{'borrowernumber'} && $restype eq "Waiting" )
889
        if( $resbor ne $borrower->{'borrowernumber'}){
879
        {
890
            if ( $restype eq "Waiting" ) {
880
            # The item is on reserve and waiting, but has been
891
                # The item is on reserve and waiting, but has been
881
            # reserved by some other patron.
892
                # reserved by some other patron.
882
            $needsconfirmation{RESERVE_WAITING} = 1;
893
                $needsconfirmation{RESERVE_WAITING} =
883
            $needsconfirmation{'resfirstname'} = $resborrower->{'firstname'};
894
    "$resborrower->{'firstname'} $resborrower->{'surname'} ($resborrower->{'cardnumber'}, $branchname)";
884
            $needsconfirmation{'ressurname'} = $resborrower->{'surname'};
895
            }
885
            $needsconfirmation{'rescardnumber'} = $resborrower->{'cardnumber'};
896
            elsif ( $restype eq "Reserved" ) {
886
            $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
897
                # The item is on reserve for someone else.
887
            $needsconfirmation{'resbranchname'} = $branchname;
898
                $needsconfirmation{RESERVED} =
888
            $needsconfirmation{'reswaitingdate'} = format_date($res->{'waitingdate'});
899
    "$res->{'reservedate'} : $resborrower->{'firstname'} $resborrower->{'surname'} ($resborrower->{'cardnumber'})";
889
        }
900
            }
890
        elsif ( $restype eq "Reserved" ) {
891
            # The item is on reserve for someone else.
892
            $needsconfirmation{RESERVED} = 1;
893
            $needsconfirmation{'resfirstname'} = $resborrower->{'firstname'};
894
            $needsconfirmation{'ressurname'} = $resborrower->{'surname'};
895
            $needsconfirmation{'rescardnumber'} = $resborrower->{'cardnumber'};
896
            $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'};
897
            $needsconfirmation{'resbranchname'} = $branchname;
898
            $needsconfirmation{'resreservedate'} = format_date($res->{'reservedate'});
899
        }
901
        }
900
    }
902
    }
901
	return ( \%issuingimpossible, \%needsconfirmation );
903
    return ( \%issuingimpossible, \%needsconfirmation );
902
}
904
}
903
905
904
=head2 AddIssue
906
=head2 AddIssue
Lines 979-985 sub AddIssue { Link Here
979
				# who wants to borrow it now. mark it returned before issuing to the new borrower
981
				# who wants to borrow it now. mark it returned before issuing to the new borrower
980
				AddReturn(
982
				AddReturn(
981
					$item->{'barcode'},
983
					$item->{'barcode'},
982
					C4::Context->userenv->{'branch'}
984
					C4::Context->userenv->{'branch'},
985
					undef,
986
					undef,
987
					1
983
				);
988
				);
984
			}
989
			}
985
990
Lines 1012-1018 sub AddIssue { Link Here
1012
					ModReserve(1,
1017
					ModReserve(1,
1013
						$res->{'biblionumber'},
1018
						$res->{'biblionumber'},
1014
						$res->{'borrowernumber'},
1019
						$res->{'borrowernumber'},
1015
						$res->{'branchcode'}
1020
						$res->{'branchcode'},
1021
						undef,
1022
						$res->{'reservenumber'}
1016
					);
1023
					);
1017
				}
1024
				}
1018
			}
1025
			}
Lines 1101-1110 sub AddIssue { Link Here
1101
                branch   => $branch,
1108
                branch   => $branch,
1102
            });
1109
            });
1103
        }
1110
        }
1111
1112
        logaction( "CIRCULATION", "ISSUE", $borrower->{'borrowernumber'}, $item->{'itemnumber'}  )
1113
          if C4::Context->preference("IssueLog");
1104
    }
1114
    }
1105
1115
1106
    logaction("CIRCULATION", "ISSUE", $borrower->{'borrowernumber'}, $biblio->{'biblionumber'})
1107
        if C4::Context->preference("IssueLog");
1108
  }
1116
  }
1109
  return ($datedue);	# not necessarily the same as when it came in!
1117
  return ($datedue);	# not necessarily the same as when it came in!
1110
}
1118
}
Lines 1119-1432 Get loan length for an itemtype, a borrower type and a branch Link Here
1119
1127
1120
sub GetLoanLength {
1128
sub GetLoanLength {
1121
    my ( $borrowertype, $itemtype, $branchcode ) = @_;
1129
    my ( $borrowertype, $itemtype, $branchcode ) = @_;
1122
    my $dbh = C4::Context->dbh;
1130
    my $loanlength=GetIssuingRule($borrowertype,$itemtype,$branchcode);
1123
    my $sth =
1131
    return $loanlength->{issuelength};
1124
      $dbh->prepare(
1125
"select issuelength from issuingrules where categorycode=? and itemtype=? and branchcode=? and issuelength is not null"
1126
      );
1127
# warn "in get loan lenght $borrowertype $itemtype $branchcode ";
1128
# try to find issuelength & return the 1st available.
1129
# check with borrowertype, itemtype and branchcode, then without one of those parameters
1130
    $sth->execute( $borrowertype, $itemtype, $branchcode );
1131
    my $loanlength = $sth->fetchrow_hashref;
1132
    return $loanlength->{issuelength}
1133
      if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1134
1135
    $sth->execute( $borrowertype, "*", $branchcode );
1136
    $loanlength = $sth->fetchrow_hashref;
1137
    return $loanlength->{issuelength}
1138
      if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1139
1140
    $sth->execute( "*", $itemtype, $branchcode );
1141
    $loanlength = $sth->fetchrow_hashref;
1142
    return $loanlength->{issuelength}
1143
      if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1144
1145
    $sth->execute( "*", "*", $branchcode );
1146
    $loanlength = $sth->fetchrow_hashref;
1147
    return $loanlength->{issuelength}
1148
      if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1149
1150
    $sth->execute( $borrowertype, $itemtype, "*" );
1151
    $loanlength = $sth->fetchrow_hashref;
1152
    return $loanlength->{issuelength}
1153
      if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1154
1155
    $sth->execute( $borrowertype, "*", "*" );
1156
    $loanlength = $sth->fetchrow_hashref;
1157
    return $loanlength->{issuelength}
1158
      if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1159
1160
    $sth->execute( "*", $itemtype, "*" );
1161
    $loanlength = $sth->fetchrow_hashref;
1162
    return $loanlength->{issuelength}
1163
      if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1164
1165
    $sth->execute( "*", "*", "*" );
1166
    $loanlength = $sth->fetchrow_hashref;
1167
    return $loanlength->{issuelength}
1168
      if defined($loanlength) && $loanlength->{issuelength} ne 'NULL';
1169
1170
    # if no rule is set => 21 days (hardcoded)
1171
    return 21;
1172
}
1173
1174
1175
=head2 GetHardDueDate
1176
1177
  my ($hardduedate,$hardduedatecompare) = &GetHardDueDate($borrowertype,$itemtype,branchcode)
1178
1179
Get the Hard Due Date and it's comparison for an itemtype, a borrower type and a branch
1180
1181
=cut
1182
1183
sub GetHardDueDate {
1184
    my ( $borrowertype, $itemtype, $branchcode ) = @_;
1185
    my $dbh = C4::Context->dbh;
1186
    my $sth =
1187
      $dbh->prepare(
1188
"select hardduedate, hardduedatecompare from issuingrules where categorycode=? and itemtype=? and branchcode=?"
1189
      );
1190
    $sth->execute( $borrowertype, $itemtype, $branchcode );
1191
    my $results = $sth->fetchrow_hashref;
1192
    return (C4::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare})
1193
      if defined($results) && $results->{hardduedate} ne 'NULL';
1194
1195
    $sth->execute( $borrowertype, "*", $branchcode );
1196
    $results = $sth->fetchrow_hashref;
1197
    return (C4::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare})
1198
      if defined($results) && $results->{hardduedate} ne 'NULL';
1199
1200
    $sth->execute( "*", $itemtype, $branchcode );
1201
    $results = $sth->fetchrow_hashref;
1202
    return (C4::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare})
1203
      if defined($results) && $results->{hardduedate} ne 'NULL';
1204
1205
    $sth->execute( "*", "*", $branchcode );
1206
    $results = $sth->fetchrow_hashref;
1207
    return (C4::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare})
1208
      if defined($results) && $results->{hardduedate} ne 'NULL';
1209
1210
    $sth->execute( $borrowertype, $itemtype, "*" );
1211
    $results = $sth->fetchrow_hashref;
1212
    return (C4::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare})
1213
      if defined($results) && $results->{hardduedate} ne 'NULL';
1214
1215
    $sth->execute( $borrowertype, "*", "*" );
1216
    $results = $sth->fetchrow_hashref;
1217
    return (C4::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare})
1218
      if defined($results) && $results->{hardduedate} ne 'NULL';
1219
1220
    $sth->execute( "*", $itemtype, "*" );
1221
    $results = $sth->fetchrow_hashref;
1222
    return (C4::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare})
1223
      if defined($results) && $results->{hardduedate} ne 'NULL';
1224
1225
    $sth->execute( "*", "*", "*" );
1226
    $results = $sth->fetchrow_hashref;
1227
    return (C4::Dates->new($results->{hardduedate}, 'iso'),$results->{hardduedatecompare})
1228
      if defined($results) && $results->{hardduedate} ne 'NULL';
1229
1230
    # if no rule is set => return undefined
1231
    return (undef, undef);
1232
}
1233
1234
=head2 GetIssuingRule
1235
1236
  my $irule = &GetIssuingRule($borrowertype,$itemtype,branchcode)
1237
1238
FIXME - This is a copy-paste of GetLoanLength
1239
as a stop-gap.  Do not wish to change API for GetLoanLength 
1240
this close to release, however, Overdues::GetIssuingRules is broken.
1241
1242
Get the issuing rule for an itemtype, a borrower type and a branch
1243
Returns a hashref from the issuingrules table.
1244
1245
=cut
1246
1247
sub GetIssuingRule {
1248
    my ( $borrowertype, $itemtype, $branchcode ) = @_;
1249
    my $dbh = C4::Context->dbh;
1250
    my $sth =  $dbh->prepare( "select * from issuingrules where categorycode=? and itemtype=? and branchcode=? and issuelength is not null"  );
1251
    my $irule;
1252
1253
	$sth->execute( $borrowertype, $itemtype, $branchcode );
1254
    $irule = $sth->fetchrow_hashref;
1255
    return $irule if defined($irule) ;
1256
1257
    $sth->execute( $borrowertype, "*", $branchcode );
1258
    $irule = $sth->fetchrow_hashref;
1259
    return $irule if defined($irule) ;
1260
1261
    $sth->execute( "*", $itemtype, $branchcode );
1262
    $irule = $sth->fetchrow_hashref;
1263
    return $irule if defined($irule) ;
1264
1265
    $sth->execute( "*", "*", $branchcode );
1266
    $irule = $sth->fetchrow_hashref;
1267
    return $irule if defined($irule) ;
1268
1269
    $sth->execute( $borrowertype, $itemtype, "*" );
1270
    $irule = $sth->fetchrow_hashref;
1271
    return $irule if defined($irule) ;
1272
1273
    $sth->execute( $borrowertype, "*", "*" );
1274
    $irule = $sth->fetchrow_hashref;
1275
    return $irule if defined($irule) ;
1276
1277
    $sth->execute( "*", $itemtype, "*" );
1278
    $irule = $sth->fetchrow_hashref;
1279
    return $irule if defined($irule) ;
1280
1281
    $sth->execute( "*", "*", "*" );
1282
    $irule = $sth->fetchrow_hashref;
1283
    return $irule if defined($irule) ;
1284
1285
    # if no rule matches,
1286
    return undef;
1287
}
1288
1289
=head2 GetBranchBorrowerCircRule
1290
1291
  my $branch_cat_rule = GetBranchBorrowerCircRule($branchcode, $categorycode);
1292
1293
Retrieves circulation rule attributes that apply to the given
1294
branch and patron category, regardless of item type.  
1295
The return value is a hashref containing the following key:
1296
1297
maxissueqty - maximum number of loans that a
1298
patron of the given category can have at the given
1299
branch.  If the value is undef, no limit.
1300
1301
This will first check for a specific branch and
1302
category match from branch_borrower_circ_rules. 
1303
1304
If no rule is found, it will then check default_branch_circ_rules
1305
(same branch, default category).  If no rule is found,
1306
it will then check default_borrower_circ_rules (default 
1307
branch, same category), then failing that, default_circ_rules
1308
(default branch, default category).
1309
1310
If no rule has been found in the database, it will default to
1311
the buillt in rule:
1312
1313
maxissueqty - undef
1314
1315
C<$branchcode> and C<$categorycode> should contain the
1316
literal branch code and patron category code, respectively - no
1317
wildcards.
1318
1319
=cut
1320
1321
sub GetBranchBorrowerCircRule {
1322
    my $branchcode = shift;
1323
    my $categorycode = shift;
1324
1325
    my $branch_cat_query = "SELECT maxissueqty
1326
                            FROM branch_borrower_circ_rules
1327
                            WHERE branchcode = ?
1328
                            AND   categorycode = ?";
1329
    my $dbh = C4::Context->dbh();
1330
    my $sth = $dbh->prepare($branch_cat_query);
1331
    $sth->execute($branchcode, $categorycode);
1332
    my $result;
1333
    if ($result = $sth->fetchrow_hashref()) {
1334
        return $result;
1335
    }
1336
1337
    # try same branch, default borrower category
1338
    my $branch_query = "SELECT maxissueqty
1339
                        FROM default_branch_circ_rules
1340
                        WHERE branchcode = ?";
1341
    $sth = $dbh->prepare($branch_query);
1342
    $sth->execute($branchcode);
1343
    if ($result = $sth->fetchrow_hashref()) {
1344
        return $result;
1345
    }
1346
1347
    # try default branch, same borrower category
1348
    my $category_query = "SELECT maxissueqty
1349
                          FROM default_borrower_circ_rules
1350
                          WHERE categorycode = ?";
1351
    $sth = $dbh->prepare($category_query);
1352
    $sth->execute($categorycode);
1353
    if ($result = $sth->fetchrow_hashref()) {
1354
        return $result;
1355
    }
1356
  
1357
    # try default branch, default borrower category
1358
    my $default_query = "SELECT maxissueqty
1359
                          FROM default_circ_rules";
1360
    $sth = $dbh->prepare($default_query);
1361
    $sth->execute();
1362
    if ($result = $sth->fetchrow_hashref()) {
1363
        return $result;
1364
    }
1365
    
1366
    # built-in default circulation rule
1367
    return {
1368
        maxissueqty => undef,
1369
    };
1370
}
1371
1372
=head2 GetBranchItemRule
1373
1374
  my $branch_item_rule = GetBranchItemRule($branchcode, $itemtype);
1375
1376
Retrieves circulation rule attributes that apply to the given
1377
branch and item type, regardless of patron category.
1378
1379
The return value is a hashref containing the following key:
1380
1381
holdallowed => Hold policy for this branch and itemtype. Possible values:
1382
  0: No holds allowed.
1383
  1: Holds allowed only by patrons that have the same homebranch as the item.
1384
  2: Holds allowed from any patron.
1385
1386
This searches branchitemrules in the following order:
1387
1388
  * Same branchcode and itemtype
1389
  * Same branchcode, itemtype '*'
1390
  * branchcode '*', same itemtype
1391
  * branchcode and itemtype '*'
1392
1393
Neither C<$branchcode> nor C<$categorycode> should be '*'.
1394
1395
=cut
1396
1397
sub GetBranchItemRule {
1398
    my ( $branchcode, $itemtype ) = @_;
1399
    my $dbh = C4::Context->dbh();
1400
    my $result = {};
1401
1402
    my @attempts = (
1403
        ['SELECT holdallowed
1404
            FROM branch_item_rules
1405
            WHERE branchcode = ?
1406
              AND itemtype = ?', $branchcode, $itemtype],
1407
        ['SELECT holdallowed
1408
            FROM default_branch_circ_rules
1409
            WHERE branchcode = ?', $branchcode],
1410
        ['SELECT holdallowed
1411
            FROM default_branch_item_rules
1412
            WHERE itemtype = ?', $itemtype],
1413
        ['SELECT holdallowed
1414
            FROM default_circ_rules'],
1415
    );
1416
1417
    foreach my $attempt (@attempts) {
1418
        my ($query, @bind_params) = @{$attempt};
1419
1420
        # Since branch/category and branch/itemtype use the same per-branch
1421
        # defaults tables, we have to check that the key we want is set, not
1422
        # just that a row was returned
1423
        return $result if ( defined( $result->{'holdallowed'} = $dbh->selectrow_array( $query, {}, @bind_params ) ) );
1424
    }
1425
    
1426
    # built-in default circulation rule
1427
    return {
1428
        holdallowed => 2,
1429
    };
1430
}
1132
}
1431
1133
1432
=head2 AddReturn
1134
=head2 AddReturn
Lines 1504-1511 patron who last borrowed the book. Link Here
1504
=cut
1206
=cut
1505
1207
1506
sub AddReturn {
1208
sub AddReturn {
1507
    my ( $barcode, $branch, $exemptfine, $dropbox ) = @_;
1209
    my ( $barcode, $branch, $exemptfine, $dropbox, $force) = @_;
1508
    if ($branch and not GetBranchDetail($branch)) {
1210
    if ( $branch and not GetBranchDetail($branch) ) {
1509
        warn "AddReturn error: branch '$branch' not found.  Reverting to " . C4::Context->userenv->{'branch'};
1211
        warn "AddReturn error: branch '$branch' not found.  Reverting to " . C4::Context->userenv->{'branch'};
1510
        undef $branch;
1212
        undef $branch;
1511
    }
1213
    }
Lines 1549-1557 sub AddReturn { Link Here
1549
        my $branches = GetBranches();    # a potentially expensive call for a non-feature.
1251
        my $branches = GetBranches();    # a potentially expensive call for a non-feature.
1550
        $branches->{$hbr}->{PE} and $messages->{'IsPermanent'} = $hbr;
1252
        $branches->{$hbr}->{PE} and $messages->{'IsPermanent'} = $hbr;
1551
    }
1253
    }
1552
1254
    my $branchtransferfield=C4::Context->preference("BranchTransferLimitsType") eq "ccode" ? "ccode" : "itype";
1255
    $debug && warn "$branch, $hbr, ",C4::Context->preference("BranchTransferLimitsType")," ,",$item->{ $branchtransferfield } ;
1256
    $debug && warn Dump($item);
1257
    $debug && warn IsBranchTransferAllowed( $branch, $hbr, $item->{ C4::Context->preference("BranchTransferLimitsType") } );
1553
    # if indy branches and returning to different branch, refuse the return
1258
    # if indy branches and returning to different branch, refuse the return
1554
    if ($hbr ne $branch && C4::Context->preference("IndependantBranches")){
1259
    if ( !$force && ($hbr ne $branch)
1260
		&& (C4::Context->preference("IndependantBranches") 
1261
			or ( C4::Context->preference("UseBranchTransferLimits")
1262
                and !IsBranchTransferAllowed( $branch, $hbr, $item->{$branchtransferfield } ) )
1263
		    )
1264
		){
1555
        $messages->{'Wrongbranch'} = {
1265
        $messages->{'Wrongbranch'} = {
1556
            Wrongbranch => $branch,
1266
            Wrongbranch => $branch,
1557
            Rightbranch => $hbr,
1267
            Rightbranch => $hbr,
Lines 1562-1568 sub AddReturn { Link Here
1562
        # FIXME - even in an indy branches situation, there should
1272
        # FIXME - even in an indy branches situation, there should
1563
        # still be an option for the library to accept the item
1273
        # still be an option for the library to accept the item
1564
        # and transfer it to its owning library.
1274
        # and transfer it to its owning library.
1565
        return ( $doreturn, $messages, $issue, $borrower );
1566
    }
1275
    }
1567
1276
1568
    if ( $item->{'wthdrawn'} ) { # book has been cancelled
1277
    if ( $item->{'wthdrawn'} ) { # book has been cancelled
Lines 1573-1584 sub AddReturn { Link Here
1573
    # case of a return of document (deal with issues and holdingbranch)
1282
    # case of a return of document (deal with issues and holdingbranch)
1574
    if ($doreturn) {
1283
    if ($doreturn) {
1575
        $borrower or warn "AddReturn without current borrower";
1284
        $borrower or warn "AddReturn without current borrower";
1576
		my $circControlBranch;
1285
        my $circControlBranch;
1577
        if ($dropbox) {
1286
        if ($dropbox) {
1578
            # define circControlBranch only if dropbox mode is set
1287
            $circControlBranch = _GetCircControlBranch( $item, $borrower );
1579
            # don't allow dropbox mode to create an invalid entry in issues (issuedate > today)
1288
            # don't allow dropbox mode to create an invalid entry in issues (issuedate > returndate) FIXME: actually checks eq, not gt
1580
            # FIXME: check issuedate > returndate, factoring in holidays
1289
            undef($dropbox) if ( $item->{'issuedate'} eq C4::Dates->today('iso') );
1581
            $circControlBranch = _GetCircControlBranch($item,$borrower) unless ( $item->{'issuedate'} eq C4::Dates->today('iso') );;
1582
        }
1290
        }
1583
1291
1584
        if ($borrowernumber) {
1292
        if ($borrowernumber) {
Lines 1586-1600 sub AddReturn { Link Here
1586
            $messages->{'WasReturned'} = 1;    # FIXME is the "= 1" right?  This could be the borrower hash.
1294
            $messages->{'WasReturned'} = 1;    # FIXME is the "= 1" right?  This could be the borrower hash.
1587
        }
1295
        }
1588
1296
1589
        ModItem({ onloan => undef }, $issue->{'biblionumber'}, $item->{'itemnumber'});
1297
        ModItem( { renewals=>0, onloan => undef }, $issue->{'biblionumber'}, $item->{'itemnumber'} );
1298
    	# the holdingbranch is updated if the document is returned to another location.
1299
    	# this is always done regardless of whether the item was on loan or not
1300
    	if ( $item->{'holdingbranch'} ne $branch ) {
1301
       	    UpdateHoldingbranch( $branch, $item->{'itemnumber'} );
1302
            $item->{'holdingbranch'} = $branch;    # update item data holdingbranch too
1303
	    }	   
1590
    }
1304
    }
1591
1305
1592
    # the holdingbranch is updated if the document is returned to another location.
1593
    # this is always done regardless of whether the item was on loan or not
1594
    if ($item->{'holdingbranch'} ne $branch) {
1595
        UpdateHoldingbranch($branch, $item->{'itemnumber'});
1596
        $item->{'holdingbranch'} = $branch; # update item data holdingbranch too
1597
    }
1598
    ModDateLastSeen( $item->{'itemnumber'} );
1306
    ModDateLastSeen( $item->{'itemnumber'} );
1599
1307
1600
    # check if we have a transfer for this document
1308
    # check if we have a transfer for this document
Lines 1621-1631 sub AddReturn { Link Here
1621
        _FixAccountForLostAndReturned($item->{'itemnumber'}, $borrowernumber, $barcode);    # can tolerate undef $borrowernumber
1329
        _FixAccountForLostAndReturned($item->{'itemnumber'}, $borrowernumber, $barcode);    # can tolerate undef $borrowernumber
1622
        $messages->{'WasLost'} = 1;
1330
        $messages->{'WasLost'} = 1;
1623
    }
1331
    }
1332
    if ($item->{'notforloan'}){
1333
        $messages->{'NotForLoan'} = $item->{'notforloan'};
1334
    }
1335
    if ($item->{'damaged'}){
1336
        $messages->{'Damaged'} = $item->{'damaged'};
1337
    }
1624
1338
1625
    # fix up the overdues in accounts...
1339
    if ($borrowernumber && $doreturn) {
1626
    if ($borrowernumber) {
1340
        # fix up the overdues in accounts...
1627
        my $fix = _FixOverduesOnReturn($borrowernumber, $item->{itemnumber}, $exemptfine, $dropbox);
1341
        my $fix = _FixOverduesOnReturn($borrowernumber, $item->{itemnumber}, $exemptfine, $dropbox);
1628
        defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $item->{itemnumber}...) failed!";  # zero is OK, check defined
1342
        defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $item->{itemnumber}...) failed!";  # zero is OK, check defined
1343
    
1344
        # fix fine days
1345
        my $debardate = _FixFineDaysOnReturn($borrower, $item, $issue->{date_due});
1346
        $messages->{'Debarred'} = $debardate if($debardate);
1347
1348
        # get fines for the borrower
1349
        my $fineamount = C4::Overdues::GetFine($borrowernumber);
1350
        $messages->{'HaveFines'} = $fineamount if($fineamount);
1351
        
1629
    }
1352
    }
1630
1353
1631
    # find reserves.....
1354
    # find reserves.....
Lines 1661-1680 sub AddReturn { Link Here
1661
            branch   => $branch,
1384
            branch   => $branch,
1662
        });
1385
        });
1663
    }
1386
    }
1664
    
1387
1665
    logaction("CIRCULATION", "RETURN", $borrowernumber, $item->{'biblionumber'})
1388
    logaction( "CIRCULATION", "RETURN", $borrowernumber, $item->{'itemnumber'} )
1666
        if C4::Context->preference("ReturnLog");
1389
      if C4::Context->preference("ReturnLog");
1667
    
1390
1668
    # FIXME: make this comment intelligible.
1391
    # FIXME: make this comment intelligible.
1669
    #adding message if holdingbranch is non equal a userenv branch to return the document to homebranch
1392
    #adding message if holdingbranch is non equal a userenv branch to return the document to homebranch
1670
    #we check, if we don't have reserv or transfert for this document, if not, return it to homebranch .
1393
    #we check, if we don't have reserv or transfert for this document, if not, return it to homebranch .
1671
1394
1672
    if (($doreturn or $messages->{'NotIssued'}) and !$resfound and ($branch ne $hbr) and not $messages->{'WrongTransfer'}){
1395
    if ( ($doreturn or $messages->{'NotIssued'}) and ( $branch ne $hbr ) and not $messages->{'WrongTransfer'} and ( $validTransfert ne 1 ) ) {
1673
        if ( C4::Context->preference("AutomaticItemReturn"    ) or
1396
        if (C4::Context->preference("AutomaticItemReturn")
1674
            (C4::Context->preference("UseBranchTransferLimits") and
1397
            or ( C4::Context->preference("UseBranchTransferLimits")
1675
             ! IsBranchTransferAllowed($branch, $hbr, $item->{C4::Context->preference("BranchTransferLimitsType")} )
1398
                and !IsBranchTransferAllowed( $branch, $hbr, $item->{ $branchtransferfield } ) )
1676
           )) {
1399
          ) {
1677
            $debug and warn sprintf "about to call ModItemTransfer(%s, %s, %s)", $item->{'itemnumber'},$branch, $hbr;
1400
            $debug and warn sprintf "about to call ModItemTransfer(%s, %s, %s)", $item->{'itemnumber'}, $branch, $hbr;
1678
            $debug and warn "item: " . Dumper($item);
1401
            $debug and warn "item: " . Dumper($item);
1679
            ModItemTransfer($item->{'itemnumber'}, $branch, $hbr);
1402
            ModItemTransfer($item->{'itemnumber'}, $branch, $hbr);
1680
            $messages->{'WasTransfered'} = 1;
1403
            $messages->{'WasTransfered'} = 1;
Lines 1749-1754 sub MarkIssueReturned { Link Here
1749
    $sth_del->execute($borrowernumber, $itemnumber);
1472
    $sth_del->execute($borrowernumber, $itemnumber);
1750
}
1473
}
1751
1474
1475
=head2 _FixFineDaysOnReturn
1476
1477
    &_FixFineDaysOnReturn($borrower, $item, $datedue);
1478
1479
C<$borrower> borrower hashref
1480
1481
C<$item> item hashref
1482
1483
C<$datedue> date due
1484
1485
Internal function, called only by AddReturn that calculate and update the user fine days, and debars him
1486
1487
=cut
1488
1489
sub _FixFineDaysOnReturn {
1490
    my ($borrower, $item, $datedue) = @_;
1491
    
1492
    if($datedue){
1493
        $datedue = C4::Dates->new($datedue,"iso");
1494
    }else{
1495
        return;
1496
    }
1497
    
1498
    my $branchcode  =_GetCircControlBranch($item, $borrower);
1499
    my $calendar    = C4::Calendar->new( branchcode => $branchcode );
1500
    my $today       = C4::Dates->new();
1501
1502
    my $deltadays = $calendar->daysBetween($datedue, C4::Dates->new());
1503
1504
    my $circcontrol = C4::Context::preference('CircControl');
1505
    my $issuingrule = GetIssuingRule($borrower->{categorycode}, $item->{itype}, $branchcode);
1506
    my $finedays    = $issuingrule->{finedays};
1507
    # exit if no finedays defined
1508
    return unless $finedays;
1509
    my $grace       = $issuingrule->{firstremind};
1510
1511
    if( $deltadays - $grace > 0){
1512
        my @newdate     = Add_Delta_Days(Today(), $deltadays * $finedays );
1513
        my $isonewdate  = join('-',@newdate);
1514
        my ($deby, $debm, $debd) = split(/-/,$borrower->{debarred});
1515
        if(check_date($deby, $debm, $debd)){
1516
            my @olddate = split(/-/, $borrower->{debarred});
1517
1518
            if(Delta_Days(@olddate,@newdate) > 0){
1519
                C4::Members::DebarMember($borrower->{borrowernumber}, $isonewdate);
1520
                return $isonewdate;
1521
            }
1522
        }else{
1523
            C4::Members::DebarMember($borrower->{borrowernumber}, $isonewdate);
1524
            return $isonewdate;
1525
        }
1526
    }
1527
}
1528
1529
1752
=head2 _FixOverduesOnReturn
1530
=head2 _FixOverduesOnReturn
1753
1531
1754
   &_FixOverduesOnReturn($brn,$itm, $exemptfine, $dropboxmode);
1532
   &_FixOverduesOnReturn($brn,$itm, $exemptfine, $dropboxmode);
Lines 1923-1930 sub _GetCircControlBranch { Link Here
1923
    my $circcontrol = C4::Context->preference('CircControl');
1701
    my $circcontrol = C4::Context->preference('CircControl');
1924
    my $branch;
1702
    my $branch;
1925
1703
1926
    if ($circcontrol eq 'PickupLibrary') {
1704
    if ($circcontrol eq 'PickupLibrary' && C4::Context->userenv->{'branch'}) {
1927
        $branch= C4::Context->userenv->{'branch'} if C4::Context->userenv;
1705
        $branch= C4::Context->userenv->{'branch'};
1928
    } elsif ($circcontrol eq 'PatronLibrary') {
1706
    } elsif ($circcontrol eq 'PatronLibrary') {
1929
        $branch=$borrower->{branchcode};
1707
        $branch=$borrower->{branchcode};
1930
    } else {
1708
    } else {
Lines 1960-1966 sub GetItemIssue { Link Here
1960
    my ($itemnumber) = @_;
1738
    my ($itemnumber) = @_;
1961
    return unless $itemnumber;
1739
    return unless $itemnumber;
1962
    my $sth = C4::Context->dbh->prepare(
1740
    my $sth = C4::Context->dbh->prepare(
1963
        "SELECT *
1741
        "SELECT *, issues.renewals as 'issues.renewals'
1964
        FROM issues 
1742
        FROM issues 
1965
        LEFT JOIN items ON issues.itemnumber=items.itemnumber
1743
        LEFT JOIN items ON issues.itemnumber=items.itemnumber
1966
        WHERE issues.itemnumber=?");
1744
        WHERE issues.itemnumber=?");
Lines 2031-2037 sub GetItemIssues { Link Here
2031
    }
1809
    }
2032
    my $results = $sth->fetchall_arrayref({});
1810
    my $results = $sth->fetchall_arrayref({});
2033
    foreach (@$results) {
1811
    foreach (@$results) {
2034
        $_->{'overdue'} = ($_->{'date_due'} lt $today) ? 1 : 0;
1812
        $_->{'overdue'} = ( $_->{'date_due'} lt $today && !defined($_->{return_date}) ) ? 1 : 0;
2035
    }
1813
    }
2036
    return $results;
1814
    return $results;
2037
}
1815
}
Lines 2138-2206 already renewed the loan. $error will contain the reason the renewal can not pro Link Here
2138
sub CanBookBeRenewed {
1916
sub CanBookBeRenewed {
2139
1917
2140
    # check renewal status
1918
    # check renewal status
2141
    my ( $borrowernumber, $itemnumber, $override_limit ) = @_;
1919
    my ( $borrowernumber, $itemnumber ) = @_;
2142
    my $dbh       = C4::Context->dbh;
1920
    my $dbh       = C4::Context->dbh;
2143
    my $renews    = 1;
1921
    my $renews    = 1;
2144
    my $renewokay = 0;
1922
    my $renewokay = 1;
2145
	my $error;
1923
    my $error;
2146
1924
2147
    # Look in the issues table for this item, lent to this borrower,
1925
    # Look in the issues table for this item, lent to this borrower,
2148
    # and not yet returned.
1926
    # and not yet returned.
2149
1927
2150
    # Look in the issues table for this item, lent to this borrower,
1928
    # Look in the issues table for this item, lent to this borrower,
2151
    # and not yet returned.
1929
    # and not yet returned.
2152
    my %branch = (
1930
    my $borrower = C4::Members::GetMemberDetails( $borrowernumber, 0 ) or return undef;
2153
            'ItemHomeLibrary' => 'items.homebranch',
1931
    my $item = GetItem($itemnumber) or return undef;
2154
            'PickupLibrary'   => 'items.holdingbranch',
1932
    my $itemissue = GetItemIssue($itemnumber) or return undef;
2155
            'PatronLibrary'   => 'borrowers.branchcode'
1933
    my $branchcode = _GetCircControlBranch($item, $borrower);
2156
            );
1934
    if ($itemissue->{'overdue'}){
2157
    my $controlbranch = $branch{C4::Context->preference('CircControl')};
1935
       $renewokay=0;
2158
    my $itype         = C4::Context->preference('item-level_itypes') ? 'items.itype' : 'biblioitems.itemtype';
1936
       $error->{message}='overdue'; 
1937
    }
2159
    
1938
    
2160
    my $sthcount = $dbh->prepare("
1939
    my $issuingrule = GetIssuingRule($borrower->{categorycode}, $item->{itype}, $branchcode);
2161
                   SELECT 
1940
    
2162
                    borrowers.categorycode, biblioitems.itemtype, issues.renewals, renewalsallowed, $controlbranch
1941
    if ( $issuingrule->{renewalsallowed} <= $itemissue->{'issues.renewals'} )  {
2163
                   FROM  issuingrules, 
1942
        $renewokay=0;
2164
                   issues 
1943
        $error->{message} = "too_many";
2165
                   LEFT JOIN items USING (itemnumber) 
1944
    }
2166
                   LEFT JOIN borrowers USING (borrowernumber) 
2167
                   LEFT JOIN biblioitems USING (biblioitemnumber)
2168
                   
2169
                   WHERE
2170
                    (issuingrules.categorycode = borrowers.categorycode OR issuingrules.categorycode = '*')
2171
                   AND
2172
                    (issuingrules.itemtype = $itype OR issuingrules.itemtype = '*')
2173
                   AND
2174
                    (issuingrules.branchcode = $controlbranch OR issuingrules.branchcode = '*') 
2175
                   AND 
2176
                    borrowernumber = ? 
2177
                   AND
2178
                    itemnumber = ?
2179
                   ORDER BY
2180
                    issuingrules.categorycode desc,
2181
                    issuingrules.itemtype desc,
2182
                    issuingrules.branchcode desc
2183
                   LIMIT 1;
2184
                  ");
2185
2186
    $sthcount->execute( $borrowernumber, $itemnumber );
2187
    if ( my $data1 = $sthcount->fetchrow_hashref ) {
2188
        
2189
        if ( ( $data1->{renewalsallowed} && $data1->{renewalsallowed} > $data1->{renewals} ) || $override_limit ) {
2190
            $renewokay = 1;
2191
        }
2192
        else {
2193
			$error="too_many";
2194
		}
2195
		
2196
        my ( $resfound, $resrec ) = C4::Reserves::CheckReserves($itemnumber);
2197
        if ($resfound) {
2198
            $renewokay = 0;
2199
			$error="on_reserve"
2200
        }
2201
1945
1946
    my ( $resfound, $resrec ) = C4::Reserves::CheckReserves($itemnumber);
1947
    if ($resfound) {
1948
        $renewokay = 0;
1949
        $error->{message} = "on_reserve";
2202
    }
1950
    }
2203
    return ($renewokay,$error);
1951
    $error->{renewals}       = $itemissue->{'issues.renewals'};
1952
    $error->{renewalsallowed}= $issuingrule->{renewalsallowed};
1953
1954
    return ( $renewokay, $error );
2204
}
1955
}
2205
1956
2206
=head2 AddRenewal
1957
=head2 AddRenewal
Lines 2255-2273 sub AddRenewal { Link Here
2255
    # based on the value of the RenewalPeriodBase syspref.
2006
    # based on the value of the RenewalPeriodBase syspref.
2256
    unless ($datedue) {
2007
    unless ($datedue) {
2257
2008
2258
        my $borrower = C4::Members::GetMemberDetails( $borrowernumber, 0 ) or return undef;
2009
        my $borrower   = C4::Members::GetMemberDetails( $borrowernumber, 0 ) or return undef;
2259
        my $itemtype = (C4::Context->preference('item-level_itypes')) ? $biblio->{'itype'} : $biblio->{'itemtype'};
2010
        my $branchcode = _GetCircControlBranch($item, $borrower);
2011
        my $loanlength = GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $branchcode );
2012
2013
        $datedue =
2014
          ( C4::Context->preference('RenewalPeriodBase') eq 'date_due' )
2015
          ? C4::Dates->new( $issuedata->{date_due}, 'iso' )
2016
          : C4::Dates->new();
2017
2018
        my $itype = ( C4::Context->preference('item-level_itypes') ) ? $biblio->{'itype'} : $biblio->{'itemtype'};
2019
        my $controlbranch = _GetCircControlBranch( $item, $borrower );
2020
        warn "RENEWALPERIOD : ".$loanlength->{renewalperiod};
2021
        my $renewalperiod = $loanlength->{renewalperiod} || GetLoanLength( $borrower->{'categorycode'}, $itype, $controlbranch );
2022
2023
        $datedue = CalcDateDue( $datedue, $biblio->{'itemtype'}, $issuedata->{'branchcode'}, $borrower, $renewalperiod );
2260
2024
2261
        $datedue = (C4::Context->preference('RenewalPeriodBase') eq 'date_due') ?
2262
                                        C4::Dates->new($issuedata->{date_due}, 'iso') :
2263
                                        C4::Dates->new();
2264
        $datedue =  CalcDateDue($datedue,$itemtype,$issuedata->{'branchcode'},$borrower);
2265
    }
2025
    }
2266
2026
2267
    # Update the issues record to have the new due date, and a new count
2027
    # Update the issues record to have the new due date, and a new count
2268
    # of how many times it has been renewed.
2028
    # of how many times it has been renewed.
2269
    my $renews = $issuedata->{'renewals'} + 1;
2029
    my $renews = $issuedata->{'renewals'} + 1;
2270
    $sth = $dbh->prepare("UPDATE issues SET date_due = ?, renewals = ?, lastreneweddate = ?
2030
    $sth = $dbh->prepare(
2031
        "UPDATE issues SET date_due = ?, renewals = ?, lastreneweddate = ?
2271
                            WHERE borrowernumber=? 
2032
                            WHERE borrowernumber=? 
2272
                            AND itemnumber=?"
2033
                            AND itemnumber=?"
2273
    );
2034
    );
Lines 2275-2282 sub AddRenewal { Link Here
2275
    $sth->finish;
2036
    $sth->finish;
2276
2037
2277
    # Update the renewal count on the item, and tell zebra to reindex
2038
    # Update the renewal count on the item, and tell zebra to reindex
2278
    $renews = $biblio->{'renewals'} + 1;
2039
    $renews = $item->{'renewals'} + 1;
2279
    ModItem({ renewals => $renews, onloan => $datedue->output('iso') }, $biblio->{'biblionumber'}, $itemnumber);
2040
    ModItem( { renewals => $renews, onloan => $datedue->output('iso') }, undef, $itemnumber );
2280
2041
2281
    # Charge a new rental fee, if applicable?
2042
    # Charge a new rental fee, if applicable?
2282
    my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber );
2043
    my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber );
Lines 2692-2711 C<$startdate> = C4::Dates object representing start date of loan period (assum Link Here
2692
C<$itemtype>  = itemtype code of item in question
2453
C<$itemtype>  = itemtype code of item in question
2693
C<$branch>  = location whose calendar to use
2454
C<$branch>  = location whose calendar to use
2694
C<$borrower> = Borrower object
2455
C<$borrower> = Borrower object
2456
C<$renewalperiod> = if it's a renewal, give the duration of the renew. If empty, it will be set to initial checkout duration
2695
2457
2696
=cut
2458
=cut
2697
2459
2698
sub CalcDateDue { 
2460
sub CalcDateDue { 
2699
	my ($startdate,$itemtype,$branch,$borrower) = @_;
2461
	my ($startdate,$itemtype,$branch,$borrower,$renewalperiod) = @_;
2700
	my $datedue;
2462
	my $datedue;
2701
        my $loanlength = GetLoanLength($borrower->{'categorycode'},$itemtype, $branch);
2702
2463
2703
	# if globalDueDate ON the datedue is set to that date
2464
	# if globalDueDate ON the datedue is set to that date
2465
    my $rule = GetIssuingRule($borrower->{'categorycode'},$itemtype, $branch);
2704
	if ( C4::Context->preference('globalDueDate')
2466
	if ( C4::Context->preference('globalDueDate')
2705
             && ( C4::Context->preference('globalDueDate') =~ C4::Dates->regexp('syspref') ) ) {
2467
             && ( C4::Context->preference('globalDueDate') =~ C4::Dates->regexp('syspref') ) ) {
2706
            $datedue = C4::Dates->new( C4::Context->preference('globalDueDate') );
2468
            $datedue = C4::Dates->new( C4::Context->preference('globalDueDate') );
2707
	} else {
2469
	} else {
2708
	# otherwise, calculate the datedue as normal
2470
	# otherwise, calculate the datedue as normal
2471
        my $loanlength = $renewalperiod || $rule->{issuelength};
2709
		if(C4::Context->preference('useDaysMode') eq 'Days') {  # ignoring calendar
2472
		if(C4::Context->preference('useDaysMode') eq 'Days') {  # ignoring calendar
2710
			my $timedue = time + ($loanlength) * 86400;
2473
			my $timedue = time + ($loanlength) * 86400;
2711
		#FIXME - assumes now even though we take a startdate 
2474
		#FIXME - assumes now even though we take a startdate 
Lines 2717-2734 sub CalcDateDue { Link Here
2717
		}
2480
		}
2718
	}
2481
	}
2719
2482
2720
	# if Hard Due Dates are used, retreive them and apply as necessary
2483
    my ($hardduedate, $hardduedatecompare) = $rule->{qw(hardduedate hardduedatecompare)};
2721
        my ($hardduedate, $hardduedatecompare) = GetHardDueDate($borrower->{'categorycode'},$itemtype, $branch);
2484
	if ( $hardduedate and $hardduedate ne '0000-00-00') {
2722
	if ( $hardduedate && $hardduedate->output('iso') && $hardduedate->output('iso') ne '0000-00-00') {
2723
            # if the calculated due date is after the 'before' Hard Due Date (ceiling), override
2485
            # if the calculated due date is after the 'before' Hard Due Date (ceiling), override
2724
            if ( $datedue->output( 'iso' ) gt $hardduedate->output( 'iso' ) && $hardduedatecompare == -1) {
2486
            if ( $datedue->output( 'iso' ) gt $hardduedate && $hardduedatecompare == -1) {
2725
                $datedue = $hardduedate;
2487
                $datedue = C4::Dates->new( $hardduedate );
2726
            # if the calculated date is before the 'after' Hard Due Date (floor), override
2488
            # if the calculated date is before the 'after' Hard Due Date (floor), override
2727
            } elsif ( $datedue->output( 'iso' ) lt $hardduedate->output( 'iso' ) && $hardduedatecompare == 1) {
2489
            } elsif ( $datedue->output( 'iso' ) lt $hardduedate && $hardduedatecompare == 1) {
2728
                $datedue = $hardduedate;               
2490
                $datedue = C4::Dates->new( $hardduedate );               
2729
            # if the hard due date is set to 'exactly', overrride
2491
            # if the hard due date is set to 'exactly', overrride
2730
            } elsif ( $hardduedatecompare == 0) {
2492
            } elsif ( $hardduedatecompare == 0) {
2731
                $datedue = $hardduedate;
2493
                $datedue = C4::Dates->new( $hardduedate );
2732
            }
2494
            }
2733
            # in all other cases, keep the date due as it is
2495
            # in all other cases, keep the date due as it is
2734
	}
2496
	}
Lines 2932-2949 sub CreateBranchTransferLimit { Link Here
2932
2694
2933
=head2 DeleteBranchTransferLimits
2695
=head2 DeleteBranchTransferLimits
2934
2696
2935
  DeleteBranchTransferLimits();
2697
  DeleteBranchTransferLimits($tobranch);
2936
2698
2937
=cut
2699
=cut
2938
2700
2939
sub DeleteBranchTransferLimits {
2701
sub DeleteBranchTransferLimits {
2940
   my $dbh = C4::Context->dbh;
2702
    my $branch = shift;
2941
   my $sth = $dbh->prepare("TRUNCATE TABLE branch_transfer_limits");
2703
    my $dbh = C4::Context->dbh;
2942
   $sth->execute();
2704
    my $sth = $dbh->prepare("DELETE FROM branch_transfer_limits WHERE toBranch = ?");
2705
    $sth->execute($branch);
2943
}
2706
}
2944
2707
2945
2708
1;
2946
  1;
2947
2709
2948
__END__
2710
__END__
2949
2711
(-)a/C4/IssuingRules.pm (+278 lines)
Line 0 Link Here
1
package C4::IssuingRules;
2
3
# Copyright 2009 BibLibre SARL
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 with
17
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18
# Suite 330, Boston, MA  02111-1307 USA
19
20
use strict;
21
use warnings;
22
use C4::Context;
23
use C4::Koha;
24
use C4::SQLHelper qw( SearchInTable InsertInTable UpdateInTable DeleteInTable );
25
eval {
26
   my $servers = C4::Context->config('memcached_servers');
27
   if ($servers) {
28
      require Memoize::Memcached;
29
      import Memoize::Memcached qw(memoize_memcached flush_cache);
30
      my $memcached = {
31
             servers    => [$servers],
32
             key_prefix => C4::Context->config('memcached_namespace') || 'koha',
33
      };
34
      memoize_memcached( 'GetIssuingRule',        memcached => $memcached, expire_time => 600000 );    #cache for 10 minutes
35
      memoize_memcached( 'GetIssuingRules',        memcached => $memcached, expire_time => 600000 );    #cache for 10 minutes
36
   }
37
38
};
39
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
40
41
BEGIN {
42
	# set the version for version checking
43
	$VERSION = 3.0.5;
44
	@ISA    = qw(Exporter);
45
	@EXPORT = qw(
46
	    &GetIssuingRule
47
		&GetIssuingRulesByBranchCode
48
		&GetIssuingRules
49
		&AddIssuingRule
50
		&ModIssuingRule
51
		&DelIssuingRule
52
	);
53
}
54
55
=head1 NAME
56
57
C4::IssuingRules - Koha issuing rules module
58
59
=head1 SYNOPSIS
60
61
use C4::IssuingRules;
62
63
=head1 DESCRIPTION
64
65
The functions in this module deal with issuing rules.
66
67
=head1 FUNCTIONS
68
69
=head2 GetIssuingRule
70
71
Compute the issuing rule for an itemtype, a borrower category and a branch.
72
Returns a hashref from the issuingrules table.
73
74
my $rule = &GetIssuingRule($categorycode, $itemtype, $branchcode);
75
76
The rules are applied from most specific to less specific, using the first found in this order:
77
    * same library, same patron type, same item type
78
    * same library, same patron type, default item type
79
    * same library, default patron type, same item type
80
    * same library, default patron type, default item type
81
    * default library, same patron type, same item type
82
    * default library, same patron type, default item type
83
    * default library, default patron type, same item type
84
    * default library, default patron type, default item type
85
86
The values in the returned hashref are inherited from a more generic rules if undef.
87
88
=cut
89
#Caching GetIssuingRule
90
91
sub GetIssuingRule {
92
    my ( $categorycode, $itemtype, $branchcode ) = @_;
93
    $categorycode||="*";
94
    $itemtype||="*";
95
    $branchcode||="*";
96
97
    # This configuration table defines the order of inheritance. We'll loop over it.
98
    my @attempts = (
99
        [ "*"          , "*"      , "*"         ],
100
        [ "*"          , $itemtype, "*"         ],
101
        [ $categorycode, "*"      , "*"         ],
102
        [ $categorycode, $itemtype, "*"         ],
103
        [ "*"          , "*"      , $branchcode ],
104
        [ "*"          , $itemtype, $branchcode ],
105
        [ $categorycode, "*"      , $branchcode ],
106
        [ $categorycode, $itemtype, $branchcode ],
107
    );
108
109
    # This complex query returns a nested hashref, so we can access a rule using :
110
    # my $rule = $$rules{$categorycode}{$itemtype}{$branchcode};
111
    # this will be usefull in the inheritance computation code
112
    my $dbh = C4::Context->dbh;
113
    my $rules = $dbh->selectall_hashref(
114
        "SELECT * FROM issuingrules where branchcode IN ('*',?) and itemtype IN ('*', ?) and categorycode IN ('*',?)",
115
        ["branchcode", "itemtype", "categorycode"],
116
        undef,
117
        ( $branchcode, $itemtype, $categorycode )
118
    );
119
120
    # This block is for inheritance. It loops over rules returned by the 
121
    # previous query. If a value is found in a more specific rule, it replaces 
122
    # the old value from the more generic rule.
123
    my $oldrule;
124
    for my $attempt ( @attempts ) {
125
        if ( my $rule = $$rules{@$attempt[2]}{@$attempt[1]}{@$attempt[0]} ) {
126
            if ( $oldrule ) {
127
                for ( keys %$oldrule ) {
128
                    if ( defined $rule->{$_} ) {
129
                        $oldrule->{$_} = $rule->{$_};
130
                    }
131
                }
132
            } else {
133
                $oldrule = $rule;
134
            }
135
        }
136
    }
137
    if($oldrule){
138
        return $oldrule;
139
    }else{
140
        return {
141
            'itemtype'          => $itemtype,
142
            'categorycode'      => $categorycode,
143
            'branchcode'        => $branchcode,
144
            'holdspickupdelay'  => 0,
145
       #     'maxissueqty'       => 0,
146
            'renewalsallowed'   => 0,
147
            'firstremind'       => 0,
148
            'accountsent'       => 0,
149
            'reservecharge'     => 0,
150
            'fine'              => 0,
151
            'restrictedtype'    => 0,
152
            'rentaldiscount'    => 0,
153
            'chargename'        => 0,
154
            'finedays'          => 0,
155
            'holdrestricted'    => 0,
156
            'allowonshelfholds' => 0,
157
            'reservesallowed'   => 0,
158
            'chargeperiod'      => 0,
159
       #     'issuelength'       => 0,
160
            'renewalperiod'     => 0,
161
        };
162
    }
163
}
164
165
=head2 GetIssuingRulesByBranchCode
166
  
167
  my @issuingrules = &GetIssuingRulesByBranchCode($branchcode);
168
169
  Retruns a list of hashref from the issuingrules Koha table for a given 
170
  branchcode.
171
  Each hashref will contain data from issuingrules plus human readable names of 
172
  patron and item categories.
173
174
=cut
175
176
sub GetIssuingRulesByBranchCode {
177
    my $dbh = C4::Context->dbh;
178
    my $sth = $dbh->prepare("
179
        SELECT issuingrules.*, itemtypes.description AS humanitemtype, categories.description AS humancategorycode
180
        FROM issuingrules
181
        LEFT JOIN itemtypes
182
            ON (itemtypes.itemtype = issuingrules.itemtype)
183
        LEFT JOIN categories
184
            ON (categories.categorycode = issuingrules.categorycode)
185
        WHERE issuingrules.branchcode = ?
186
        ORDER BY humancategorycode, humanitemtype
187
    ");
188
    $sth->execute(shift);
189
    
190
    my $res = $sth->fetchall_arrayref({});
191
    
192
    return @$res;
193
}
194
195
=head2 GetIssuingRules
196
  
197
  my @issuingrules = &GetIssuingRules({
198
      branchcode   => $branch, 
199
      categorycode => $input->param('categorycode'), 
200
      itemtype     => $input->param('itemtype'),
201
  });
202
203
  Get an issuing rule from Koha database.
204
  An alias for SearchInTable, see C4::SQLHelper for more help.
205
206
=cut
207
208
sub GetIssuingRules {
209
    my $res = SearchInTable('issuingrules', shift);
210
    return @$res;
211
}
212
213
=head2 AddIssuingRule
214
215
  my $issuingrule = {
216
      branchcode      => $branch,
217
      categorycode    => $input->param('categorycode'),
218
      itemtype        => $input->param('itemtype'),
219
      maxissueqty     => $maxissueqty,
220
      renewalsallowed => $input->param('renewalsallowed'),
221
      reservesallowed => $input->param('reservesallowed'),
222
      issuelength     => $input->param('issuelength'),
223
      fine            => $input->param('fine'),
224
      finedays        => $input->param('finedays'),
225
      firstremind     => $input->param('firstremind'),
226
      chargeperiod    => $input->param('chargeperiod'),
227
  };
228
  
229
  &AddIssuingRule( $issuingrule );
230
231
  Adds an issuing rule to Koha database.
232
  An alias for InsertInTable, see C4::SQLHelper for more help.
233
234
=cut
235
236
sub AddIssuingRule { InsertInTable('issuingrules',shift); }
237
238
=head2 ModIssuingRule
239
  
240
  &ModIssuingRule( $issuingrule );
241
242
  Update an issuing rule of the Koha database.
243
  An alias for UpdateInTable, see C4::SQLHelper for more help.
244
245
=cut
246
247
sub ModIssuingRule { 
248
    if (C4::Context->config('memcached_servers')){
249
        flush_cache('GetIssuingRule');
250
        flush_cache('GetIssuingRules');
251
    }
252
    UpdateInTable('issuingrules',shift); 
253
}
254
255
=head2 DelIssuingRule
256
  
257
  DelIssuingRule({
258
      branchcode   => $branch, 
259
      categorycode => $input->param('categorycode'), 
260
      itemtype     => $input->param('itemtype'),
261
  });
262
263
  Delete an issuing rule from Koha database.
264
  An alias for DeleteInTable, see C4::SQLHelper for more help.
265
266
=cut
267
268
sub DelIssuingRule { DeleteInTable('issuingrules',shift); }
269
270
1;
271
272
=head1 AUTHOR
273
274
Koha Developement team <info@koha.org>
275
276
Jean-André Santoni <jeanandre.santoni@biblibre.com>
277
278
=cut
(-)a/C4/Members.pm (+2 lines)
Lines 1041-1046 sub GetPendingIssues { Link Here
1041
        $bquery .= " OR" if ($i < (scalar(@borrowernumbers) - 1));
1041
        $bquery .= " OR" if ($i < (scalar(@borrowernumbers) - 1));
1042
    }
1042
    }
1043
1043
1044
    $bquery="1" unless $bquery; # if nothing, set to 1 (true) to avoid a SQL error
1045
    
1044
    # must avoid biblioitems.* to prevent large marc and marcxml fields from killing performance
1046
    # must avoid biblioitems.* to prevent large marc and marcxml fields from killing performance
1045
    # FIXME: namespace collision: each table has "timestamp" fields.  Which one is "timestamp" ?
1047
    # FIXME: namespace collision: each table has "timestamp" fields.  Which one is "timestamp" ?
1046
    # FIXME: circ/ciculation.pl tries to sort by timestamp!
1048
    # FIXME: circ/ciculation.pl tries to sort by timestamp!
(-)a/C4/Overdues.pm (-58 / +21 lines)
Lines 24-29 use strict; Link Here
24
use Date::Calc qw/Today Date_to_Days/;
24
use Date::Calc qw/Today Date_to_Days/;
25
use Date::Manip qw/UnixDate/;
25
use Date::Manip qw/UnixDate/;
26
use C4::Circulation;
26
use C4::Circulation;
27
use C4::IssuingRules;
27
use C4::Context;
28
use C4::Context;
28
use C4::Accounts;
29
use C4::Accounts;
29
use C4::Log; # logaction
30
use C4::Log; # logaction
Lines 72-80 BEGIN { Link Here
72
	push @EXPORT, qw(
73
	push @EXPORT, qw(
73
        &GetIssuesIteminfo
74
        &GetIssuesIteminfo
74
	);
75
	);
75
    #
76
	# &GetIssuingRules - delete.
77
	# use C4::Circulation::GetIssuingRule instead.
78
	
76
	
79
	# subs to move to Members.pm
77
	# subs to move to Members.pm
80
	push @EXPORT, qw(
78
	push @EXPORT, qw(
Lines 125-131 sub Getoverdues { Link Here
125
   SELECT issues.*, items.itype as itemtype, items.homebranch, items.barcode
123
   SELECT issues.*, items.itype as itemtype, items.homebranch, items.barcode
126
     FROM issues 
124
     FROM issues 
127
LEFT JOIN items       USING (itemnumber)
125
LEFT JOIN items       USING (itemnumber)
128
    WHERE date_due < CURDATE() 
126
    WHERE DATE(date_due) < CURDATE()
129
";
127
";
130
    } else {
128
    } else {
131
        $statement = "
129
        $statement = "
Lines 133-139 LEFT JOIN items USING (itemnumber) Link Here
133
     FROM issues 
131
     FROM issues 
134
LEFT JOIN items       USING (itemnumber)
132
LEFT JOIN items       USING (itemnumber)
135
LEFT JOIN biblioitems USING (biblioitemnumber)
133
LEFT JOIN biblioitems USING (biblioitemnumber)
136
    WHERE date_due < CURDATE() 
134
    WHERE DATE(date_due) < CURDATE()
137
";
135
";
138
    }
136
    }
139
137
Lines 171-177 sub checkoverdues { Link Here
171
         LEFT JOIN biblio      ON items.biblionumber     = biblio.biblionumber
169
         LEFT JOIN biblio      ON items.biblionumber     = biblio.biblionumber
172
         LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
170
         LEFT JOIN biblioitems ON items.biblioitemnumber = biblioitems.biblioitemnumber
173
            WHERE issues.borrowernumber  = ?
171
            WHERE issues.borrowernumber  = ?
174
            AND   issues.date_due < CURDATE()"
172
            AND   DATE(issues.date_due) < CURDATE()"
175
    );
173
    );
176
    # FIXME: SELECT * across 4 tables?  do we really need the marc AND marcxml blobs??
174
    # FIXME: SELECT * across 4 tables?  do we really need the marc AND marcxml blobs??
177
    $sth->execute($borrowernumber);
175
    $sth->execute($borrowernumber);
Lines 246-252 sub CalcFine { Link Here
246
	my $daystocharge;
244
	my $daystocharge;
247
	# get issuingrules (fines part will be used)
245
	# get issuingrules (fines part will be used)
248
    $debug and warn sprintf("CalcFine calling GetIssuingRule(%s, %s, %s)", $bortype, $item->{'itemtype'}, $branchcode);
246
    $debug and warn sprintf("CalcFine calling GetIssuingRule(%s, %s, %s)", $bortype, $item->{'itemtype'}, $branchcode);
249
    my $data = C4::Circulation::GetIssuingRule($bortype, $item->{'itemtype'}, $branchcode);
247
    my $data = GetIssuingRule($bortype, $item->{'itemtype'}, $branchcode);
250
	if($difference) {
248
	if($difference) {
251
		# if $difference is supplied, the difference has already been calculated, but we still need to adjust for the calendar.
249
		# if $difference is supplied, the difference has already been calculated, but we still need to adjust for the calendar.
252
    	# use copy-pasted functions from calendar module.  (deprecated -- these functions will be removed from C4::Overdues ).
250
    	# use copy-pasted functions from calendar module.  (deprecated -- these functions will be removed from C4::Overdues ).
Lines 270-276 sub CalcFine { Link Here
270
    } else {
268
    } else {
271
        # a zero (or null)  chargeperiod means no charge.
269
        # a zero (or null)  chargeperiod means no charge.
272
    }
270
    }
273
	$amount = C4::Context->preference('maxFine') if(C4::Context->preference('maxFine') && ( $amount > C4::Context->preference('maxFine')));
271
    $amount = C4::Context->preference('MaxFine') if ( C4::Context->preference('MaxFine') && ( $amount > C4::Context->preference('MaxFine') ) );
274
	$debug and warn sprintf("CalcFine returning (%s, %s, %s, %s)", $amount, $data->{'chargename'}, $days_minus_grace, $daystocharge);
272
	$debug and warn sprintf("CalcFine returning (%s, %s, %s, %s)", $amount, $data->{'chargename'}, $days_minus_grace, $daystocharge);
275
    return ($amount, $data->{'chargename'}, $days_minus_grace, $daystocharge);
273
    return ($amount, $data->{'chargename'}, $days_minus_grace, $daystocharge);
276
    # FIXME: chargename is NEVER populated anywhere.
274
    # FIXME: chargename is NEVER populated anywhere.
Lines 586-592 Returns the replacement cost of the item with the given item number. Link Here
586
584
587
=cut
585
=cut
588
586
589
#'
587
590
sub ReplacementCost {
588
sub ReplacementCost {
591
    my ($itemnum) = @_;
589
    my ($itemnum) = @_;
592
    my $dbh       = C4::Context->dbh;
590
    my $dbh       = C4::Context->dbh;
Lines 605-664 sub ReplacementCost { Link Here
605
603
606
return the total of fine
604
return the total of fine
607
605
608
C<$itemnum> is item number
609
610
C<$borrowernumber> is the borrowernumber
606
C<$borrowernumber> is the borrowernumber
611
607
612
=cut 
608
=cut
613
614
609
615
sub GetFine {
610
sub GetFine {
616
    my ( $itemnum, $borrowernumber ) = @_;
611
    my ( $borrowernumber ) = @_;
617
    my $dbh   = C4::Context->dbh();
612
    my $dbh   = C4::Context->dbh();
618
    my $query = "SELECT sum(amountoutstanding) FROM accountlines
613
    my $query = "SELECT sum(amountoutstanding) FROM accountlines
619
    where accounttype like 'F%'  
614
    where accounttype like 'F%'  
620
  AND amountoutstanding > 0 AND itemnumber = ? AND borrowernumber=?";
615
  AND amountoutstanding > 0 AND borrowernumber=?";
621
    my $sth = $dbh->prepare($query);
616
    my $sth = $dbh->prepare($query);
622
    $sth->execute( $itemnum, $borrowernumber );
617
    $sth->execute( $borrowernumber );
623
    my $data = $sth->fetchrow_hashref();
618
    my $data = $sth->fetchrow_hashref();
624
    return ( $data->{'sum(amountoutstanding)'} );
619
    return ( $data->{'sum(amountoutstanding)'} );
625
}
620
}
626
621
627
628
=head2 GetIssuingRules
629
630
FIXME - This sub should be deprecated and removed.
631
It ignores branch and defaults.
632
633
    $data = &GetIssuingRules($itemtype,$categorycode);
634
635
Looks up for all issuingrules an item info 
636
637
C<$itemnumber> is a reference-to-hash whose keys are all of the fields
638
from the borrowers and categories tables of the Koha database. Thus,
639
640
C<$categorycode> contains  information about borrowers category 
641
642
C<$data> contains all information about both the borrower and
643
category he or she belongs to.
644
=cut 
645
646
sub GetIssuingRules {
647
	warn "GetIssuingRules is deprecated: use GetIssuingRule from C4::Circulation instead.";
648
   my ($itemtype,$categorycode)=@_;
649
   my $dbh   = C4::Context->dbh();    
650
   my $query=qq|SELECT *
651
        FROM issuingrules
652
        WHERE issuingrules.itemtype=?
653
            AND issuingrules.categorycode=?
654
        |;
655
    my $sth = $dbh->prepare($query);
656
    #  print $query;
657
    $sth->execute($itemtype,$categorycode);
658
    return $sth->fetchrow_hashref;
659
}
660
661
662
sub ReplacementCost2 {
622
sub ReplacementCost2 {
663
    my ( $itemnum, $borrowernumber ) = @_;
623
    my ( $itemnum, $borrowernumber ) = @_;
664
    my $dbh   = C4::Context->dbh();
624
    my $dbh   = C4::Context->dbh();
Lines 1034-1040 sub GetOverduerules { Link Here
1034
994
1035
Check if the borrowers is already debarred
995
Check if the borrowers is already debarred
1036
996
1037
C<$debarredstatus> return 0 for not debarred and return 1 for debarred
997
C<$debarredstatus> return undef for not debarred and return end of debar date for debarred
1038
998
1039
C<$borrowernumber> contains the borrower number
999
C<$borrowernumber> contains the borrower number
1040
1000
Lines 1048-1079 sub CheckBorrowerDebarred { Link Here
1048
        SELECT debarred
1008
        SELECT debarred
1049
        FROM borrowers
1009
        FROM borrowers
1050
        WHERE borrowernumber=?
1010
        WHERE borrowernumber=?
1011
        AND debarred > NOW()
1051
    |;
1012
    |;
1052
    my $sth = $dbh->prepare($query);
1013
    my $sth = $dbh->prepare($query);
1053
    $sth->execute($borrowernumber);
1014
    $sth->execute($borrowernumber);
1054
    my ($debarredstatus) = $sth->fetchrow;
1015
    my $debarredstatus= $sth->fetchrow;
1055
    return ( $debarredstatus eq '1' ? 1 : 0 );
1016
    return $debarredstatus;
1017
    
1056
}
1018
}
1057
1019
1058
=head2 UpdateBorrowerDebarred
1020
=head2 UpdateBorrowerDebarred
1059
1021
1060
    ($borrowerstatut) = &UpdateBorrowerDebarred($borrowernumber);
1022
   ($borrowerstatut) = &UpdateBorrowerDebarred($borrowernumber, $todate);
1061
1023
1062
update status of borrowers in borrowers table (field debarred)
1024
update status of borrowers in borrowers table (field debarred)
1063
1025
1064
C<$borrowernumber> borrower number
1026
C<$borrowernumber> borrower number
1027
C<$todate> end of bare
1065
1028
1066
=cut
1029
=cut
1067
1030
1068
sub UpdateBorrowerDebarred{
1031
sub UpdateBorrowerDebarred{
1069
    my($borrowernumber) = @_;
1032
    my($borrowernumber, $todate) = @_;
1070
    my $dbh = C4::Context->dbh;
1033
    my $dbh = C4::Context->dbh;
1071
        my $query=qq|UPDATE borrowers
1034
        my $query=qq|UPDATE borrowers
1072
             SET debarred='1'
1035
             SET debarred=?
1073
                     WHERE borrowernumber=?
1036
                     WHERE borrowernumber=?
1074
            |;
1037
            |;
1075
    my $sth=$dbh->prepare($query);
1038
    my $sth=$dbh->prepare($query);
1076
        $sth->execute($borrowernumber);
1039
        $sth->execute($todate, $borrowernumber);
1077
        $sth->finish;
1040
        $sth->finish;
1078
        return 1;
1041
        return 1;
1079
}
1042
}
(-)a/C4/Reserves.pm (-187 / +445 lines)
Lines 22-27 package C4::Reserves; Link Here
22
22
23
use strict;
23
use strict;
24
#use warnings; FIXME - Bug 2505
24
#use warnings; FIXME - Bug 2505
25
use Date::Calc qw( Add_Delta_Days Time_to_Date Today);
25
use C4::Context;
26
use C4::Context;
26
use C4::Biblio;
27
use C4::Biblio;
27
use C4::Members;
28
use C4::Members;
Lines 32-41 use C4::Accounts; Link Here
32
33
33
# for _koha_notify_reserve
34
# for _koha_notify_reserve
34
use C4::Members::Messaging;
35
use C4::Members::Messaging;
35
use C4::Members qw();
36
use C4::Members ;
36
use C4::Letters;
37
use C4::Letters;
37
use C4::Branch qw( GetBranchDetail );
38
use C4::Branch qw( GetBranchDetail );
38
use C4::Dates qw( format_date_in_iso );
39
use C4::Dates qw( format_date_in_iso );
40
use C4::IssuingRules;
39
use List::MoreUtils qw( firstidx );
41
use List::MoreUtils qw( firstidx );
40
42
41
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
43
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
Lines 91-101 BEGIN { Link Here
91
    @EXPORT = qw(
93
    @EXPORT = qw(
92
        &AddReserve
94
        &AddReserve
93
  
95
  
96
        &GetMaxPickupDelay
97
        &GetMaxPickupDate
94
        &GetReservesFromItemnumber
98
        &GetReservesFromItemnumber
95
        &GetReservesFromBiblionumber
99
        &GetReservesFromBiblionumber
96
        &GetReservesFromBorrowernumber
100
        &GetReservesFromBorrowernumber
97
        &GetReservesForBranch
101
        &GetReservesForBranch
98
        &GetReservesToBranch
102
        &GetReservesToBranch
103
        &GetReservesControlBranch
99
        &GetReserveCount
104
        &GetReserveCount
100
        &GetReserveFee
105
        &GetReserveFee
101
		&GetReserveInfo
106
		&GetReserveInfo
Lines 113-125 BEGIN { Link Here
113
        &CheckReserves
118
        &CheckReserves
114
        &CanBookBeReserved
119
        &CanBookBeReserved
115
	&CanItemBeReserved
120
	&CanItemBeReserved
116
        &CancelReserve
121
      &CanHoldOnShelf
117
        &CancelExpiredReserves
122
      &CancelReserve
123
      &CancelExpiredReserves
118
124
119
        &IsAvailableForItemLevelRequest
125
      &IsAvailableForItemLevelRequest
120
        
126
121
        &AlterPriority
127
      &AlterPriority
122
        &ToggleLowestPriority
128
      &ToggleLowestPriority
129
      &CanHoldMultipleItems
130
      &BorrowerHasReserve
123
    );
131
    );
124
}    
132
}    
125
133
Lines 142-152 sub AddReserve { Link Here
142
    my $const   = lc substr( $constraint, 0, 1 );
150
    my $const   = lc substr( $constraint, 0, 1 );
143
    $resdate = format_date_in_iso( $resdate ) if ( $resdate );
151
    $resdate = format_date_in_iso( $resdate ) if ( $resdate );
144
    $resdate = C4::Dates->today( 'iso' ) unless ( $resdate );
152
    $resdate = C4::Dates->today( 'iso' ) unless ( $resdate );
153
    my $item = C4::Items::GetItem($checkitem);
154
    my @maxPickupDate = GetMaxPickupDate($resdate, $borrowernumber, $item);
155
    my $maxpickupdate = sprintf( "%d-%02d-%02d", @maxPickupDate );
145
    if ($expdate) {
156
    if ($expdate) {
146
        $expdate = format_date_in_iso( $expdate );
157
        $expdate = format_date_in_iso( $expdate );
158
        my @expdate = split("-", $expdate);
159
        $expdate = $maxpickupdate if Delta_Days(@expdate[ 0 .. 2 ], @maxPickupDate[ 0 .. 2 ]) < 0;
147
    } else {
160
    } else {
148
        undef $expdate; # make reserves.expirationdate default to null rather than '0000-00-00'
161
        $expdate = $maxpickupdate;   
149
    }
162
    }
163
    undef $expdate if $resdate eq $maxpickupdate; # make reserves.expirationdate default to null rather than '0000-00-00'
150
    if ( C4::Context->preference( 'AllowHoldDateInFuture' ) ) {
164
    if ( C4::Context->preference( 'AllowHoldDateInFuture' ) ) {
151
	# Make room in reserves for this before those of a later reserve date
165
	# Make room in reserves for this before those of a later reserve date
152
	$priority = _ShiftPriorityByDateAndPriority( $biblionumber, $resdate, $priority );
166
	$priority = _ShiftPriorityByDateAndPriority( $biblionumber, $resdate, $priority );
Lines 250-273 sub GetReservesFromBiblionumber { Link Here
250
264
251
    # Find the desired items in the reserves
265
    # Find the desired items in the reserves
252
    my $query = "
266
    my $query = "
253
        SELECT  branchcode,
267
        SELECT  reserves.reservenumber,
254
                timestamp AS rtimestamp,
268
                reserves.branchcode,
255
                priority,
269
                reserves.timestamp AS rtimestamp,
256
                biblionumber,
270
                reserves.priority,
257
                borrowernumber,
271
                reserves.biblionumber,
258
                reservedate,
272
                reserves.borrowernumber,
259
                constrainttype,
273
                reserves.reservedate,
260
                found,
274
                reserves.constrainttype,
261
                itemnumber,
275
                reserves.found,
262
                reservenotes,
276
                reserves.itemnumber,
263
                expirationdate,
277
                reserves.reservenotes,
264
                lowestPriority
278
                reserves.expirationdate,
279
                reserves.lowestPriority,
280
                biblioitems.itemtype
265
        FROM     reserves
281
        FROM     reserves
266
        WHERE biblionumber = ? ";
282
        LEFT JOIN biblioitems ON biblioitems.biblionumber = reserves.biblionumber
283
        WHERE reserves.biblionumber = ? ";
267
    unless ( $all_dates ) {
284
    unless ( $all_dates ) {
268
        $query .= "AND reservedate <= CURRENT_DATE()";
285
        $query .= "AND reservedate <= CURRENT_DATE()";
269
    }
286
    }
270
    $query .= "ORDER BY priority";
287
    $query .= "ORDER BY reserves.priority";
271
    my $sth = $dbh->prepare($query);
288
    my $sth = $dbh->prepare($query);
272
    $sth->execute($biblionumber);
289
    $sth->execute($biblionumber);
273
    my @results;
290
    my @results;
Lines 373-387 sub GetReservesFromBorrowernumber { Link Here
373
    return @$data;
390
    return @$data;
374
}
391
}
375
#-------------------------------------------------------------------------------------
392
#-------------------------------------------------------------------------------------
393
sub BorrowerHasReserve {
394
    my ( $borrowernumber, $biblionumber, $itemnumber ) = @_;
395
    my $dbh   = C4::Context->dbh;
396
    my $sth;
397
    
398
    if ( $biblionumber ) {
399
      $sth = $dbh->prepare("
400
            SELECT COUNT(*) AS hasReserve
401
            FROM   reserves
402
            WHERE  borrowernumber = ?
403
            AND    biblionumber = ?
404
            ORDER BY reservedate
405
        ");
406
      $sth->execute( $borrowernumber, $biblionumber );
407
    } elsif ( $itemnumber ) {
408
      $sth = $dbh->prepare("
409
            SELECT COUNT(*) AS hasReserve
410
            FROM   reserves
411
            WHERE  borrowernumber = ?
412
            AND    itemnumber = ?
413
            ORDER BY reservedate
414
        ");
415
      $sth->execute( $borrowernumber, $itemnumber );
416
    } else {
417
      return -1;
418
    }
419
420
    my $data = $sth->fetchrow_hashref();
421
    return $data->{'hasReserve'};
422
}
423
376
=head2 CanBookBeReserved
424
=head2 CanBookBeReserved
377
425
378
  $error = &CanBookBeReserved($borrowernumber, $biblionumber)
426
$error = &CanBookBeReserved($borrowernumber, $biblionumber)
379
427
380
=cut
428
=cut
381
429
382
sub CanBookBeReserved{
430
sub CanBookBeReserved{
383
    my ($borrowernumber, $biblionumber) = @_;
431
    my ($borrowernumber, $biblionumber) = @_;
384
385
    my @items = GetItemsInfo($biblionumber);
432
    my @items = GetItemsInfo($biblionumber);
386
    foreach my $item (@items){
433
    foreach my $item (@items){
387
        return 1 if CanItemBeReserved($borrowernumber, $item->{itemnumber});
434
        return 1 if CanItemBeReserved($borrowernumber, $item->{itemnumber});
Lines 399-405 This function return 1 if an item can be issued by this borrower. Link Here
399
446
400
sub CanItemBeReserved{
447
sub CanItemBeReserved{
401
    my ($borrowernumber, $itemnumber) = @_;
448
    my ($borrowernumber, $itemnumber) = @_;
402
    
403
    my $dbh             = C4::Context->dbh;
449
    my $dbh             = C4::Context->dbh;
404
    my $allowedreserves = 0;
450
    my $allowedreserves = 0;
405
            
451
            
Lines 407-413 sub CanItemBeReserved{ Link Here
407
    my $itype         = C4::Context->preference('item-level_itypes') ? "itype" : "itemtype";
453
    my $itype         = C4::Context->preference('item-level_itypes') ? "itype" : "itemtype";
408
454
409
    # we retrieve borrowers and items informations #
455
    # we retrieve borrowers and items informations #
410
    my $item     = GetItem($itemnumber);
456
    my $item     = C4::Items::GetItem($itemnumber);
411
    my $borrower = C4::Members::GetMember('borrowernumber'=>$borrowernumber);     
457
    my $borrower = C4::Members::GetMember('borrowernumber'=>$borrowernumber);     
412
    
458
    
413
    # we retrieve user rights on this itemtype and branchcode
459
    # we retrieve user rights on this itemtype and branchcode
Lines 438-459 sub CanItemBeReserved{ Link Here
438
    my $branchfield  = "reserves.branchcode";
484
    my $branchfield  = "reserves.branchcode";
439
    
485
    
440
    if( $controlbranch eq "ItemHomeLibrary" ){
486
    if( $controlbranch eq "ItemHomeLibrary" ){
441
        $branchfield = "items.homebranch";
487
        my $field=C4::Context->preference("HomeOrHoldingBranch")||"homebranch";
442
        $branchcode = $item->{homebranch};
488
        $branchfield = "items.$field";
489
        $branchcode = $item->{$field};
443
    }elsif( $controlbranch eq "PatronLibrary" ){
490
    }elsif( $controlbranch eq "PatronLibrary" ){
444
        $branchfield = "borrowers.branchcode";
491
        $branchfield = "borrowers.branchcode";
445
        $branchcode = $borrower->{branchcode};
492
        $branchcode = $borrower->{branchcode};
446
    }
493
    }
447
    
494
    
448
    # we retrieve rights 
495
    # we retrieve user rights on this itemtype and branchcode
449
    $sth->execute($categorycode, $itemtype, $branchcode);
496
    my $issuingrule = GetIssuingRule($borrower->{categorycode}, $item->{$itype}, $branchcode);
450
    if(my $rights = $sth->fetchrow_hashref()){
497
    return 0 if( defined $issuingrule->{reservesallowed} && not $issuingrule->{reservesallowed} );
451
        $itemtype        = $rights->{itemtype};
498
    
452
        $allowedreserves = $rights->{reservesallowed}; 
499
    # We retrieve the count of reserves allowed for this category code
500
    $issuingrule  = GetIssuingRule ($borrower->{categorycode}, "*", "*");
501
502
    if($issuingrule){
503
        $itemtype        = $issuingrule->{itemtype};
504
        $allowedreserves = $issuingrule->{reservesallowed}; 
453
    }else{
505
    }else{
454
        $itemtype = '*';
506
        $itemtype = '*';
455
    }
507
    }
456
    
508
    
509
    return 0 if ($issuingrule->{reservesallowed}==0 || 
510
                ($issuingrule->{holdrestricted}== 1 && !($branchcode eq $borrower->{branchcode}))
511
                );
457
    # we retrieve count
512
    # we retrieve count
458
    
513
    
459
    $querycount .= "AND $branchfield = ?";
514
    $querycount .= "AND $branchfield = ?";
Lines 479-484 sub CanItemBeReserved{ Link Here
479
        return 0;
534
        return 0;
480
    }
535
    }
481
}
536
}
537
538
=item GetMaxPickupDelay
539
540
$resallowed = &GetMaxPickupDelay($borrowernumber, $itemnumber)
541
542
this function return the number of allowed reserves.
543
544
=cut
545
546
sub GetMaxPickupDelay {
547
    my ($borrowernumber, $itemnumber) = @_;
548
    
549
    my $dbh             = C4::Context->dbh;
550
    my $allowedreserves = 0;
551
            
552
    my $itype         = C4::Context->preference('item-level_itypes') ? "itype" : "itemtype";
553
554
    # we retrieve borrowers and items informations #
555
    my $item     = C4::Items::GetItem($itemnumber);
556
    my $borrower = C4::Members::GetMember('borrowernumber'=>$borrowernumber);     
557
    my $controlbranch = GetReservesControlBranch($borrower,$item);
558
    
559
    # we retrieve user rights on this itemtype and branchcode
560
    my $sth = $dbh->prepare("SELECT holdspickupdelay 
561
                    FROM issuingrules 
562
                    WHERE categorycode=? 
563
                    AND itemtype=?
564
                    AND branchcode=?
565
                    AND holdspickupdelay IS NOT NULL"
566
                           );
567
    
568
    my $itemtype     = $item->{$itype};
569
    my $borrowertype = $borrower->{categorycode};
570
    my $branchcode   = $controlbranch;
571
    
572
    $sth->execute( $borrowertype, $itemtype, $branchcode );
573
    my $pickupdelay = $sth->fetchrow_hashref;
574
    return $pickupdelay->{holdspickupdelay}
575
      if defined($pickupdelay) && $pickupdelay->{holdspickupdelay} ne 'NULL';
576
577
    $sth->execute( $borrowertype, "*", $branchcode );
578
    $pickupdelay = $sth->fetchrow_hashref;
579
    return $pickupdelay->{holdspickupdelay}
580
      if defined($pickupdelay) && $pickupdelay->{holdspickupdelay} ne 'NULL';
581
582
    $sth->execute( "*", $itemtype, $branchcode );
583
    $pickupdelay = $sth->fetchrow_hashref;
584
    return $pickupdelay->{holdspickupdelay}
585
      if defined($pickupdelay) && $pickupdelay->{holdspickupdelay} ne 'NULL';
586
587
    $sth->execute( "*", "*", $branchcode );
588
    $pickupdelay = $sth->fetchrow_hashref;
589
    return $pickupdelay->{holdspickupdelay}
590
      if defined($pickupdelay) && $pickupdelay->{holdspickupdelay} ne 'NULL';
591
592
    $sth->execute( $borrowertype, $itemtype, "*" );
593
    $pickupdelay = $sth->fetchrow_hashref;
594
    return $pickupdelay->{holdspickupdelay}
595
      if defined($pickupdelay) && $pickupdelay->{holdspickupdelay} ne 'NULL';
596
597
    $sth->execute( $borrowertype, "*", "*" );
598
    $pickupdelay = $sth->fetchrow_hashref;
599
    return $pickupdelay->{holdspickupdelay}
600
      if defined($pickupdelay) && $pickupdelay->{holdspickupdelay} ne 'NULL';
601
602
    $sth->execute( "*", $itemtype, "*" );
603
    $pickupdelay = $sth->fetchrow_hashref;
604
    return $pickupdelay->{holdspickupdelay}
605
      if defined($pickupdelay) && $pickupdelay->{holdspickupdelay} ne 'NULL';
606
607
    $sth->execute( "*", "*", "*" );
608
    $pickupdelay = $sth->fetchrow_hashref;
609
    return $pickupdelay->{holdspickupdelay}
610
      if defined($pickupdelay) && $pickupdelay->{holdspickupdelay} ne 'NULL';
611
    
612
    # if nothing found, return no rights
613
    return 0;
614
}
615
616
=item GetMaxPickupDate
617
618
$maxpickupdate = &GetMaxPickupDate($date);
619
620
this function return the max pickup date.
621
(e.g. : the date after which the hold will be considered cancelled)
622
623
=cut
624
625
sub GetMaxPickupDate{
626
    my $inputdate=shift;
627
    my $borrowernumber=shift;
628
    my $item=shift;
629
    return unless $inputdate;
630
    my @date = split(/-/,$inputdate);
631
    my $delay = GetMaxPickupDelay($borrowernumber, $item->{'itemnumber'});
632
    ( @date ) =
633
      Add_Delta_Days( @date[0..2], $delay);
634
    return @date;
635
}
636
482
#--------------------------------------------------------------------------------
637
#--------------------------------------------------------------------------------
483
=head2 GetReserveCount
638
=head2 GetReserveCount
484
639
Lines 518-538 sub GetOtherReserves { Link Here
518
    my $nextreservinfo;
673
    my $nextreservinfo;
519
    my ( $restype, $checkreserves ) = CheckReserves($itemnumber);
674
    my ( $restype, $checkreserves ) = CheckReserves($itemnumber);
520
    if ($checkreserves) {
675
    if ($checkreserves) {
521
        my $iteminfo = GetItem($itemnumber);
676
        my $iteminfo = C4::Items::GetItem($itemnumber);
522
        if ( $iteminfo->{'holdingbranch'} ne $checkreserves->{'branchcode'} ) {
677
        if ( $iteminfo->{'holdingbranch'} ne $checkreserves->{'branchcode'} ) {
523
            $messages->{'transfert'} = $checkreserves->{'branchcode'};
678
            $messages->{'transfert'} = $checkreserves->{'branchcode'};
524
            #minus priorities of others reservs
679
            #minus priorities of others reservs
525
            ModReserveMinusPriority(
680
            ModReserveMinusPriority(
526
                $itemnumber,
681
                $itemnumber,
527
                $checkreserves->{'borrowernumber'},
682
                $checkreserves->{'borrowernumber'},
528
                $iteminfo->{'biblionumber'}
683
                $iteminfo->{'biblionumber'},
684
                $checkreserves->{'reservenumber'}
529
            );
685
            );
530
686
531
            #launch the subroutine dotransfer
687
            #launch the subroutine dotransfer
532
            C4::Items::ModItemTransfer(
688
            C4::Items::ModItemTransfer(
533
                $itemnumber,
689
                $itemnumber,
534
                $iteminfo->{'holdingbranch'},
690
                $iteminfo->{'holdingbranch'},
535
                $checkreserves->{'branchcode'}
691
                $checkreserves->{'branchcode'},
536
              ),
692
              ),
537
              ;
693
              ;
538
        }
694
        }
Lines 543-549 sub GetOtherReserves { Link Here
543
            ModReserveMinusPriority(
699
            ModReserveMinusPriority(
544
                $itemnumber,
700
                $itemnumber,
545
                $checkreserves->{'borrowernumber'},
701
                $checkreserves->{'borrowernumber'},
546
                $iteminfo->{'biblionumber'}
702
                $iteminfo->{'biblionumber'},
703
                $checkreserves->{'reservenumber'}                
547
            );
704
            );
548
            ModReserveStatus($itemnumber,'W');
705
            ModReserveStatus($itemnumber,'W');
549
        }
706
        }
Lines 657-662 sub GetReserveFee { Link Here
657
    return $fee;
814
    return $fee;
658
}
815
}
659
816
817
=head2 GetReservesControlBranch
818
819
$branchcode = &GetReservesControlBranch($borrower, $item)
820
821
Returns the branchcode to consider to check hold rules against
822
823
=cut
824
sub GetReservesControlBranch{
825
    my ($borrower, $item) = @_;
826
    my $controlbranch = C4::Context->preference('ReservesControlBranch');
827
    my $hbr           = C4::Context->preference('HomeOrHoldingBranch')||"homebranch";
828
    my $branchcode="*";
829
    if($controlbranch eq "ItemHomeLibrary"){
830
        $branchcode = $item->{$hbr};
831
    } elsif($controlbranch eq "PatronLibrary"){
832
        $branchcode = $borrower->{'branchcode'};
833
    }
834
    return $branchcode;
835
}
836
660
=head2 GetReservesToBranch
837
=head2 GetReservesToBranch
661
838
662
  @transreserv = GetReservesToBranch( $frombranch );
839
  @transreserv = GetReservesToBranch( $frombranch );
Lines 804-815 sub CheckReserves { Link Here
804
            } else {
981
            } else {
805
                # See if this item is more important than what we've got so far
982
                # See if this item is more important than what we've got so far
806
                if ( $res->{'priority'} && $res->{'priority'} < $priority ) {
983
                if ( $res->{'priority'} && $res->{'priority'} < $priority ) {
807
                    my $borrowerinfo=C4::Members::GetMemberDetails($res->{'borrowernumber'});
808
                    my $iteminfo=C4::Items::GetItem($itemnumber);
809
                    my $branch=C4::Circulation::_GetCircControlBranch($iteminfo,$borrowerinfo);
810
                    my $branchitemrule = C4::Circulation::GetBranchItemRule($branch,$iteminfo->{'itype'});
811
                    next if ($branchitemrule->{'holdallowed'} == 0);
812
                    next if (($branchitemrule->{'holdallowed'} == 1) && ($branch ne $borrowerinfo->{'branchcode'}));
813
                    $priority = $res->{'priority'};
984
                    $priority = $res->{'priority'};
814
                    $highest  = $res;
985
                    $highest  = $res;
815
                }
986
                }
Lines 846-868 sub CancelExpiredReserves { Link Here
846
    $sth->execute();
1017
    $sth->execute();
847
1018
848
    while ( my $res = $sth->fetchrow_hashref() ) {
1019
    while ( my $res = $sth->fetchrow_hashref() ) {
849
        CancelReserve( $res->{'biblionumber'}, '', $res->{'borrowernumber'} );
1020
        CancelReserve( $res->{'reservenumber'}, $res->{'biblionumber'} );
850
    }
1021
    }
851
  
1022
  
852
}
1023
}
853
1024
854
=head2 CancelReserve
1025
=head2 CancelReserve
855
1026
856
  &CancelReserve($biblionumber, $itemnumber, $borrowernumber);
1027
  &CancelReserve( $reservenumber, $biblionumber );
857
1028
858
Cancels a reserve.
1029
Cancels a reserve.
859
1030
860
Use either C<$biblionumber> or C<$itemnumber> to specify the item to
1031
C<$reservenumber> is the unique key for the reserve to be canceled.
861
cancel, but not both: if both are given, C<&CancelReserve> does
862
nothing.
863
864
C<$borrowernumber> is the borrower number of the patron on whose
865
behalf the book was reserved.
866
1032
867
If C<$biblionumber> was given, C<&CancelReserve> also adjusts the
1033
If C<$biblionumber> was given, C<&CancelReserve> also adjusts the
868
priorities of the other people who are waiting on the book.
1034
priorities of the other people who are waiting on the book.
Lines 870-878 priorities of the other people who are waiting on the book. Link Here
870
=cut
1036
=cut
871
1037
872
sub CancelReserve {
1038
sub CancelReserve {
873
    my ( $biblio, $item, $borr ) = @_;
1039
    my ( $reservenumber, $biblio ) = @_;
874
    my $dbh = C4::Context->dbh;
1040
    my $dbh = C4::Context->dbh;
875
        if ( $item and $borr ) {
1041
    
1042
    my $sth = $dbh->prepare('SELECT * FROM reserves WHERE reservenumber = ?');
1043
    $sth->execute( $reservenumber );
1044
    my $reserve = $sth->fetchrow_hashref();
1045
    
1046
    if ( $reserve->{'found'} eq 'W' ) {
876
        # removing a waiting reserve record....
1047
        # removing a waiting reserve record....
877
        # update the database...
1048
        # update the database...
878
        my $query = "
1049
        my $query = "
Lines 880-906 sub CancelReserve { Link Here
880
            SET    cancellationdate = now(),
1051
            SET    cancellationdate = now(),
881
                   found            = Null,
1052
                   found            = Null,
882
                   priority         = 0
1053
                   priority         = 0
883
            WHERE  itemnumber       = ?
1054
            WHERE  reservenumber   = ?
884
             AND   borrowernumber   = ?
885
        ";
1055
        ";
886
        my $sth = $dbh->prepare($query);
1056
        my $sth = $dbh->prepare($query);
887
        $sth->execute( $item, $borr );
1057
        $sth->execute( $reservenumber );
888
        $sth->finish;
1058
1059
        # get reserve information to place into old_reserves
889
        $query = "
1060
        $query = "
890
            INSERT INTO old_reserves
1061
            INSERT INTO old_reserves
891
            SELECT * FROM reserves
1062
            SELECT * FROM reserves
892
            WHERE  itemnumber       = ?
1063
            WHERE reservenumber     = ?
893
             AND   borrowernumber   = ?
894
        ";
1064
        ";
895
        $sth = $dbh->prepare($query);
1065
        $sth = $dbh->prepare($query);
896
        $sth->execute( $item, $borr );
1066
        $sth->execute( $reservenumber );
1067
        my $holditem = $sth->fetchrow_hashref;
1068
        my $insert_fields = '';
1069
        my $value_fields = '';
1070
        foreach my $column ('borrowernumber','reservedate','biblionumber','constrainttype','branchcode','notificationdate','reminderdate','cancellationdate','reservenotes','priority','found','itemnumber','waitingdate','expirationdate') {
1071
          if (defined($holditem->{$column})) {
1072
            if (length($insert_fields)) {
1073
              $insert_fields .= ",$column";
1074
              $value_fields .= ",\'$holditem->{$column}\'";
1075
            }
1076
            else {
1077
              $insert_fields .= "$column";
1078
              $value_fields .= "\'$holditem->{$column}\'";
1079
            }
1080
          }
1081
        }
1082
        $query = qq/
1083
            INSERT INTO old_reserves ($insert_fields)
1084
            VALUES ($value_fields)
1085
        /;
1086
        $sth = $dbh->prepare($query);
1087
        $sth->execute();
897
        $query = "
1088
        $query = "
898
            DELETE FROM reserves
1089
            DELETE FROM reserves
899
            WHERE  itemnumber       = ?
1090
            WHERE  reservenumber   = ?
900
             AND   borrowernumber   = ?
901
        ";
1091
        ";
902
        $sth = $dbh->prepare($query);
1092
        $sth = $dbh->prepare($query);
903
        $sth->execute( $item, $borr );
1093
        $sth->execute( $reservenumber );
904
    }
1094
    }
905
    else {
1095
    else {
906
        # removing a reserve record....
1096
        # removing a reserve record....
Lines 908-959 sub CancelReserve { Link Here
908
        my $priority;
1098
        my $priority;
909
        my $query = qq/
1099
        my $query = qq/
910
            SELECT priority FROM reserves
1100
            SELECT priority FROM reserves
911
            WHERE biblionumber   = ?
1101
            WHERE reservenumber = ?
912
              AND borrowernumber = ?
913
              AND cancellationdate IS NULL
1102
              AND cancellationdate IS NULL
914
              AND itemnumber IS NULL
1103
              AND itemnumber IS NULL
915
        /;
1104
        /;
916
        my $sth = $dbh->prepare($query);
1105
        my $sth = $dbh->prepare($query);
917
        $sth->execute( $biblio, $borr );
1106
        $sth->execute( $reservenumber );
918
        ($priority) = $sth->fetchrow_array;
1107
        ($priority) = $sth->fetchrow_array;
919
        $sth->finish;
1108
        $sth->finish;
920
        $query = qq/
1109
        $query = qq/
921
            UPDATE reserves
1110
            UPDATE reserves
922
            SET    cancellationdate = now(),
1111
            SET    cancellationdate = now(),
923
                   found            = Null,
1112
                   found            = Null,
924
                   priority         = 0
1113
                   priority         = 0,
925
            WHERE  biblionumber     = ?
1114
                   expirationdate   = NULL
926
              AND  borrowernumber   = ?
1115
            WHERE  reservenumber   = ?
927
        /;
1116
        /;
928
1117
929
        # update the database, removing the record...
1118
        # update the database, removing the record...
930
        $sth = $dbh->prepare($query);
1119
        $sth = $dbh->prepare($query);
931
        $sth->execute( $biblio, $borr );
1120
        $sth->execute( $reservenumber );
932
        $sth->finish;
933
1121
934
        $query = qq/
1122
        $query = qq/
935
            INSERT INTO old_reserves
1123
            INSERT INTO old_reserves
936
            SELECT * FROM reserves
1124
            SELECT * FROM reserves
937
            WHERE  biblionumber     = ?
1125
            WHERE reservenumber   = ?
938
              AND  borrowernumber   = ?
1126
        /;
1127
        $sth = $dbh->prepare($query);
1128
        $sth->execute( $reservenumber );
1129
        my $holditem = $sth->fetchrow_hashref;
1130
1131
        my $insert_fields = '';
1132
        my $value_fields = '';
1133
        foreach my $column ('borrowernumber','reservedate','biblionumber','constrainttype','branchcode','notificationdate','reminderdate','cancellationdate','reservenotes','priority','found','itemnumber','waitingdate','expirationdate') {
1134
          if (defined($holditem->{$column})) {
1135
            if (length($insert_fields)) {
1136
              $insert_fields .= ",$column";
1137
              $value_fields .= ",\'$holditem->{$column}\'";
1138
            }
1139
            else {
1140
              $insert_fields .= "$column";
1141
              $value_fields .= "\'$holditem->{$column}\'";
1142
            }
1143
          }
1144
        }
1145
        $query = qq/
1146
            INSERT INTO old_reserves ($insert_fields)
1147
            VALUES ($value_fields)
939
        /;
1148
        /;
940
        $sth = $dbh->prepare($query);
1149
        $sth = $dbh->prepare($query);
941
        $sth->execute( $biblio, $borr );
1150
        $sth->execute();
942
1151
943
        $query = qq/
1152
        $query = qq/
944
            DELETE FROM reserves
1153
            DELETE FROM reserves
945
            WHERE  biblionumber     = ?
1154
            WHERE  reservenumber   = ?
946
              AND  borrowernumber   = ?
947
        /;
1155
        /;
948
        $sth = $dbh->prepare($query);
1156
        $sth = $dbh->prepare($query);
949
        $sth->execute( $biblio, $borr );
1157
        $sth->execute( $reservenumber );
950
1158
951
        # now fix the priority on the others....
1159
        # now fix the priority on the others....
952
        _FixPriority( $biblio, $borr );
1160
        _FixPriority( '', '', $priority,'', $reservenumber );
953
    }
1161
    }
954
}
1162
}
955
1163
956
=head2 ModReserve
1164
=item ModReserve
1165
1166
=over 4
957
1167
958
  ModReserve($rank, $biblio, $borrower, $branch[, $itemnumber])
1168
  ModReserve($rank, $biblio, $borrower, $branch[, $itemnumber])
959
1169
Lines 986-1037 itemnumber and supplying itemnumber. Link Here
986
1196
987
sub ModReserve {
1197
sub ModReserve {
988
    #subroutine to update a reserve
1198
    #subroutine to update a reserve
989
    my ( $rank, $biblio, $borrower, $branch , $itemnumber) = @_;
1199
    my ( $rank, $biblio, $borrower, $branch , $itemnumber, $reservenumber) = @_;
990
     return if $rank eq "W";
1200
     return if $rank eq "W";
991
     return if $rank eq "n";
1201
     return if $rank eq "n";
992
    my $dbh = C4::Context->dbh;
1202
    my $dbh = C4::Context->dbh;
993
    if ( $rank eq "del" ) {
1203
    if ( $rank eq "del" ) {
994
        my $query = qq/
1204
        my $query = qq/
995
            UPDATE reserves
1205
            UPDATE reserves
996
            SET    cancellationdate=now()
1206
            SET    cancellationdate=now(),
997
            WHERE  biblionumber   = ?
1207
                   expirationdate = NULL
998
             AND   borrowernumber = ?
1208
            WHERE  reservenumber   = ?
999
        /;
1209
        /;
1000
        my $sth = $dbh->prepare($query);
1210
        my $sth = $dbh->prepare($query);
1001
        $sth->execute( $biblio, $borrower );
1211
        $sth->execute( $reservenumber );
1002
        $sth->finish;
1212
        $sth->finish;
1003
        $query = qq/
1213
        $query = qq/
1004
            INSERT INTO old_reserves
1214
            INSERT INTO old_reserves
1005
            SELECT *
1215
            SELECT * FROM reserves
1006
            FROM   reserves 
1216
            WHERE  reservenumber   = ?
1007
            WHERE  biblionumber   = ?
1008
             AND   borrowernumber = ?
1009
        /;
1217
        /;
1010
        $sth = $dbh->prepare($query);
1218
        $sth = $dbh->prepare($query);
1011
        $sth->execute( $biblio, $borrower );
1219
        $sth->execute( $reservenumber );
1012
        $query = qq/
1220
        $query = qq/
1013
            DELETE FROM reserves 
1221
            DELETE FROM reserves 
1014
            WHERE  biblionumber   = ?
1222
            WHERE  reservenumber   = ?
1015
             AND   borrowernumber = ?
1016
        /;
1223
        /;
1017
        $sth = $dbh->prepare($query);
1224
        $sth = $dbh->prepare($query);
1018
        $sth->execute( $biblio, $borrower );
1225
        $sth->execute( $reservenumber );
1019
        
1226
        
1020
    }
1227
    }
1021
    elsif ($rank =~ /^\d+/ and $rank > 0) {
1228
    elsif ($rank =~ /^\d+/ and $rank > 0) {
1022
        my $query = qq/
1229
        my $query = qq/
1023
        UPDATE reserves SET priority = ? ,branchcode = ?, itemnumber = ?, found = NULL, waitingdate = NULL
1230
        UPDATE reserves SET priority = ? ,branchcode = ?, itemnumber = ?, found = NULL, waitingdate = NULL
1024
            WHERE biblionumber   = ?
1231
            WHERE reservenumber = ?
1025
             AND borrowernumber = ?
1026
        /;
1232
        /;
1027
        my $sth = $dbh->prepare($query);
1233
        my $sth = $dbh->prepare($query);
1028
        $sth->execute( $rank, $branch,$itemnumber, $biblio, $borrower);
1234
        $sth->execute( $rank, $branch, $itemnumber, $reservenumber );
1029
        $sth->finish;
1235
        $sth->finish;
1030
        _FixPriority( $biblio, $borrower, $rank);
1236
        _FixPriority( $biblio, $borrower, $rank, '', $reservenumber);
1031
    }
1237
    }
1032
}
1238
}
1033
1239
1034
=head2 ModReserveFill
1240
=item ModReserveFill
1035
1241
1036
  &ModReserveFill($reserve);
1242
  &ModReserveFill($reserve);
1037
1243
Lines 1050-1065 sub ModReserveFill { Link Here
1050
    my $biblionumber = $res->{'biblionumber'};
1256
    my $biblionumber = $res->{'biblionumber'};
1051
    my $borrowernumber    = $res->{'borrowernumber'};
1257
    my $borrowernumber    = $res->{'borrowernumber'};
1052
    my $resdate = $res->{'reservedate'};
1258
    my $resdate = $res->{'reservedate'};
1259
    my $resnumber      = $res->{'reservenumber'};
1053
1260
1054
    # get the priority on this record....
1261
    # get the priority on this record....
1055
    my $priority;
1262
    my $priority;
1056
    my $query = "SELECT priority
1263
    my $query = "SELECT priority
1057
                 FROM   reserves
1264
                 FROM   reserves
1058
                 WHERE  biblionumber   = ?
1265
                 WHERE  borrowernumber   = ?
1059
                  AND   borrowernumber = ?
1266
                  AND   reservenumber  = ?
1060
                  AND   reservedate    = ?";
1267
                  AND   reservedate    = ?";
1061
    my $sth = $dbh->prepare($query);
1268
    my $sth = $dbh->prepare($query);
1062
    $sth->execute( $biblionumber, $borrowernumber, $resdate );
1269
    $sth->execute( $resnumber, $borrowernumber, $resdate );
1063
    ($priority) = $sth->fetchrow_array;
1270
    ($priority) = $sth->fetchrow_array;
1064
    $sth->finish;
1271
    $sth->finish;
1065
1272
Lines 1067-1101 sub ModReserveFill { Link Here
1067
    $query = "UPDATE reserves
1274
    $query = "UPDATE reserves
1068
                  SET    found            = 'F',
1275
                  SET    found            = 'F',
1069
                         priority         = 0
1276
                         priority         = 0
1070
                 WHERE  biblionumber     = ?
1277
                 WHERE  reservenumber     = ?
1071
                    AND reservedate      = ?
1278
                    AND reservedate      = ?
1072
                    AND borrowernumber   = ?
1279
                    AND borrowernumber   = ?
1073
                ";
1280
                ";
1074
    $sth = $dbh->prepare($query);
1281
    $sth = $dbh->prepare($query);
1075
    $sth->execute( $biblionumber, $resdate, $borrowernumber );
1282
    $sth->execute( $resnumber, $resdate, $borrowernumber );
1076
    $sth->finish;
1283
    $sth->finish;
1077
1284
1078
    # move to old_reserves
1285
    # move to old_reserves
1079
    $query = "INSERT INTO old_reserves
1286
    $query = "INSERT INTO old_reserves
1080
                 SELECT * FROM reserves
1287
                 SELECT * FROM reserves
1081
                 WHERE  biblionumber     = ?
1288
                 WHERE  reservenumber    = ?
1082
                    AND reservedate      = ?
1289
                    AND reservedate      = ?
1083
                    AND borrowernumber   = ?
1290
                    AND borrowernumber   = ?
1084
                ";
1291
                ";
1085
    $sth = $dbh->prepare($query);
1292
    $sth = $dbh->prepare($query);
1086
    $sth->execute( $biblionumber, $resdate, $borrowernumber );
1293
    $sth->execute( $resnumber, $resdate, $borrowernumber );
1087
    $query = "DELETE FROM reserves
1294
    $query = "DELETE FROM reserves
1088
                 WHERE  biblionumber     = ?
1295
                 WHERE  reservenumber    = ?
1089
                    AND reservedate      = ?
1296
                    AND reservedate      = ?
1090
                    AND borrowernumber   = ?
1297
                    AND borrowernumber   = ?
1091
                ";
1298
                ";
1092
    $sth = $dbh->prepare($query);
1299
    $sth = $dbh->prepare($query);
1093
    $sth->execute( $biblionumber, $resdate, $borrowernumber );
1300
    $sth->execute( $resnumber, $resdate, $borrowernumber );
1094
    
1301
    
1095
    # now fix the priority on the others (if the priority wasn't
1302
    # now fix the priority on the others (if the priority wasn't
1096
    # already sorted!)....
1303
    # already sorted!)....
1097
    unless ( $priority == 0 ) {
1304
    unless ( $priority == 0 ) {
1098
        _FixPriority( $biblionumber, $borrowernumber );
1305
        _FixPriority( $priority, $biblionumber,undef,undef, $res->{reservenumber} );
1099
    }
1306
    }
1100
}
1307
}
1101
1308
Lines 1112-1118 $newstatus is the new status. Link Here
1112
=cut
1319
=cut
1113
1320
1114
sub ModReserveStatus {
1321
sub ModReserveStatus {
1115
1116
    #first : check if we have a reservation for this item .
1322
    #first : check if we have a reservation for this item .
1117
    my ($itemnumber, $newstatus) = @_;
1323
    my ($itemnumber, $newstatus) = @_;
1118
    my $dbh          = C4::Context->dbh;
1324
    my $dbh          = C4::Context->dbh;
Lines 1146-1154 take care of the waiting status Link Here
1146
=cut
1352
=cut
1147
1353
1148
sub ModReserveAffect {
1354
sub ModReserveAffect {
1149
    my ( $itemnumber, $borrowernumber,$transferToDo ) = @_;
1355
    my ( $itemnumber, $borrowernumber,$transferToDo, $reservenumber ) = @_;
1150
    my $dbh = C4::Context->dbh;
1356
    my $dbh = C4::Context->dbh;
1151
1152
    # we want to attach $itemnumber to $borrowernumber, find the biblionumber
1357
    # we want to attach $itemnumber to $borrowernumber, find the biblionumber
1153
    # attached to $itemnumber
1358
    # attached to $itemnumber
1154
    my $sth = $dbh->prepare("SELECT biblionumber FROM items WHERE itemnumber=?");
1359
    my $sth = $dbh->prepare("SELECT biblionumber FROM items WHERE itemnumber=?");
Lines 1166-1192 sub ModReserveAffect { Link Here
1166
    $query = "
1371
    $query = "
1167
        UPDATE reserves
1372
        UPDATE reserves
1168
        SET    priority = 0,
1373
        SET    priority = 0,
1169
               itemnumber = ?,
1374
               itemnumber = ?
1170
               found = 'T'
1375
        WHERE reservenumber = ?
1171
        WHERE borrowernumber = ?
1172
          AND biblionumber = ?
1173
    ";
1376
    ";
1174
    }
1377
    }
1175
    else {
1378
    else {
1176
    # affect the reserve to Waiting as well.
1379
    # affect the reserve to Waiting as well.
1177
    $query = "
1380
      my $holdperiod = C4::Context->preference('ReservesMaxPickUpDelay');
1178
        UPDATE reserves
1381
      if ((!defined($holdperiod)) || ($holdperiod eq '') || ($holdperiod == 0)) {
1179
        SET     priority = 0,
1382
        $query = "
1180
                found = 'W',
1383
            UPDATE reserves
1181
                waitingdate=now(),
1384
            SET     priority = 0,
1182
                itemnumber = ?
1385
                    found = 'W',
1183
        WHERE borrowernumber = ?
1386
                    waitingdate=now(),
1184
          AND biblionumber = ?
1387
                    itemnumber = ?
1185
    ";
1388
        WHERE reservenumber = ?
1389
        ";
1390
      }
1391
      else {
1392
        my ($holdexpyear,$holdexpmonth,$holdexpday) = Today();
1393
        my $holdstartdate = C4::Dates->new(sprintf "%02d/%02d/%04d",$holdexpmonth,$holdexpday,$holdexpyear, 'us');
1394
1395
        # Grab branch for calendar purposes
1396
        $sth = $dbh->prepare("SELECT branchcode FROM reserves WHERE borrowernumber=? AND biblionumber=?");
1397
        $sth->execute($borrowernumber,$biblionumber);
1398
        my ($branch) = $sth->fetchrow;
1399
1400
        # Check to see if hold expiration date falls on a closed library day.
1401
        # Note the useDaysMode syspref will need to be set to Calendar for
1402
        # the code to advance to the next non-closed day.
1403
        my $calendar = C4::Calendar->new( branchcode => $branch);
1404
        my $holdexpdate  = $calendar->addDate($holdstartdate, $holdperiod);
1405
        my $sqlexpdate = $holdexpdate->output('iso');
1406
        $query = "
1407
            UPDATE reserves
1408
            SET     priority = 0,
1409
                    found = 'W',
1410
                    waitingdate=now(),
1411
                    itemnumber = ?,
1412
                    expirationdate='$sqlexpdate'
1413
        WHERE reservenumber = ?
1414
        ";
1415
      }
1186
    }
1416
    }
1187
    $sth = $dbh->prepare($query);
1417
    $sth = $dbh->prepare($query);
1188
    $sth->execute( $itemnumber, $borrowernumber,$biblionumber);
1418
    $sth->execute( $itemnumber, $reservenumber );
1189
    _koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber ) if ( !$transferToDo && !$already_on_shelf );
1419
    _koha_notify_reserve( $itemnumber, $borrowernumber, $biblionumber, $reservenumber ) if ( !$transferToDo && !$already_on_shelf );
1190
1420
1191
    if ( C4::Context->preference("ReturnToShelvingCart") ) {
1421
    if ( C4::Context->preference("ReturnToShelvingCart") ) {
1192
      CartToShelf( $itemnumber );
1422
      CartToShelf( $itemnumber );
Lines 1226-1248 Reduce the values of queuded list Link Here
1226
=cut
1456
=cut
1227
1457
1228
sub ModReserveMinusPriority {
1458
sub ModReserveMinusPriority {
1229
    my ( $itemnumber, $borrowernumber, $biblionumber ) = @_;
1459
    my ( $itemnumber, $borrowernumber, $biblionumber, $reservenumber ) = @_;
1230
1231
    #first step update the value of the first person on reserv
1460
    #first step update the value of the first person on reserv
1232
    my $dbh   = C4::Context->dbh;
1461
    my $dbh   = C4::Context->dbh;
1233
    my $query = "
1462
    my $query = "
1234
        UPDATE reserves
1463
        UPDATE reserves
1235
        SET    priority = 0 , itemnumber = ? 
1464
        SET    priority = 0 , itemnumber = ? 
1236
        WHERE  borrowernumber=?
1465
        WHERE  reservenumber=?
1237
          AND  biblionumber=?
1238
    ";
1466
    ";
1239
    my $sth_upd = $dbh->prepare($query);
1467
    my $sth_upd = $dbh->prepare($query);
1240
    $sth_upd->execute( $itemnumber, $borrowernumber, $biblionumber );
1468
    $sth_upd->execute( $itemnumber, $reservenumber );
1241
    # second step update all others reservs
1469
    # second step update all others reservs
1242
    _FixPriority($biblionumber, $borrowernumber, '0');
1470
    _FixPriority($biblionumber, $borrowernumber, '0', '', $reservenumber);
1243
}
1471
}
1244
1472
1245
=head2 GetReserveInfo
1473
=item GetReserveInfo
1246
1474
1247
  &GetReserveInfo($borrowernumber,$biblionumber);
1475
  &GetReserveInfo($borrowernumber,$biblionumber);
1248
1476
Lines 1327-1333 and canreservefromotherbranches. Link Here
1327
sub IsAvailableForItemLevelRequest {
1555
sub IsAvailableForItemLevelRequest {
1328
    my $itemnumber = shift;
1556
    my $itemnumber = shift;
1329
   
1557
   
1330
    my $item = GetItem($itemnumber);
1558
    my $item = C4::Items::GetItem($itemnumber);
1331
1559
1332
    # must check the notforloan setting of the itemtype
1560
    # must check the notforloan setting of the itemtype
1333
    # FIXME - a lot of places in the code do this
1561
    # FIXME - a lot of places in the code do this
Lines 1362-1371 sub IsAvailableForItemLevelRequest { Link Here
1362
                               $notforloan_per_itemtype;
1590
                               $notforloan_per_itemtype;
1363
1591
1364
1592
1365
    if (C4::Context->preference('AllowOnShelfHolds')) {
1593
    if (CanHoldOnShelf($itemnumber)) {
1366
        return $available_per_item;
1594
        return $available_per_item;
1367
    } else {
1595
    } else {
1368
        return ($available_per_item and ($item->{onloan} or GetReserveStatus($itemnumber) eq "W")); 
1596
        return ($available_per_item and ($item->{onloan} or GetReserveStatus($itemnumber) eq "W"));
1369
    }
1597
    }
1370
}
1598
}
1371
1599
Lines 1393-1407 sub AlterPriority { Link Here
1393
    
1621
    
1394
      my $priority = $reserve->{'priority'};        
1622
      my $priority = $reserve->{'priority'};        
1395
      $priority = $where eq 'up' ? $priority - 1 : $priority + 1;
1623
      $priority = $where eq 'up' ? $priority - 1 : $priority + 1;
1396
      _FixPriority( $biblionumber, $borrowernumber, $priority )
1624
      _FixPriority( $biblionumber, $borrowernumber, $priority ,undef,$reserve->{reservenumber})
1397
1625
1398
    } elsif ( $where eq 'top' ) {
1626
    } elsif ( $where eq 'top' ) {
1399
1627
1400
      _FixPriority( $biblionumber, $borrowernumber, '1' )
1628
      _FixPriority( $biblionumber, $borrowernumber, '1',undef,$reserve->{reservenumber} )
1401
1629
1402
    } elsif ( $where eq 'bottom' ) {
1630
    } elsif ( $where eq 'bottom' ) {
1403
1631
1404
      _FixPriority( $biblionumber, $borrowernumber, '999999' )
1632
        _FixPriority( $biblionumber, $borrowernumber, '999999',undef,$reserve->{reservenumber} )
1405
1633
1406
    }
1634
    }
1407
}
1635
}
Lines 1424-1441 sub ToggleLowestPriority { Link Here
1424
         WHERE biblionumber = ?
1652
         WHERE biblionumber = ?
1425
         AND borrowernumber = ?"
1653
         AND borrowernumber = ?"
1426
    );
1654
    );
1427
    $sth->execute(
1655
    $sth->execute( $biblionumber, $borrowernumber, );
1428
        $biblionumber,
1429
        $borrowernumber,
1430
    );
1431
    $sth->finish;
1656
    $sth->finish;
1432
    
1657
    
1433
    _FixPriority( $biblionumber, $borrowernumber, '999999' );
1658
    _FixPriority( $biblionumber, $borrowernumber, '999999' );
1434
}
1659
}
1435
1660
1661
=head2 CanHoldOnShelf
1662
1663
my $canhold = &CanHoldOnShelf($itemnumber);
1664
1665
 Check if a book can be hold on shelf.
1666
1667
=cut
1668
1669
sub CanHoldOnShelf {
1670
    my ($itemnumber) = @_;
1671
    
1672
    my $item = C4::Items::GetItem($itemnumber);
1673
    my $itemtype = C4::Context->preference('item-level_itypes');
1674
    $itemtype = $itemtype ? $item->{itype} : $item->{itemtype} ;
1675
    my $branch = $item->{C4::Context->preference('HomeOrHoldingBranch')};
1676
    
1677
    my $issuingrule = GetIssuingRule('*', $itemtype, $branch);
1678
    return $issuingrule->{allowonshelfholds};
1679
    
1680
}
1681
1682
sub CanHoldMultipleItems {
1683
  my ( $itemtype ) = @_;
1684
  
1685
  my @multi_itemtypes = split( / /, C4::Context->preference('AllowMultipleHoldsPerBib') );
1686
  for my $mtype ( @multi_itemtypes ) {
1687
    if ( $itemtype eq $mtype ) {
1688
      return 1;
1689
    }
1690
  }
1691
  
1692
  return 0;
1693
}
1694
1436
=head2 _FixPriority
1695
=head2 _FixPriority
1437
1696
1438
  &_FixPriority($biblio,$borrowernumber,$rank,$ignoreSetLowestRank);
1697
&_FixPriority($biblio,$borrowernumber,$rank,$ignoreSetLowestRank,$reservenumber);
1439
1698
1440
Only used internally (so don't export it)
1699
Only used internally (so don't export it)
1441
Changed how this functions works #
1700
Changed how this functions works #
Lines 1447-1453 in new priority rank Link Here
1447
=cut 
1706
=cut 
1448
1707
1449
sub _FixPriority {
1708
sub _FixPriority {
1450
    my ( $biblio, $borrowernumber, $rank, $ignoreSetLowestRank ) = @_;
1709
    my ( $biblio, $borrowernumber, $rank, $ignoreSetLowestRank, $reservenumber ) = @_;
1451
    my $dbh = C4::Context->dbh;
1710
    my $dbh = C4::Context->dbh;
1452
     if ( $rank eq "del" ) {
1711
     if ( $rank eq "del" ) {
1453
         CancelReserve( $biblio, undef, $borrowernumber );
1712
         CancelReserve( $biblio, undef, $borrowernumber );
Lines 1458-1469 sub _FixPriority { Link Here
1458
        my $query = qq/
1717
        my $query = qq/
1459
            UPDATE reserves
1718
            UPDATE reserves
1460
            SET    priority = 0
1719
            SET    priority = 0
1461
            WHERE biblionumber = ?
1720
            WHERE reservenumber = ?
1462
              AND borrowernumber = ?
1721
              AND found IN ('W',"T")
1463
              AND found IN ('W', 'T')
1464
        /;
1722
        /;
1465
        my $sth = $dbh->prepare($query);
1723
        my $sth = $dbh->prepare($query);
1466
        $sth->execute( $biblio, $borrowernumber );
1724
        $sth->execute( $reservenumber );
1467
    }
1725
    }
1468
    my @priority;
1726
    my @priority;
1469
    my @reservedates;
1727
    my @reservedates;
Lines 1474-1480 sub _FixPriority { Link Here
1474
	# This is wrong a waiting reserve has W set
1732
	# This is wrong a waiting reserve has W set
1475
	# The assumption that having an itemnumber set means waiting is wrong and should be corrected any place it occurs
1733
	# The assumption that having an itemnumber set means waiting is wrong and should be corrected any place it occurs
1476
    my $query = qq/
1734
    my $query = qq/
1477
        SELECT borrowernumber, reservedate, constrainttype
1735
        SELECT borrowernumber, reservedate, constrainttype, reservenumber
1478
        FROM   reserves
1736
        FROM   reserves
1479
        WHERE  biblionumber   = ?
1737
        WHERE  biblionumber   = ?
1480
          AND  ((found <> 'W' AND found <> 'T') or found is NULL)
1738
          AND  ((found <> 'W' AND found <> 'T') or found is NULL)
Lines 1509-1524 sub _FixPriority { Link Here
1509
    $query = "
1767
    $query = "
1510
            UPDATE reserves
1768
            UPDATE reserves
1511
            SET    priority = ?
1769
            SET    priority = ?
1512
                WHERE  biblionumber = ?
1770
                WHERE  reservenumber = ?
1513
                 AND borrowernumber   = ?
1514
                 AND reservedate = ?
1771
                 AND reservedate = ?
1515
         AND found IS NULL
1772
         AND found IS NULL
1516
    ";
1773
    ";
1517
    $sth = $dbh->prepare($query);
1774
    $sth = $dbh->prepare($query);
1518
    for ( my $j = 0 ; $j < @priority ; $j++ ) {
1775
    for ( my $j = 0 ; $j < @priority ; $j++ ) {
1519
        $sth->execute(
1776
        $sth->execute(
1520
            $j + 1, $biblio,
1777
            $j + 1, 
1521
            $priority[$j]->{'borrowernumber'},
1778
            $priority[$j]->{'reservenumber'},
1522
            $priority[$j]->{'reservedate'}
1779
            $priority[$j]->{'reservedate'}
1523
        );
1780
        );
1524
        $sth->finish;
1781
        $sth->finish;
Lines 1558-1572 sub _Findgroupreserve { Link Here
1558
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1815
    # TODO: consolidate at least the SELECT portion of the first 2 queries to a common $select var.
1559
    # check for exact targetted match
1816
    # check for exact targetted match
1560
    my $item_level_target_query = qq/
1817
    my $item_level_target_query = qq/
1561
        SELECT reserves.biblionumber        AS biblionumber,
1818
        SELECT reserves.reservenumber AS reservenumber,
1562
               reserves.borrowernumber      AS borrowernumber,
1819
               reserves.biblionumber AS biblionumber,
1563
               reserves.reservedate         AS reservedate,
1820
               reserves.borrowernumber AS borrowernumber,
1564
               reserves.branchcode          AS branchcode,
1821
               reserves.reservedate AS reservedate,
1565
               reserves.cancellationdate    AS cancellationdate,
1822
               reserves.branchcode AS branchcode,
1566
               reserves.found               AS found,
1823
               reserves.cancellationdate AS cancellationdate,
1567
               reserves.reservenotes        AS reservenotes,
1824
               reserves.found AS found,
1568
               reserves.priority            AS priority,
1825
               reserves.reservenotes AS reservenotes,
1569
               reserves.timestamp           AS timestamp,
1826
               reserves.priority AS priority,
1827
               reserves.timestamp AS timestamp,
1570
               biblioitems.biblioitemnumber AS biblioitemnumber,
1828
               biblioitems.biblioitemnumber AS biblioitemnumber,
1571
               reserves.itemnumber          AS itemnumber
1829
               reserves.itemnumber          AS itemnumber
1572
        FROM reserves
1830
        FROM reserves
Lines 1588-1602 sub _Findgroupreserve { Link Here
1588
    
1846
    
1589
    # check for title-level targetted match
1847
    # check for title-level targetted match
1590
    my $title_level_target_query = qq/
1848
    my $title_level_target_query = qq/
1591
        SELECT reserves.biblionumber        AS biblionumber,
1849
        SELECT reserves.reservenumber AS reservenumber,
1592
               reserves.borrowernumber      AS borrowernumber,
1850
               reserves.biblionumber AS biblionumber,
1593
               reserves.reservedate         AS reservedate,
1851
               reserves.borrowernumber AS borrowernumber,
1594
               reserves.branchcode          AS branchcode,
1852
               reserves.reservedate AS reservedate,
1595
               reserves.cancellationdate    AS cancellationdate,
1853
               reserves.branchcode AS branchcode,
1596
               reserves.found               AS found,
1854
               reserves.cancellationdate AS cancellationdate,
1597
               reserves.reservenotes        AS reservenotes,
1855
               reserves.found AS found,
1598
               reserves.priority            AS priority,
1856
               reserves.reservenotes AS reservenotes,
1599
               reserves.timestamp           AS timestamp,
1857
               reserves.priority AS priority,
1858
               reserves.timestamp AS timestamp,
1600
               biblioitems.biblioitemnumber AS biblioitemnumber,
1859
               biblioitems.biblioitemnumber AS biblioitemnumber,
1601
               reserves.itemnumber          AS itemnumber
1860
               reserves.itemnumber          AS itemnumber
1602
        FROM reserves
1861
        FROM reserves
Lines 1617-1632 sub _Findgroupreserve { Link Here
1617
    return @results if @results;
1876
    return @results if @results;
1618
1877
1619
    my $query = qq/
1878
    my $query = qq/
1620
        SELECT reserves.biblionumber               AS biblionumber,
1879
        SELECT reserves.reservenumber AS reservenumber,
1621
               reserves.borrowernumber             AS borrowernumber,
1880
               reserves.biblionumber AS biblionumber,
1622
               reserves.reservedate                AS reservedate,
1881
               reserves.borrowernumber AS borrowernumber,
1623
               reserves.waitingdate                AS waitingdate,
1882
               reserves.reservedate AS reservedate,
1624
               reserves.branchcode                 AS branchcode,
1883
               reserves.branchcode AS branchcode,
1625
               reserves.cancellationdate           AS cancellationdate,
1884
               reserves.cancellationdate AS cancellationdate,
1626
               reserves.found                      AS found,
1885
               reserves.found AS found,
1627
               reserves.reservenotes               AS reservenotes,
1886
               reserves.reservenotes AS reservenotes,
1628
               reserves.priority                   AS priority,
1887
               reserves.priority AS priority,
1629
               reserves.timestamp                  AS timestamp,
1888
               reserves.timestamp AS timestamp,
1630
               reserveconstraints.biblioitemnumber AS biblioitemnumber,
1889
               reserveconstraints.biblioitemnumber AS biblioitemnumber,
1631
               reserves.itemnumber                 AS itemnumber
1890
               reserves.itemnumber                 AS itemnumber
1632
        FROM reserves
1891
        FROM reserves
Lines 1658-1664 ModReserveAffect, _not_ ModReserveFill) Link Here
1658
=cut
1917
=cut
1659
1918
1660
sub _koha_notify_reserve {
1919
sub _koha_notify_reserve {
1661
    my ($itemnumber, $borrowernumber, $biblionumber) = @_;
1920
    my ($itemnumber, $borrowernumber, $biblionumber, $reservenumber) = @_;
1662
1921
1663
    my $dbh = C4::Context->dbh;
1922
    my $dbh = C4::Context->dbh;
1664
    my $borrower = C4::Members::GetMember(borrowernumber => $borrowernumber);
1923
    my $borrower = C4::Members::GetMember(borrowernumber => $borrowernumber);
Lines 1678-1698 sub _koha_notify_reserve { Link Here
1678
    my $messagingprefs;
1937
    my $messagingprefs;
1679
    if ( $to_address || $borrower->{'smsalertnumber'} ) {
1938
    if ( $to_address || $borrower->{'smsalertnumber'} ) {
1680
        $messagingprefs = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $borrowernumber, message_name => 'Hold_Filled' } );
1939
        $messagingprefs = C4::Members::Messaging::GetMessagingPreferences( { borrowernumber => $borrowernumber, message_name => 'Hold_Filled' } );
1681
1682
        return if ( !defined( $messagingprefs->{'letter_code'} ) );
1940
        return if ( !defined( $messagingprefs->{'letter_code'} ) );
1683
        $letter_code = $messagingprefs->{'letter_code'};
1941
        $letter_code = $messagingprefs->{'letter_code'};
1684
    } else {
1942
    } else {
1685
        $letter_code = 'HOLD_PRINT';
1943
        $letter_code = 'HOLD';
1686
        $print_mode = 1;
1944
        $print_mode = 1;
1687
    }
1945
    }
1688
1946
1689
    my $sth = $dbh->prepare("
1947
    my $sth = $dbh->prepare("
1690
        SELECT *
1948
        SELECT *
1691
        FROM   reserves
1949
        FROM   reserves
1692
        WHERE  borrowernumber = ?
1950
        WHERE  reservenumber = ?
1693
            AND biblionumber = ?
1694
    ");
1951
    ");
1695
    $sth->execute( $borrowernumber, $biblionumber );
1952
    $sth->execute( $reservenumber );
1696
    my $reserve = $sth->fetchrow_hashref;
1953
    my $reserve = $sth->fetchrow_hashref;
1697
    my $branch_details = GetBranchDetail( $reserve->{'branchcode'} );
1954
    my $branch_details = GetBranchDetail( $reserve->{'branchcode'} );
1698
1955
Lines 1705-1710 sub _koha_notify_reserve { Link Here
1705
    C4::Letters::parseletter( $letter, 'borrowers', $borrowernumber );
1962
    C4::Letters::parseletter( $letter, 'borrowers', $borrowernumber );
1706
    C4::Letters::parseletter( $letter, 'biblio', $biblionumber );
1963
    C4::Letters::parseletter( $letter, 'biblio', $biblionumber );
1707
    C4::Letters::parseletter( $letter, 'reserves', $borrowernumber, $biblionumber );
1964
    C4::Letters::parseletter( $letter, 'reserves', $borrowernumber, $biblionumber );
1965
    C4::Letters::parseletter( $letter, 'items',  $itemnumber );
1708
1966
1709
    if ( $reserve->{'itemnumber'} ) {
1967
    if ( $reserve->{'itemnumber'} ) {
1710
        C4::Letters::parseletter( $letter, 'items', $reserve->{'itemnumber'} );
1968
        C4::Letters::parseletter( $letter, 'items', $reserve->{'itemnumber'} );
(-)a/admin/smart-rules-service.pl (+82 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# 2009 BibLibre <jeanandre.santoni@biblibre.com>
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 with
17
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18
# Suite 330, Boston, MA  02111-1307 USA
19
#
20
21
use CGI;
22
use C4::Auth;
23
use C4::IssuingRules qw(ModIssuingRule GetIssuingRule);
24
25
my $cgi = CGI->new;
26
27
# get the status of the user, this will check his credentials and rights
28
my ($status, $cookie, $sessionId) = C4::Auth::check_api_auth($cgi, undef);
29
30
my $result;
31
32
if ($status eq 'ok') { # if authentication is ok
33
34
    # Get the POST data
35
    my $branchcode   = $cgi->param('branchcode');
36
    my $categorycode = $cgi->param('categorycode');
37
    my $itemtype     = $cgi->param('itemtype');
38
    my $varname      = $cgi->param('varname');
39
    my $inputvalue   = $cgi->param('inputvalue') eq '' ? undef : $cgi->param('inputvalue');
40
    
41
    # Modify the existing rule
42
    ModIssuingRule({
43
        branchcode   => $branchcode,
44
        categorycode => $categorycode,
45
        itemtype     => $itemtype,
46
        $varname     => $inputvalue,
47
    });
48
    
49
    # Compute inheritance, and return the new value;
50
    my $rule = GetIssuingRule($categorycode, $itemtype, $branchcode);
51
    
52
    $result = $rule->{$varname};
53
    $result = C4::Dates->new($rule->{$varname},'iso')->output() if ($varname eq 'hardduedate');
54
    if ($varname eq 'fine') {
55
        my $num_formatter;
56
        my $cur_format = C4::Context->preference("CurrencyFormat");
57
        use Number::Format;
58
        if ( $cur_format eq 'FR' ) {
59
            $num_formatter = Number::Format->new(
60
                'decimal_fill'      => '2',
61
                'decimal_point'     => ',',
62
                'int_curr_symbol'   => '',
63
                'mon_thousands_sep' => ' ',
64
                'thousands_sep'     => ' ',
65
                'mon_decimal_point' => ','
66
            );
67
        } else {    # US by default..
68
            $num_formatter = Number::Format->new(
69
                'int_curr_symbol'   => '',
70
                'mon_thousands_sep' => ',',
71
                'mon_decimal_point' => '.'
72
            );
73
        }
74
        $result = $num_formatter->format_price($result);
75
    }
76
} else {
77
    $result = 'Fail';
78
}
79
80
print CGI::header('-type'=>'text/plain', '-charset'=>'utf-8');
81
print $result;
82
(-)a/admin/smart-rules.pl (-472 / +99 lines)
Lines 27-531 use C4::Koha; Link Here
27
use C4::Debug;
27
use C4::Debug;
28
use C4::Branch; # GetBranches
28
use C4::Branch; # GetBranches
29
use C4::Dates qw/format_date format_date_in_iso/;
29
use C4::Dates qw/format_date format_date_in_iso/;
30
use C4::IssuingRules;
31
use C4::Circulation;
30
32
31
my $input = new CGI;
33
my $input = new CGI;
32
my $dbh = C4::Context->dbh;
34
my $dbh = C4::Context->dbh;
33
35
34
# my $flagsrequired;
36
my ($template, $loggedinuser, $cookie) = get_template_and_user({
35
# $flagsrequired->{circulation}=1;
37
    template_name   => "admin/smart-rules.tmpl",
36
my ($template, $loggedinuser, $cookie)
38
    query           => $input,
37
    = get_template_and_user({template_name => "admin/smart-rules.tmpl",
39
    type            => "intranet",
38
                            query => $input,
40
    authnotrequired => 0,
39
                            type => "intranet",
41
    flagsrequired   => {parameters => 1},
40
                            authnotrequired => 0,
42
    debug           => 1,
41
                            flagsrequired => {parameters => 1},
43
});
42
                            debug => 1,
44
43
                            });
45
my $type       = $input->param('type');
44
46
my $branchcode = $input->param('branchcode') || ( C4::Branch::onlymine() ? ( C4::Branch::mybranch() || '*' ) : '*' );
45
my $type=$input->param('type');
47
my $op         = $input->param('op');
46
my $branch = $input->param('branch') || ( C4::Branch::onlymine() ? ( C4::Branch::mybranch() || '*' ) : '*' );
48
my $confirm    = $input->param('confirm'); 
47
my $op = $input->param('op');
49
48
50
# This block builds the branch list
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, reservesallowed, issuelength, hardduedate, hardduedatecompare, fine, finedays, firstremind, chargeperiod,rentaldiscount) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
105
    my $sth_update=$dbh->prepare("UPDATE issuingrules SET fine=?, finedays=?, firstremind=?, chargeperiod=?, maxissueqty=?, renewalsallowed=?, reservesallowed=?, issuelength=?, hardduedate=?, hardduedatecompare=?, rentaldiscount=?  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 $reservesallowed  = $input->param('reservesallowed');
117
    $maxissueqty =~ s/\s//g;
118
    $maxissueqty = undef if $maxissueqty !~ /^\d+/;
119
    my $issuelength  = $input->param('issuelength');
120
    my $hardduedate = $input->param('hardduedate');
121
    $hardduedate = format_date_in_iso($hardduedate);
122
    my $hardduedatecompare = $input->param('hardduedatecompare');
123
    my $rentaldiscount = $input->param('rentaldiscount');
124
    $debug and warn "Adding $br, $bor, $cat, $fine, $maxissueqty";
125
126
    $sth_search->execute($br,$bor,$cat);
127
    my $res = $sth_search->fetchrow_hashref();
128
    if ($res->{total}) {
129
        $sth_update->execute($fine, $finedays,$firstremind, $chargeperiod, $maxissueqty, $renewalsallowed,$reservesallowed, $issuelength,$hardduedate,$hardduedatecompare,$rentaldiscount, $br,$bor,$cat);
130
    } else {
131
        $sth_insert->execute($br,$bor,$cat,$maxissueqty,$renewalsallowed,$reservesallowed,$issuelength,$hardduedate,$hardduedatecompare,$fine,$finedays,$firstremind,$chargeperiod,$rentaldiscount);
132
    }
133
} 
134
elsif ($op eq "set-branch-defaults") {
135
    my $categorycode  = $input->param('categorycode');
136
    my $maxissueqty   = $input->param('maxissueqty');
137
    my $holdallowed   = $input->param('holdallowed');
138
    $maxissueqty =~ s/\s//g;
139
    $maxissueqty = undef if $maxissueqty !~ /^\d+/;
140
    $holdallowed =~ s/\s//g;
141
    $holdallowed = undef if $holdallowed !~ /^\d+/;
142
143
    if ($branch eq "*") {
144
        my $sth_search = $dbh->prepare("SELECT count(*) AS total
145
                                        FROM default_circ_rules");
146
        my $sth_insert = $dbh->prepare("INSERT INTO default_circ_rules
147
                                        (maxissueqty, holdallowed)
148
                                        VALUES (?, ?)");
149
        my $sth_update = $dbh->prepare("UPDATE default_circ_rules
150
                                        SET maxissueqty = ?, holdallowed = ?");
151
152
        $sth_search->execute();
153
        my $res = $sth_search->fetchrow_hashref();
154
        if ($res->{total}) {
155
            $sth_update->execute($maxissueqty, $holdallowed);
156
        } else {
157
            $sth_insert->execute($maxissueqty, $holdallowed);
158
        }
159
    } else {
160
        my $sth_search = $dbh->prepare("SELECT count(*) AS total
161
                                        FROM default_branch_circ_rules
162
                                        WHERE branchcode = ?");
163
        my $sth_insert = $dbh->prepare("INSERT INTO default_branch_circ_rules
164
                                        (branchcode, maxissueqty, holdallowed)
165
                                        VALUES (?, ?, ?)");
166
        my $sth_update = $dbh->prepare("UPDATE default_branch_circ_rules
167
                                        SET maxissueqty = ?, holdallowed = ?
168
                                        WHERE branchcode = ?");
169
        $sth_search->execute($branch);
170
        my $res = $sth_search->fetchrow_hashref();
171
        if ($res->{total}) {
172
            $sth_update->execute($maxissueqty, $holdallowed, $branch);
173
        } else {
174
            $sth_insert->execute($branch, $maxissueqty, $holdallowed);
175
        }
176
    }
177
}
178
elsif ($op eq "add-branch-cat") {
179
    my $categorycode  = $input->param('categorycode');
180
    my $maxissueqty   = $input->param('maxissueqty');
181
    $maxissueqty =~ s/\s//g;
182
    $maxissueqty = undef if $maxissueqty !~ /^\d+/;
183
184
    if ($branch eq "*") {
185
        if ($categorycode eq "*") {
186
            my $sth_search = $dbh->prepare("SELECT count(*) AS total
187
                                            FROM default_circ_rules");
188
            my $sth_insert = $dbh->prepare("INSERT INTO default_circ_rules
189
                                            (maxissueqty)
190
                                            VALUES (?)");
191
            my $sth_update = $dbh->prepare("UPDATE default_circ_rules
192
                                            SET maxissueqty = ?");
193
194
            $sth_search->execute();
195
            my $res = $sth_search->fetchrow_hashref();
196
            if ($res->{total}) {
197
                $sth_update->execute($maxissueqty);
198
            } else {
199
                $sth_insert->execute($maxissueqty);
200
            }
201
        } else {
202
            my $sth_search = $dbh->prepare("SELECT count(*) AS total
203
                                            FROM default_borrower_circ_rules
204
                                            WHERE categorycode = ?");
205
            my $sth_insert = $dbh->prepare("INSERT INTO default_borrower_circ_rules
206
                                            (categorycode, maxissueqty)
207
                                            VALUES (?, ?)");
208
            my $sth_update = $dbh->prepare("UPDATE default_borrower_circ_rules
209
                                            SET maxissueqty = ?
210
                                            WHERE categorycode = ?");
211
            $sth_search->execute($branch);
212
            my $res = $sth_search->fetchrow_hashref();
213
            if ($res->{total}) {
214
                $sth_update->execute($maxissueqty, $categorycode);
215
            } else {
216
                $sth_insert->execute($categorycode, $maxissueqty);
217
            }
218
        }
219
    } elsif ($categorycode eq "*") {
220
        my $sth_search = $dbh->prepare("SELECT count(*) AS total
221
                                        FROM default_branch_circ_rules
222
                                        WHERE branchcode = ?");
223
        my $sth_insert = $dbh->prepare("INSERT INTO default_branch_circ_rules
224
                                        (branchcode, maxissueqty)
225
                                        VALUES (?, ?)");
226
        my $sth_update = $dbh->prepare("UPDATE default_branch_circ_rules
227
                                        SET maxissueqty = ?
228
                                        WHERE branchcode = ?");
229
        $sth_search->execute($branch);
230
        my $res = $sth_search->fetchrow_hashref();
231
        if ($res->{total}) {
232
            $sth_update->execute($maxissueqty, $branch);
233
        } else {
234
            $sth_insert->execute($branch, $maxissueqty);
235
        }
236
    } else {
237
        my $sth_search = $dbh->prepare("SELECT count(*) AS total
238
                                        FROM branch_borrower_circ_rules
239
                                        WHERE branchcode = ?
240
                                        AND   categorycode = ?");
241
        my $sth_insert = $dbh->prepare("INSERT INTO branch_borrower_circ_rules
242
                                        (branchcode, categorycode, maxissueqty)
243
                                        VALUES (?, ?, ?)");
244
        my $sth_update = $dbh->prepare("UPDATE branch_borrower_circ_rules
245
                                        SET maxissueqty = ?
246
                                        WHERE branchcode = ?
247
                                        AND categorycode = ?");
248
249
        $sth_search->execute($branch, $categorycode);
250
        my $res = $sth_search->fetchrow_hashref();
251
        if ($res->{total}) {
252
            $sth_update->execute($maxissueqty, $branch, $categorycode);
253
        } else {
254
            $sth_insert->execute($branch, $categorycode, $maxissueqty);
255
        }
256
    }
257
}
258
elsif ($op eq "add-branch-item") {
259
    my $itemtype  = $input->param('itemtype');
260
    my $holdallowed   = $input->param('holdallowed');
261
    $holdallowed =~ s/\s//g;
262
    $holdallowed = undef if $holdallowed !~ /^\d+/;
263
264
    if ($branch eq "*") {
265
        if ($itemtype eq "*") {
266
            my $sth_search = $dbh->prepare("SELECT count(*) AS total
267
                                            FROM default_circ_rules");
268
            my $sth_insert = $dbh->prepare("INSERT INTO default_circ_rules
269
                                            (holdallowed)
270
                                            VALUES (?)");
271
            my $sth_update = $dbh->prepare("UPDATE default_circ_rules
272
                                            SET holdallowed = ?");
273
274
            $sth_search->execute();
275
            my $res = $sth_search->fetchrow_hashref();
276
            if ($res->{total}) {
277
                $sth_update->execute($holdallowed);
278
            } else {
279
                $sth_insert->execute($holdallowed);
280
            }
281
        } else {
282
            my $sth_search = $dbh->prepare("SELECT count(*) AS total
283
                                            FROM default_branch_item_rules
284
                                            WHERE itemtype = ?");
285
            my $sth_insert = $dbh->prepare("INSERT INTO default_branch_item_rules
286
                                            (itemtype, holdallowed)
287
                                            VALUES (?, ?)");
288
            my $sth_update = $dbh->prepare("UPDATE default_branch_item_rules
289
                                            SET holdallowed = ?
290
                                            WHERE itemtype = ?");
291
            $sth_search->execute($itemtype);
292
            my $res = $sth_search->fetchrow_hashref();
293
            if ($res->{total}) {
294
                $sth_update->execute($holdallowed, $itemtype);
295
            } else {
296
                $sth_insert->execute($itemtype, $holdallowed);
297
            }
298
        }
299
    } elsif ($itemtype eq "*") {
300
        my $sth_search = $dbh->prepare("SELECT count(*) AS total
301
                                        FROM default_branch_circ_rules
302
                                        WHERE branchcode = ?");
303
        my $sth_insert = $dbh->prepare("INSERT INTO default_branch_circ_rules
304
                                        (branchcode, holdallowed)
305
                                        VALUES (?, ?)");
306
        my $sth_update = $dbh->prepare("UPDATE default_branch_circ_rules
307
                                        SET holdallowed = ?
308
                                        WHERE branchcode = ?");
309
        $sth_search->execute($branch);
310
        my $res = $sth_search->fetchrow_hashref();
311
        if ($res->{total}) {
312
            $sth_update->execute($holdallowed, $branch);
313
        } else {
314
            $sth_insert->execute($branch, $holdallowed);
315
        }
316
    } else {
317
        my $sth_search = $dbh->prepare("SELECT count(*) AS total
318
                                        FROM branch_item_rules
319
                                        WHERE branchcode = ?
320
                                        AND   itemtype = ?");
321
        my $sth_insert = $dbh->prepare("INSERT INTO branch_item_rules
322
                                        (branchcode, itemtype, holdallowed)
323
                                        VALUES (?, ?, ?)");
324
        my $sth_update = $dbh->prepare("UPDATE branch_item_rules
325
                                        SET holdallowed = ?
326
                                        WHERE branchcode = ?
327
                                        AND itemtype = ?");
328
329
        $sth_search->execute($branch, $itemtype);
330
        my $res = $sth_search->fetchrow_hashref();
331
        if ($res->{total}) {
332
            $sth_update->execute($holdallowed, $branch, $itemtype);
333
        } else {
334
            $sth_insert->execute($branch, $itemtype, $holdallowed);
335
        }
336
    }
337
}
338
339
my $branches = GetBranches();
51
my $branches = GetBranches();
340
my @branchloop;
52
my @branchloop;
341
for my $thisbranch (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %$branches) {
53
for my $thisbranch (sort { $branches->{$a}->{branchname} cmp $branches->{$b}->{branchname} } keys %$branches) {
342
    push @branchloop, {
54
    push @branchloop, {
343
        value      => $thisbranch,
55
        value      => $thisbranch,
344
        selected   => $thisbranch eq $branch,
56
        selected   => $thisbranch eq $branchcode,
345
        branchname => $branches->{$thisbranch}->{'branchname'},
57
        branchname => $branches->{$thisbranch}->{'branchname'},
346
    };
58
    };
347
}
59
}
348
60
349
my $sth=$dbh->prepare("SELECT description,categorycode FROM categories ORDER BY description");
61
# Get the patron category list
350
$sth->execute;
62
my @category_loop = C4::Category->all;
351
my @category_loop;
352
while (my $data=$sth->fetchrow_hashref){
353
    push @category_loop,$data;
354
}
355
63
356
$sth->finish;
64
# Get the item types list
357
$sth=$dbh->prepare("SELECT description,itemtype FROM itemtypes ORDER BY description");
65
my @itemtypes = C4::ItemType->all;
358
$sth->execute;
66
359
# $i=0;
67
if ( $op eq 'delete' ) {
360
my @row_loop;
68
    DelIssuingRule({
361
my @itemtypes;
69
        branchcode   => $branchcode,
362
while (my $row=$sth->fetchrow_hashref){
70
        categorycode => $input->param('categorycode'),
363
    push @itemtypes,$row;
71
        itemtype     => $input->param('itemtype'),
72
    });
364
}
73
}
74
# save the values entered
75
elsif ( $op eq 'add' ) {
365
76
366
my $sth2 = $dbh->prepare("
77
    # Converts '' to undef, so we can have NULL in database fields
367
    SELECT issuingrules.*, itemtypes.description AS humanitemtype, categories.description AS humancategorycode
78
    my $issuingrule;
368
    FROM issuingrules
79
    for ( $input->param ) {
369
    LEFT JOIN itemtypes
80
        my $v = $input->param($_);
370
        ON (itemtypes.itemtype = issuingrules.itemtype)
81
        $issuingrule->{$_} = length $v ? $v : undef;
371
    LEFT JOIN categories
82
    }
372
        ON (categories.categorycode = issuingrules.categorycode)
373
    WHERE issuingrules.branchcode = ?
374
");
375
$sth2->execute($branch);
376
83
377
while (my $row = $sth2->fetchrow_hashref) {
84
    # We don't want op to be passed to the API
378
    $row->{'current_branch'} ||= $row->{'branchcode'};
85
    delete $issuingrule->{'op'};
379
    $row->{'humanitemtype'} ||= $row->{'itemtype'};
86
380
    $row->{'default_humanitemtype'} = 1 if $row->{'humanitemtype'} eq '*';
87
    # If the (branchcode,categorycode,itemtype) combination already exists...
381
    $row->{'humancategorycode'} ||= $row->{'categorycode'};
88
    my @issuingrules = GetIssuingRules({
382
    $row->{'default_humancategorycode'} = 1 if $row->{'humancategorycode'} eq '*';
89
        branchcode      => $issuingrule->{'branchcode'},
383
    $row->{'fine'} = sprintf('%.2f', $row->{'fine'});
90
        categorycode    => $issuingrule->{'categorycode'},
384
    if ($row->{'hardduedate'} ne '0000-00-00') {
91
        itemtype        => $issuingrule->{'itemtype'},
385
       $row->{'hardduedate'} = format_date( $row->{'hardduedate'});
92
    });
386
       $row->{'hardduedatebefore'} = 1 if ($row->{'hardduedatecompare'} == -1);
93
387
       $row->{'hardduedateexact'} = 1 if ($row->{'hardduedatecompare'} ==  0);
94
    # ...we modify the existing rule...
388
       $row->{'hardduedateafter'} = 1 if ($row->{'hardduedatecompare'} ==  1);
95
    if ( @issuingrules ) {
96
        ModIssuingRule( $issuingrule );
97
#    } elsif (@issuingrules){
98
#        $template->param(confirm=>1);
99
#        $template->param(%$issuingrule);
100
#        foreach (@category_loop) { 
101
#            $_->{selected}="selected" if ($_->{categorycode} eq $issuingrule->{categorycode});
102
#        }
103
#        foreach (@itemtypes) { 
104
#            $_->{selected}="selected" if ($_->{itemtype} eq $issuingrule->{itemtype});
105
#        }
106
    # ...else we add a new rule.
389
    } else {
107
    } else {
390
       $row->{'hardduedate'} = 0;
108
        AddIssuingRule( $issuingrule );
391
    }
109
    }
392
    push @row_loop, $row;
393
}
394
$sth->finish;
395
396
my @sorted_row_loop = sort by_category_and_itemtype @row_loop;
397
398
my $sth_branch_cat;
399
if ($branch eq "*") {
400
    $sth_branch_cat = $dbh->prepare("
401
        SELECT default_borrower_circ_rules.*, categories.description AS humancategorycode
402
        FROM default_borrower_circ_rules
403
        JOIN categories USING (categorycode)
404
        
405
    ");
406
    $sth_branch_cat->execute();
407
} else {
408
    $sth_branch_cat = $dbh->prepare("
409
        SELECT branch_borrower_circ_rules.*, categories.description AS humancategorycode
410
        FROM branch_borrower_circ_rules
411
        JOIN categories USING (categorycode)
412
        WHERE branch_borrower_circ_rules.branchcode = ?
413
    ");
414
    $sth_branch_cat->execute($branch);
415
}
416
417
my @branch_cat_rules = ();
418
while (my $row = $sth_branch_cat->fetchrow_hashref) {
419
    push @branch_cat_rules, $row;
420
}
421
my @sorted_branch_cat_rules = sort { $a->{'humancategorycode'} cmp $b->{'humancategorycode'} } @branch_cat_rules;
422
423
# note undef maxissueqty so that template can deal with them
424
foreach my $entry (@sorted_branch_cat_rules, @sorted_row_loop) {
425
    $entry->{unlimited_maxissueqty} = 1 unless defined($entry->{maxissueqty});
426
}
427
428
@sorted_row_loop = sort by_category_and_itemtype @row_loop;
429
430
my $sth_branch_item;
431
if ($branch eq "*") {
432
    $sth_branch_item = $dbh->prepare("
433
        SELECT default_branch_item_rules.*, itemtypes.description AS humanitemtype
434
        FROM default_branch_item_rules
435
        JOIN itemtypes USING (itemtype)
436
    ");
437
    $sth_branch_item->execute();
438
} else {
439
    $sth_branch_item = $dbh->prepare("
440
        SELECT branch_item_rules.*, itemtypes.description AS humanitemtype
441
        FROM branch_item_rules
442
        JOIN itemtypes USING (itemtype)
443
        WHERE branch_item_rules.branchcode = ?
444
    ");
445
    $sth_branch_item->execute($branch);
446
}
447
448
my @branch_item_rules = ();
449
while (my $row = $sth_branch_item->fetchrow_hashref) {
450
    push @branch_item_rules, $row;
451
}
452
my @sorted_branch_item_rules = sort { $a->{'humanitemtype'} cmp $b->{'humanitemtype'} } @branch_item_rules;
453
454
# note undef holdallowed so that template can deal with them
455
foreach my $entry (@sorted_branch_item_rules) {
456
    $entry->{holdallowed_any} = 1 if($entry->{holdallowed} == 2);
457
    $entry->{holdallowed_same} = 1 if($entry->{holdallowed} == 1);
458
}
110
}
459
111
460
$template->param(show_branch_cat_rule_form => 1);
112
# Get the issuing rules list...
461
$template->param(branch_item_rule_loop => \@sorted_branch_item_rules);
113
my @issuingrules = GetIssuingRulesByBranchCode($branchcode);
462
$template->param(branch_cat_rule_loop => \@sorted_branch_cat_rules);
114
463
115
# ...and refine its data, row by row.
464
my $sth_defaults;
116
for my $rule ( @issuingrules ) {
465
if ($branch eq "*") {
117
    $rule->{'humanitemtype'}             ||= $rule->{'itemtype'};
466
    $sth_defaults = $dbh->prepare("
118
    $rule->{'default_humanitemtype'}       = $rule->{'humanitemtype'} eq '*';
467
        SELECT *
119
    $rule->{'humancategorycode'}         ||= $rule->{'categorycode'};
468
        FROM default_circ_rules
120
    $rule->{'default_humancategorycode'}   = $rule->{'humancategorycode'} eq '*';
469
    ");
121
    if ($rule->{'hardduedate'} ne '0000-00-00') {
470
    $sth_defaults->execute();
122
       $rule->{'hardduedate'} = format_date( $rule->{'hardduedate'});
471
} else {
123
       $rule->{'hardduedatebefore'} = 1 if ($rule->{'hardduedatecompare'} == -1);
472
    $sth_defaults = $dbh->prepare("
124
       $rule->{'hardduedateexact'} = 1 if ($rule->{'hardduedatecompare'} ==  0);
473
        SELECT *
125
       $rule->{'hardduedateafter'} = 1 if ($rule->{'hardduedatecompare'} ==  1);
474
        FROM default_branch_circ_rules
126
    } else {
475
        WHERE branchcode = ?
127
       $rule->{'hardduedate'} = 0;
476
    ");
128
    }
477
    $sth_defaults->execute($branch);
129
    $rule->{'fine'}                        = sprintf('%.2f', $rule->{'fine'});
130
131
    # This block is to show herited values in grey.
132
    # We juste compare keys from our raw rule, with keys from the computed rule.
133
    my $computedrule = GetIssuingRule($rule->{'categorycode'}, $rule->{'itemtype'}, $rule->{'branchcode'});
134
    for ( keys %$rule ) {
135
        if ( not defined $rule->{$_} ) {
136
            $rule->{$_} = $computedrule->{$_};
137
            $rule->{"herited_$_"} = 1;
138
        }
139
    }
478
}
140
}
479
141
480
my $defaults = $sth_defaults->fetchrow_hashref;
481
142
482
if ($defaults) {
143
$template->param(default_rules => ($branchcode eq '*' ? 1 : 0));
483
    $template->param(default_holdallowed_none => 1) if($defaults->{holdallowed} == 0);
484
    $template->param(default_holdallowed_same => 1) if($defaults->{holdallowed} == 1);
485
    $template->param(default_holdallowed_any => 1) if($defaults->{holdallowed} == 2);
486
    $template->param(default_maxissueqty => $defaults->{maxissueqty});
487
}
488
144
489
$template->param(default_rules => ($defaults ? 1 : 0));
145
$template->param(
146
    categoryloop  => \@category_loop,
147
    itemtypeloop  => \@itemtypes,
148
    rules         => \@issuingrules,
149
    branchloop    => \@branchloop,
150
    humanbranch   => ($branchcode ne '*' ? $branches->{$branchcode}->{branchname} : ''),
151
    branchcode    => $branchcode,
152
    definedbranch => scalar(@issuingrules) > 0,
153
);
490
154
491
$template->param(categoryloop => \@category_loop,
492
                        itemtypeloop => \@itemtypes,
493
                        rules => \@sorted_row_loop,
494
                        branchloop => \@branchloop,
495
                        humanbranch => ($branch ne '*' ? $branches->{$branch}->{branchname} : ''),
496
                        current_branch => $branch,
497
                        definedbranch => scalar(@sorted_row_loop)>0 
498
                        );
499
output_html_with_http_headers $input, $cookie, $template->output;
155
output_html_with_http_headers $input, $cookie, $template->output;
500
156
501
exit 0;
157
exit 0;
502
158
503
# sort by patron category, then item type, putting
504
# default entries at the bottom
505
sub by_category_and_itemtype {
506
    unless (by_category($a, $b)) {
507
        return by_itemtype($a, $b);
508
    }
509
}
510
511
sub by_category {
512
    my ($a, $b) = @_;
513
    if ($a->{'default_humancategorycode'}) {
514
        return ($b->{'default_humancategorycode'} ? 0 : 1);
515
    } elsif ($b->{'default_humancategorycode'}) {
516
        return -1;
517
    } else {
518
        return $a->{'humancategorycode'} cmp $b->{'humancategorycode'};
519
    }
520
}
521
522
sub by_itemtype {
523
    my ($a, $b) = @_;
524
    if ($a->{'default_humanitemtype'}) {
525
        return ($b->{'default_humanitemtype'} ? 0 : 1);
526
    } elsif ($b->{'default_humanitemtype'}) {
527
        return -1;
528
    } else {
529
        return $a->{'humanitemtype'} cmp $b->{'humanitemtype'};
530
    }
531
}
(-)a/circ/branchtransfers.pl (-1 / +3 lines)
Lines 86-92 if ( $request eq "KillWaiting" ) { Link Here
86
}
86
}
87
elsif ( $request eq "SetWaiting" ) {
87
elsif ( $request eq "SetWaiting" ) {
88
    my $item = $query->param('itemnumber');
88
    my $item = $query->param('itemnumber');
89
    ModReserveAffect( $item, $borrowernumber );
89
    my $itemhash=C4::Items::GetItem($item);
90
    my ( $reservetype, $reserve ) = C4::Reserves::CheckReserves( undef, $itemhash->{barcode} );
91
    ModReserveAffect( $item, $borrowernumber,$tobranchcd ne C4::Context->userenv->{'branch'}, $reserve->{reservenumber});
90
    $ignoreRs    = 1;
92
    $ignoreRs    = 1;
91
    $setwaiting  = 1;
93
    $setwaiting  = 1;
92
    $reqmessage  = 1;
94
    $reqmessage  = 1;
(-)a/circ/circulation.pl (-50 / +181 lines)
Lines 30-41 use C4::Dates qw/format_date/; Link Here
30
use C4::Branch; # GetBranches
30
use C4::Branch; # GetBranches
31
use C4::Koha;   # GetPrinter
31
use C4::Koha;   # GetPrinter
32
use C4::Circulation;
32
use C4::Circulation;
33
use C4::Overdues qw/CheckBorrowerDebarred/;
33
use C4::Members;
34
use C4::Members;
34
use C4::Biblio;
35
use C4::Biblio;
35
use C4::Reserves;
36
use C4::Reserves;
36
use C4::Context;
37
use C4::Context;
38
use C4::Debug;
37
use CGI::Session;
39
use CGI::Session;
38
40
use C4::Items;
41
use JSON;
42
use YAML;
39
use Date::Calc qw(
43
use Date::Calc qw(
40
  Today
44
  Today
41
  Add_Delta_YM
45
  Add_Delta_YM
Lines 49-57 use List::MoreUtils qw/uniq/; Link Here
49
# PARAMETERS READING
53
# PARAMETERS READING
50
#
54
#
51
my $query = new CGI;
55
my $query = new CGI;
52
56
my $dbh = C4::Context->dbh;
53
my $sessionID = $query->cookie("CGISESSID") ;
57
my $remotehost = $query->remote_host();
54
my $session = get_session($sessionID);
58
my $sessionID  = $query->cookie("CGISESSID");
59
my $session    = get_session($sessionID);
55
60
56
# branch and printer are now defined by the userenv
61
# branch and printer are now defined by the userenv
57
# but first we have to check if someone has tried to change them
62
# but first we have to check if someone has tried to change them
Lines 89-97 my ( $template, $loggedinuser, $cookie ) = get_template_and_user ( Link Here
89
94
90
my $branches = GetBranches();
95
my $branches = GetBranches();
91
96
92
my @failedrenews = $query->param('failedrenew');    # expected to be itemnumbers 
97
my @failedrenews  = $query->param('failedrenew');   # expected to be itemnumbers
98
my @failedreturns = $query->param('failedreturn');  # expected to be barcodes
99
my @renewerrors   = $query->param('renewerror');    # expected to be json
100
my @returnerrors  = $query->param('returnerror');   # expected to be json
93
my %renew_failed;
101
my %renew_failed;
94
for (@failedrenews) { $renew_failed{$_} = 1; }
102
my %return_failed;
103
for (@failedrenews) { $renew_failed{$_} = decode_json(shift @renewerrors); }
104
for (@failedreturns) { $return_failed{GetItemnumberFromBarcode($_)} = decode_json(shift @returnerrors); }
95
105
96
my $findborrower = $query->param('findborrower');
106
my $findborrower = $query->param('findborrower');
97
$findborrower =~ s|,| |g;
107
$findborrower =~ s|,| |g;
Lines 126-139 my $organisation = $query->param('organisations'); Link Here
126
my $print          = $query->param('print');
136
my $print          = $query->param('print');
127
my $newexpiry      = $query->param('dateexpiry');
137
my $newexpiry      = $query->param('dateexpiry');
128
my $debt_confirmed = $query->param('debt_confirmed') || 0; # Don't show the debt error dialog twice
138
my $debt_confirmed = $query->param('debt_confirmed') || 0; # Don't show the debt error dialog twice
129
139
$debug && warn $newexpiry;
130
# Check if stickyduedate is turned off
140
# Check if stickyduedate is turned off
131
if ( $barcode ) {
141
if ( $barcode ) {
132
    # was stickyduedate loaded from session?
142
    # was stickyduedate loaded from session?
133
    if ( $stickyduedate && ! $query->param("stickyduedate") ) {
143
    if ( $stickyduedate && ! $query->param("stickyduedate") ) {
134
        $session->clear( 'stickyduedate' );
144
        $session->clear( 'stickyduedate' );
135
        $stickyduedate  = $query->param('stickyduedate');
145
        $stickyduedate  = $query->param('stickyduedate');
136
        $duedatespec    = $query->param('duedatespec');
137
    }
146
    }
138
}
147
}
139
148
Lines 158-164 if($duedatespec_allow){ Link Here
158
    }
167
    }
159
}
168
}
160
169
161
my $todaysdate = C4::Dates->new->output('iso');
170
my $todaysdate = C4::Dates->new->output( 'iso' );
162
171
163
# check and see if we should print
172
# check and see if we should print
164
if ( $barcode eq '' && $print eq 'maybe' ) {
173
if ( $barcode eq '' && $print eq 'maybe' ) {
Lines 238-244 if ($borrowernumber) { Link Here
238
        $template->param(
247
        $template->param(
239
            flagged  => "1",
248
            flagged  => "1",
240
            noissues => "1",
249
            noissues => "1",
241
            expired => "1",
250
            expired     => format_date($borrower->{dateexpiry}),
251
            warning     => 1,
242
            renewaldate => format_date("$renew_year-$renew_month-$renew_day")
252
            renewaldate => format_date("$renew_year-$renew_month-$renew_day")
243
        );
253
        );
244
    }
254
    }
Lines 249-257 if ($borrowernumber) { Link Here
249
    {
259
    {
250
        # borrower card soon to expire warn librarian
260
        # borrower card soon to expire warn librarian
251
        $template->param("warndeparture" => format_date($borrower->{dateexpiry}),
261
        $template->param("warndeparture" => format_date($borrower->{dateexpiry}),
252
        flagged       => "1",);
262
        flagged       => "1", "warning" => 1);
253
        if (C4::Context->preference('ReturnBeforeExpiry')){
263
        if (C4::Context->preference('ReturnBeforeExpiry')){
254
            $template->param("returnbeforeexpiry" => 1);
264
            $template->param("returnbeforeexpiry" => 1, "warning => 1");
255
        }
265
        }
256
    }
266
    }
257
    $template->param(
267
    $template->param(
Lines 259-270 if ($borrowernumber) { Link Here
259
        issuecount   => $issue,
269
        issuecount   => $issue,
260
        finetotal    => $fines
270
        finetotal    => $fines
261
    );
271
    );
272
273
    my $debar = CheckBorrowerDebarred($borrowernumber);
274
    if($debar){
275
        $template->param(userdebarred => 1);
276
        $template->param(debarredcomment => $borrower->{debarredcomment});
277
        if( $debar ne "9999-12-31"){
278
            $template->param(userdebarreddate => C4::Dates::format_date($debar));
279
        }
280
    }
262
}
281
}
263
282
264
#
283
#
265
# STEP 3 : ISSUING
284
# STEP 3 : ISSUING
266
#
285
#
267
#
286
#
287
my $confirm_required = 0;
268
if ($barcode) {
288
if ($barcode) {
269
    # always check for blockers on issuing
289
    # always check for blockers on issuing
270
    my ( $error, $question ) =
290
    my ( $error, $question ) =
Lines 306-313 if ($barcode) { Link Here
306
    # FIXME If the issue is confirmed, we launch another time GetMemberIssuesAndFines, now display the issue count after issue 
326
    # FIXME If the issue is confirmed, we launch another time GetMemberIssuesAndFines, now display the issue count after issue 
307
    my ( $od, $issue, $fines ) = GetMemberIssuesAndFines( $borrowernumber );
327
    my ( $od, $issue, $fines ) = GetMemberIssuesAndFines( $borrowernumber );
308
    $template->param( issuecount   => $issue );
328
    $template->param( issuecount   => $issue );
329
330
    # Is there a circulation note?
331
    my $itemnumber = GetItemnumberFromBarcode($barcode);
332
    my $biblionumber = GetBiblionumberFromItemnumber($itemnumber);
333
    my $record = GetMarcBiblio($biblionumber);
334
    my $frameworkcode = GetFrameworkCode($biblionumber);
335
    my $circnotefield = GetRecordValue('circnote', $record, $frameworkcode);
336
    if (defined @$circnotefield[0]) {
337
	$template->param(circnote => @$circnotefield[0]->{'subfield'});
338
    }
309
}
339
}
310
340
341
342
# Setting the right status if an hold has been confirmed
343
#This should never be used in fact
344
my $resbarcode = $query->param("resbarcode");
345
if ($resbarcode) {
346
        if ( my ( $reservetype, $reserve ) = C4::Reserves::CheckReserves( undef, $resbarcode ) ) {
347
            if ( $reservetype eq "Waiting" || $reservetype eq "Reserved" ) {
348
                my $transfer = C4::Context->userenv->{branch} ne $reserve->{branchcode};
349
                ModReserveAffect( $reserve->{itemnumber}, $reserve->{borrowernumber}, $transfer, $reserve->{"reservenumber"} );
350
            }
351
        }
352
}
353
354
355
311
# reload the borrower info for the sake of reseting the flags.....
356
# reload the borrower info for the sake of reseting the flags.....
312
if ($borrowernumber) {
357
if ($borrowernumber) {
313
    $borrower = GetMemberDetails( $borrowernumber, 0 );
358
    $borrower = GetMemberDetails( $borrowernumber, 0 );
Lines 345-355 if ($borrowernumber) { Link Here
345
        $getreserv{itemcallnumber} = $getiteminfo->{'itemcallnumber'};
390
        $getreserv{itemcallnumber} = $getiteminfo->{'itemcallnumber'};
346
        $getreserv{biblionumber}   = $getiteminfo->{'biblionumber'};
391
        $getreserv{biblionumber}   = $getiteminfo->{'biblionumber'};
347
        $getreserv{waitingat}      = GetBranchName( $num_res->{'branchcode'} );
392
        $getreserv{waitingat}      = GetBranchName( $num_res->{'branchcode'} );
393
	my $materials = $getiteminfo->{'materials'};
394
        $template->param(materials         => $materials);
348
        #         check if we have a waiting status for reservations
395
        #         check if we have a waiting status for reservations
349
        if ( $num_res->{'found'} eq 'W' ) {
396
        if ( $num_res->{'found'} eq 'W' ) {
350
            $getreserv{color}   = 'reserved';
397
            $getreserv{color}   = 'reserved';
351
            $getreserv{waiting} = 1;
398
            $getreserv{waiting} = 1;
352
#     genarate information displaying only waiting reserves
399
#     genarate information displaying only waiting reserves
400
        my @maxpickupdate = $num_res->{'waitingdate'} ? GetMaxPickupDate( $num_res->{'waitingdate'}, $borrowernumber, $num_res ) : '';
401
        $getreserv{'maxpickupdate'} = sprintf( "%d-%02d-%02d", @maxpickupdate );
402
        $getWaitingReserveInfo{'formattedwaitingdate'} = format_date( $getreserv{'maxpickupdate'} );
403
        $getreserv{'formattedwaitingdate'} = format_date( $getreserv{'maxpickupdate'} );
404
353
        $getWaitingReserveInfo{title}        = $getiteminfo->{'title'};
405
        $getWaitingReserveInfo{title}        = $getiteminfo->{'title'};
354
        $getWaitingReserveInfo{biblionumber} = $getiteminfo->{'biblionumber'};
406
        $getWaitingReserveInfo{biblionumber} = $getiteminfo->{'biblionumber'};
355
        $getWaitingReserveInfo{itemtype}     = $itemtypeinfo->{'description'};
407
        $getWaitingReserveInfo{itemtype}     = $itemtypeinfo->{'description'};
Lines 408-458 my @relissues; Link Here
408
my @relprevissues;
460
my @relprevissues;
409
my $displayrelissues;
461
my $displayrelissues;
410
462
463
my @borrowers_with_issues;
464
my @relissues;
465
my @relprevissues;
466
my $displayrelissues;
467
## ADDED BY JF: new itemtype issuingrules counter stuff
468
my $issued_itemtypes_count;
469
my @issued_itemtypes_count_loop;
470
411
my $totalprice = 0;
471
my $totalprice = 0;
412
472
413
sub build_issue_data {
473
sub build_issue_data {
414
    my $issueslist = shift;
474
    my $issueslist = shift;
415
    my $relatives = shift;
475
    my $relatives = shift;
416
476
417
    # split in 2 arrays for today & previous
477
  # split in 2 arrays for today & previous
418
    foreach my $it ( @$issueslist ) {
478
    foreach my $it (@$issueslist) {
419
        my $itemtypeinfo = getitemtypeinfo( (C4::Context->preference('item-level_itypes')) ? $it->{'itype'} : $it->{'itemtype'} );
479
        my $itemtypeinfo = getitemtypeinfo( ( C4::Context->preference('item-level_itypes') ) ? $it->{'itype'} : $it->{'itemtype'} );
420
480
421
        # Getting borrower details
481
        # Getting borrower details
422
        my $memberdetails = GetMemberDetails($it->{'borrowernumber'});
482
        my $memberdetails = GetMemberDetails($it->{'borrowernumber'});
423
        $it->{'borrowername'} = $memberdetails->{'firstname'} . " " . $memberdetails->{'surname'};
483
        $it->{'borrowername'} = $memberdetails->{'firstname'} . " " . $memberdetails->{'surname'};
424
        $it->{'cardnumber'} = $memberdetails->{'cardnumber'};
484
        $it->{'cardnumber'} = $memberdetails->{'cardnumber'};
425
        # set itemtype per item-level_itype syspref - FIXME this is an ugly hack
485
        # set itemtype per item-level_itype syspref - FIXME this is an ugly hack
426
        $it->{'itemtype'} = ( C4::Context->preference( 'item-level_itypes' ) ) ? $it->{'itype'} : $it->{'itemtype'};
486
        $it->{'itemtype'} = ( C4::Context->preference('item-level_itypes') ) ? $it->{'itype'} : $it->{'itemtype'};
427
487
428
        ($it->{'charge'}, $it->{'itemtype_charge'}) = GetIssuingCharges(
488
        ( $it->{'charge'}, $it->{'itemtype_charge'} ) = GetIssuingCharges( $it->{'itemnumber'}, $borrower->{'borrowernumber'} );
429
            $it->{'itemnumber'}, $borrower->{'borrowernumber'}
489
        $it->{'charge'} = sprintf( "%.2f", $it->{'charge'} );
430
        );
490
        my ( $can_renew, $can_renew_error ) = CanBookBeRenewed( $borrower->{'borrowernumber'}, $it->{'itemnumber'} );
431
        $it->{'charge'} = sprintf("%.2f", $it->{'charge'});
491
        if ( defined $can_renew_error->{message} ) {
432
        my ($can_renew, $can_renew_error) = CanBookBeRenewed( 
492
            $it->{ "renew_error_" . $can_renew_error->{message} } = 1;
433
            $borrower->{'borrowernumber'},$it->{'itemnumber'}
493
            $it->{'renew_error'} = 1;
434
        );
494
        }
435
        $it->{"renew_error_${can_renew_error}"} = 1 if defined $can_renew_error;
495
        $it->{renewals} ||= 0;
496
        $it->{$_} = $can_renew_error->{$_} for (qw(renewalsallowed reserves));
436
        my ( $restype, $reserves ) = CheckReserves( $it->{'itemnumber'} );
497
        my ( $restype, $reserves ) = CheckReserves( $it->{'itemnumber'} );
437
        $it->{'can_renew'} = $can_renew;
498
        if ($restype) {
438
        $it->{'can_confirm'} = !$can_renew && !$restype;
499
            $it->{'reserved'} = 1;
439
        $it->{'renew_error'} = $restype;
500
            $it->{$restype} = 1;
440
        $it->{'checkoutdate'} = C4::Dates->new($it->{'issuedate'},'iso')->output('syspref');
501
        }
502
        $it->{'can_renew'}    = $can_renew;
503
        $it->{'can_confirm'}  = !$can_renew && !$restype;
504
        $it->{'renew_error'}  = $restype;
505
        $it->{'checkoutdate'} = $it->{'issuedate'};
441
506
442
        $totalprice += $it->{'replacementprice'};
507
        $totalprice += $it->{'replacementprice'};
443
        $it->{'itemtype'} = $itemtypeinfo->{'description'};
508
        $it->{'itemtype'}       = $itemtypeinfo->{'description'};
444
        $it->{'itemtype_image'} = $itemtypeinfo->{'imageurl'};
509
        $it->{'itemtype_image'} = $itemtypeinfo->{'imageurl'};
445
        $it->{'dd'} = format_date($it->{'date_due'});
446
        $it->{'displaydate'} = format_date($it->{'issuedate'});
447
        $it->{'od'} = ( $it->{'date_due'} lt $todaysdate ) ? 1 : 0 ;
510
        $it->{'od'} = ( $it->{'date_due'} lt $todaysdate ) ? 1 : 0 ;
448
        ($it->{'author'} eq '') and $it->{'author'} = ' ';
511
        $it->{'dd'}             = format_date( $it->{'date_due'} );
449
        $it->{'renew_failed'} = $renew_failed{$it->{'itemnumber'}};
512
        $it->{'displaydate'}    = format_date( $it->{'issuedate'} );
450
513
        ( $it->{'author'} eq '' ) and $it->{'author'} = ' ';
451
        if ( $todaysdate eq $it->{'issuedate'} or $todaysdate eq $it->{'lastreneweddate'} ) {
514
        if ( defined( $return_failed{ $it->{'itemnumber'} } ) ) {
452
            (!$relatives) ? push @todaysissues, $it : push @relissues, $it;
515
            $it->{ 'return_error_' . $return_failed{ $it->{'itemnumber'} }->{message} } = 1;
453
        } else {
516
            delete $return_failed{ $it->{'itemnumber'} };
454
            (!$relatives) ? push @previousissues, $it : push @relprevissues, $it;
517
        }
518
        if ( defined( $renew_failed{ $it->{'itemnumber'} } ) ) {
519
            $it->{ 'renew_error_' . $renew_failed{ $it->{'itemnumber'} }->{message} } = 1;
455
        }
520
        }
521
        $it->{'return_failed'} = defined( $return_failed{ $it->{'itemnumber'} } );
522
        $it->{'branchdisplay'} = GetBranchName( ( C4::Context->preference('HomeOrHoldingBranch') eq 'holdingbranch' ) ? $it->{'holdingbranch'} : $it->{'homebranch'} );
523
524
        # ADDED BY JF: NEW ITEMTYPE COUNT DISPLAY
525
        $issued_itemtypes_count->{ $it->{'itemtype'} }++;
526
	if ( $todaysdate eq $it->{'checkoutdate'} or $todaysdate eq $it->{'lastreneweddate'} ) {
527
	    (!$relatives) ? push @todaysissues, $it : push @relissues, $it;
528
	} else {
529
	    (!$relatives) ? push @previousissues, $it : push @relprevissues, $it;
530
	}
531
456
    }
532
    }
457
}
533
}
458
534
Lines 484-490 if ($borrower) { Link Here
484
        @previousissues = sort { $b->{'date_due'} cmp $a->{'date_due'} } @previousissues;
560
        @previousissues = sort { $b->{'date_due'} cmp $a->{'date_due'} } @previousissues;
485
    }
561
    }
486
}
562
}
563
my @reserveswaiting;
564
foreach my $itemnumber (keys %return_failed){
565
   next unless $return_failed{$itemnumber}->{'reservesdata'};
566
   my $hashdata=$return_failed{$itemnumber}->{'reservesdata'};
567
   $hashdata->{circborrowernumber}=$borrowernumber;
568
   $hashdata->{script_name}=$query->script_name();
569
   push @reserveswaiting, $hashdata if (%$hashdata);
570
}
571
572
$template->param(reserves_waiting=>\@reserveswaiting);
573
574
#### ADDED BY JF FOR COUNTS BY ITEMTYPE RULES
575
# FIXME: This should utilize all the issuingrules options rather than just the defaults
576
# and it should be moved to a module
577
578
# how many of each is allowed?
579
my $issueqty_sth = $dbh->prepare(
580
    'SELECT itemtypes.description AS description,issuingrules.itemtype,maxissueqty ' .
581
    'FROM issuingrules LEFT JOIN itemtypes ON (itemtypes.itemtype=issuingrules.itemtype) ' .
582
    'WHERE categorycode=?'
583
);
584
$issueqty_sth->execute(q{*}); # This is a literal asterisk, not a wildcard.
487
585
586
while ( my $data = $issueqty_sth->fetchrow_hashref() ) {
587
588
    # subtract how many of each this borrower has
589
    $data->{'count'} = $issued_itemtypes_count->{ $data->{'description'} };  
590
    $data->{'left'}  =
591
      ( $data->{'maxissueqty'} -
592
          $issued_itemtypes_count->{ $data->{'description'} } );
593
594
    # can't have a negative number of remaining
595
    if ( $data->{'left'} < 0 ) { $data->{'left'} = '0' }
596
    if ( $data->{maxissueqty} <= $data->{count} ) {
597
        $data->{flag} = 1;
598
    }
599
    if ( $data->{maxissueqty} > 0 && $data->{itemtype} !~m/^(\*|CIRC)$/ ) {
600
        push @issued_itemtypes_count_loop, $data;
601
    }
602
}
603
604
#### / JF
488
605
489
my @values;
606
my @values;
490
my %labels;
607
my %labels;
Lines 514-519 if ($borrowerslist) { Link Here
514
631
515
#title
632
#title
516
my $flags = $borrower->{'flags'};
633
my $flags = $borrower->{'flags'};
634
    $debug && warn Dump($flags);
517
foreach my $flag ( sort keys %$flags ) {
635
foreach my $flag ( sort keys %$flags ) {
518
    $template->param( flagged=> 1);
636
    $template->param( flagged=> 1);
519
    $flags->{$flag}->{'message'} =~ s#\n#<br />#g;
637
    $flags->{$flag}->{'message'} =~ s#\n#<br />#g;
Lines 523-542 foreach my $flag ( sort keys %$flags ) { Link Here
523
            noissues => 'true',
641
            noissues => 'true',
524
        );
642
        );
525
        if ( $flag eq 'GNA' ) {
643
        if ( $flag eq 'GNA' ) {
526
            $template->param( gna => 'true' );
644
            $template->param( gna => 'true', gonenoaddresscomment => $borrower->{'gonenoaddresscomment'}, warning => 1 );
527
        }
645
        }
528
        elsif ( $flag eq 'LOST' ) {
646
        elsif ( $flag eq 'LOST' ) {
529
            $template->param( lost => 'true' );
647
            $template->param( lost => 'true', lostcomment => $borrower->{'lostcomment'}, warning => 1 );
530
        }
648
        } elsif ( $flag eq 'DEBARRED' ) {
531
        elsif ( $flag eq 'DBARRED' ) {
649
            $template->param( userdebarred => 'true', warning => 1, userdebarreddate=> format_date($flags->{DEBARRED}->{dateend}),debardebarredcomment=>$borrower->{'debarredcomment'});
532
            $template->param( dbarred => 'true' );
650
        } elsif ( $flag eq 'CHARGES' ) {
533
        }
534
        elsif ( $flag eq 'CHARGES' ) {
535
            $template->param(
651
            $template->param(
536
                charges    => 'true',
652
                charges    => 'true',
537
                chargesmsg => $flags->{'CHARGES'}->{'message'},
653
                chargesmsg => $flags->{'CHARGES'}->{'message'},
538
                chargesamount => $flags->{'CHARGES'}->{'amount'},
654
                chargesamount => $flags->{'CHARGES'}->{'amount'},
539
                charges_is_blocker => 1
655
                charges_is_blocker => 1,
656
                warning => 1
540
            );
657
            );
541
        }
658
        }
542
        elsif ( $flag eq 'CREDITS' ) {
659
        elsif ( $flag eq 'CREDITS' ) {
Lines 544-549 foreach my $flag ( sort keys %$flags ) { Link Here
544
                credits    => 'true',
661
                credits    => 'true',
545
                creditsmsg => $flags->{'CREDITS'}->{'message'},
662
                creditsmsg => $flags->{'CREDITS'}->{'message'},
546
                creditsamount => sprintf("%.02f", -($flags->{'CREDITS'}->{'amount'})), # from patron's pov
663
                creditsamount => sprintf("%.02f", -($flags->{'CREDITS'}->{'amount'})), # from patron's pov
664
		        warning => 1
547
            );
665
            );
548
        }
666
        }
549
    }
667
    }
Lines 554-559 foreach my $flag ( sort keys %$flags ) { Link Here
554
                flagged    => 1,
672
                flagged    => 1,
555
                chargesmsg => $flags->{'CHARGES'}->{'message'},
673
                chargesmsg => $flags->{'CHARGES'}->{'message'},
556
                chargesamount => $flags->{'CHARGES'}->{'amount'},
674
                chargesamount => $flags->{'CHARGES'}->{'amount'},
675
                warning => 1
557
            );
676
            );
558
        }
677
        }
559
        elsif ( $flag eq 'CREDITS' ) {
678
        elsif ( $flag eq 'CREDITS' ) {
Lines 561-573 foreach my $flag ( sort keys %$flags ) { Link Here
561
                credits    => 'true',
680
                credits    => 'true',
562
                creditsmsg => $flags->{'CREDITS'}->{'message'},
681
                creditsmsg => $flags->{'CREDITS'}->{'message'},
563
                creditsamount => sprintf("%.02f", -($flags->{'CREDITS'}->{'amount'})), # from patron's pov
682
                creditsamount => sprintf("%.02f", -($flags->{'CREDITS'}->{'amount'})), # from patron's pov
683
		warning => 1
564
            );
684
            );
565
        }
685
        }
566
        elsif ( $flag eq 'ODUES' ) {
686
        elsif ( $flag eq 'ODUES' ) {
567
            $template->param(
687
            $template->param(
568
                odues    => 'true',
688
                odues    => 'true',
569
                flagged  => 1,
689
                flagged  => 1,
570
                oduesmsg => $flags->{'ODUES'}->{'message'}
690
                oduesmsg => $flags->{'ODUES'}->{'message'},
691
                warning => 1
571
            );
692
            );
572
693
573
            my $items = $flags->{$flag}->{'itemlist'};
694
            my $items = $flags->{$flag}->{'itemlist'};
Lines 624-630 if($bor_messages_loop){ $template->param(flagged => 1 ); } Link Here
624
745
625
# Computes full borrower address
746
# Computes full borrower address
626
my (undef, $roadttype_hashref) = &GetRoadTypes();
747
my (undef, $roadttype_hashref) = &GetRoadTypes();
627
my $address = $borrower->{'streetnumber'}.' '.$roadttype_hashref->{$borrower->{'streettype'}}.' '.$borrower->{'address'};
748
749
my $address = $borrower->{'streetnumber'}.' ' if ($borrower->{'streetnumber'});
750
$address    .= $roadttype_hashref->{$borrower->{'streettype'}}.' ' if ( $roadttype_hashref->{$borrower->{'streettype'}});
751
$address    .= $borrower->{'address'};
752
753
$duedatespec = "" if not ($stickyduedate or scalar $confirm_required);
754
my @categories = C4::Category->all;
628
755
629
my $fast_cataloging = 0;
756
my $fast_cataloging = 0;
630
    if (defined getframeworkinfo('FA')) {
757
    if (defined getframeworkinfo('FA')) {
Lines 644-650 $template->param( Link Here
644
    printername       => $printer,
771
    printername       => $printer,
645
    firstname         => $borrower->{'firstname'},
772
    firstname         => $borrower->{'firstname'},
646
    surname           => $borrower->{'surname'},
773
    surname           => $borrower->{'surname'},
647
    dateexpiry        => format_date($newexpiry),
774
    printer                     => $printer,
775
    printername                 => $printer,
648
    expiry            => format_date($borrower->{'dateexpiry'}),
776
    expiry            => format_date($borrower->{'dateexpiry'}),
649
    categorycode      => $borrower->{'categorycode'},
777
    categorycode      => $borrower->{'categorycode'},
650
    categoryname      => $borrower->{description},
778
    categoryname      => $borrower->{description},
Lines 679-686 $template->param( Link Here
679
    circview => 1,
807
    circview => 1,
680
    soundon           => C4::Context->preference("SoundOn"),
808
    soundon           => C4::Context->preference("SoundOn"),
681
    fast_cataloging   => $fast_cataloging,
809
    fast_cataloging   => $fast_cataloging,
810
    categoryloop      => \@categories,
682
);
811
);
683
812
813
$template->param(newexpiry => format_date($newexpiry)) if (defined $newexpiry);
814
684
# save stickyduedate to session
815
# save stickyduedate to session
685
if ($stickyduedate) {
816
if ($stickyduedate) {
686
    $session->param( 'stickyduedate', $duedatespec );
817
    $session->param( 'stickyduedate', $duedatespec );
(-)a/circ/returns.pl (-33 / +97 lines)
Lines 37-50 use C4::Circulation; Link Here
37
use C4::Dates qw/format_date/;
37
use C4::Dates qw/format_date/;
38
use Date::Calc qw/Add_Delta_Days/;
38
use Date::Calc qw/Add_Delta_Days/;
39
use C4::Calendar;
39
use C4::Calendar;
40
use C4::Budgets qw/GetCurrency/;
40
use C4::Print;
41
use C4::Print;
41
use C4::Reserves;
42
use C4::Reserves;
42
use C4::Biblio;
43
use C4::Biblio;
43
use C4::Items;
44
use C4::Items;
44
use C4::Members;
45
use C4::Members;
46
use C4::Overdues qw/CheckBorrowerDebarred/;
45
use C4::Branch; # GetBranches GetBranchName
47
use C4::Branch; # GetBranches GetBranchName
46
use C4::Koha;   # FIXME : is it still useful ?
48
use C4::Koha;   # FIXME : is it still useful ?
47
use C4::RotatingCollections;
49
use C4::RotatingCollections;
50
use C4::Debug;
48
51
49
my $query = new CGI;
52
my $query = new CGI;
50
53
Lines 134-139 if ( $query->param('resbarcode') ) { Link Here
134
    my $item           = $query->param('itemnumber');
137
    my $item           = $query->param('itemnumber');
135
    my $borrowernumber = $query->param('borrowernumber');
138
    my $borrowernumber = $query->param('borrowernumber');
136
    my $resbarcode     = $query->param('resbarcode');
139
    my $resbarcode     = $query->param('resbarcode');
140
    my $reservenumber = $query->param('reservenumber');
137
    my $diffBranchReturned = $query->param('diffBranch');
141
    my $diffBranchReturned = $query->param('diffBranch');
138
    my $iteminfo   = GetBiblioFromItemNumber($item);
142
    my $iteminfo   = GetBiblioFromItemNumber($item);
139
    # fix up item type for display
143
    # fix up item type for display
Lines 141-158 if ( $query->param('resbarcode') ) { Link Here
141
    my $diffBranchSend = ($userenv_branch ne $diffBranchReturned) ? $diffBranchReturned : undef;
145
    my $diffBranchSend = ($userenv_branch ne $diffBranchReturned) ? $diffBranchReturned : undef;
142
# diffBranchSend tells ModReserveAffect whether document is expected in this library or not,
146
# diffBranchSend tells ModReserveAffect whether document is expected in this library or not,
143
# i.e., whether to apply waiting status
147
# i.e., whether to apply waiting status
144
    ModReserveAffect( $item, $borrowernumber, $diffBranchSend);
148
    ModReserveAffect( $item, $borrowernumber, $diffBranchSend, $reservenumber );
149
145
#   check if we have other reserves for this document, if we have a return send the message of transfer
150
#   check if we have other reserves for this document, if we have a return send the message of transfer
146
    my ( $messages, $nextreservinfo ) = GetOtherReserves($item);
151
    my ( $reservemessages, $nextreservinfo ) = GetOtherReserves($item);
147
152
148
    my ($borr) = GetMemberDetails( $nextreservinfo, 0 );
153
    my ($borr) = GetMemberDetails( $nextreservinfo, 0 );
149
    my $name   = $borr->{'surname'} . ", " . $borr->{'title'} . " " . $borr->{'firstname'};
154
    my $name   = $borr->{'surname'} . ", " . $borr->{'title'} . " " . $borr->{'firstname'};
150
    if ( $messages->{'transfert'} ) {
155
    if ( $reservemessages->{'transfert'} ) {
151
        $template->param(
156
        $template->param(
152
            itemtitle      => $iteminfo->{'title'},
157
            itemtitle      => $iteminfo->{'title'},
153
            itembiblionumber => $iteminfo->{'biblionumber'},
158
            itembiblionumber => $iteminfo->{'biblionumber'},
154
            iteminfo       => $iteminfo->{'author'},
159
            iteminfo       => $iteminfo->{'author'},
155
            tobranchname   => GetBranchName($messages->{'transfert'}),
160
            tobranchname   => GetBranchName($reservemessages->{'transfert'}),
156
            name           => $name,
161
            name           => $name,
157
            borrowernumber => $borrowernumber,
162
            borrowernumber => $borrowernumber,
158
            borcnum        => $borr->{'cardnumber'},
163
            borcnum        => $borr->{'cardnumber'},
Lines 168-179 my $returned = 0; Link Here
168
my $messages;
173
my $messages;
169
my $issueinformation;
174
my $issueinformation;
170
my $itemnumber;
175
my $itemnumber;
176
my $biblio;
171
my $barcode     = $query->param('barcode');
177
my $barcode     = $query->param('barcode');
172
my $exemptfine  = $query->param('exemptfine');
178
my $exemptfine  = $query->param('exemptfine');
173
my $dropboxmode = $query->param('dropboxmode');
179
my $dropboxmode = $query->param('dropboxmode');
174
my $dotransfer  = $query->param('dotransfer');
180
my $dotransfer  = $query->param('dotransfer');
175
my $canceltransfer = $query->param('canceltransfer');
181
my $canceltransfer = $query->param('canceltransfer');
176
my $dest = $query->param('dest');
182
my $dest = $query->param('dest');
183
my $override    = $query->param('override');
177
my $calendar    = C4::Calendar->new( branchcode => $userenv_branch );
184
my $calendar    = C4::Calendar->new( branchcode => $userenv_branch );
178
#dropbox: get last open day (today - 1)
185
#dropbox: get last open day (today - 1)
179
my $today       = C4::Dates->new();
186
my $today       = C4::Dates->new();
Lines 198-204 if ($canceltransfer){ Link Here
198
}
205
}
199
206
200
# actually return book and prepare item table.....
207
# actually return book and prepare item table.....
201
if ($barcode) {
208
if ($barcode and not $query->param('cancel')) {
202
    $barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace
209
    $barcode =~ s/^\s*|\s*$//g; # remove leading/trailing whitespace
203
    $barcode = barcodedecode($barcode) if C4::Context->preference('itemBarcodeInputFilter');
210
    $barcode = barcodedecode($barcode) if C4::Context->preference('itemBarcodeInputFilter');
204
    $itemnumber = GetItemnumberFromBarcode($barcode);
211
    $itemnumber = GetItemnumberFromBarcode($barcode);
Lines 221-231 if ($barcode) { Link Here
221
# save the return
228
# save the return
222
#
229
#
223
    ( $returned, $messages, $issueinformation, $borrower ) =
230
    ( $returned, $messages, $issueinformation, $borrower ) =
224
      AddReturn( $barcode, $userenv_branch, $exemptfine, $dropboxmode);     # do the return
231
      AddReturn( $barcode, $userenv_branch, $exemptfine, $dropboxmode,$override);     # do the return
225
    my $homeorholdingbranchreturn = C4::Context->preference('HomeOrHoldingBranchReturn') or 'homebranch';
232
    my $homeorholdingbranchreturn = C4::Context->preference('HomeOrHoldingBranchReturn') or 'homebranch';
226
233
227
    # get biblio description
234
    # get biblio description
228
    my $biblio = GetBiblioFromItemNumber($itemnumber);
235
    $biblio = GetBiblioFromItemNumber($itemnumber);
229
    # fix up item type for display
236
    # fix up item type for display
230
    $biblio->{'itemtype'} = C4::Context->preference('item-level_itypes') ? $biblio->{'itype'} : $biblio->{'itemtype'};
237
    $biblio->{'itemtype'} = C4::Context->preference('item-level_itypes') ? $biblio->{'itype'} : $biblio->{'itemtype'};
231
238
Lines 283-289 if ($barcode) { Link Here
283
            }
290
            }
284
        }
291
        }
285
    }
292
    }
286
    elsif ( !$messages->{'BadBarcode'} ) {
293
    elsif ( !$messages->{'BadBarcode'} and ! $messages->{'Wrongbranch'} ) {
287
        $input{duedate}   = 0;
294
        $input{duedate}   = 0;
288
        $returneditems{0} = $barcode;
295
        $returneditems{0} = $barcode;
289
        $riduedate{0}     = 0;
296
        $riduedate{0}     = 0;
Lines 301-306 if ($barcode) { Link Here
301
}
308
}
302
$template->param( inputloop => \@inputloop );
309
$template->param( inputloop => \@inputloop );
303
310
311
312
# Is there a circulation note?
313
my $itemnumber = GetItemnumberFromBarcode($barcode);
314
my $biblionumber = GetBiblionumberFromItemnumber($itemnumber);
315
my $record = GetMarcBiblio($biblionumber);
316
my $frameworkcode = GetFrameworkCode($biblionumber);
317
my $circnotefield = GetRecordValue('circnote', $record, $frameworkcode);
318
if (defined @$circnotefield[0]) {
319
   $template->param(circnote => @$circnotefield[0]->{'subfield'});
320
}
321
322
304
my $found    = 0;
323
my $found    = 0;
305
my $waiting  = 0;
324
my $waiting  = 0;
306
my $reserved = 0;
325
my $reserved = 0;
Lines 324-332 if ( $messages->{'NeedsTransfer'} ){ Link Here
324
}
343
}
325
344
326
if ( $messages->{'Wrongbranch'} ){
345
if ( $messages->{'Wrongbranch'} ){
327
    $template->param(
346
	$template->param(
328
        wrongbranch => 1,
347
		wrongbranch => $branches->{$messages->{'Wrongbranch'}->{'Wrongbranch'}}->{'branchname'},
329
    );
348
		rightbranch => $branches->{$messages->{'Wrongbranch'}->{'Rightbranch'}}->{'branchname'},
349
		barcode     => $barcode,
350
		exemptfine  => $exemptfine,
351
		dropboxmode => $dropboxmode,
352
	);
330
}
353
}
331
354
332
# case of wrong transfert, if the document wasn't transfered to the right library (according to branchtransfer (tobranch) BDD)
355
# case of wrong transfert, if the document wasn't transfered to the right library (according to branchtransfer (tobranch) BDD)
Lines 382-388 if ( $messages->{'ResFound'}) { Link Here
382
                reserved     => 1,
405
                reserved     => 1,
383
            );
406
            );
384
        }
407
        }
385
408
        my $debarred = CheckBorrowerDebarred($reserve->{borrowernumber});
386
        # same params for Waiting or Reserved
409
        # same params for Waiting or Reserved
387
        $template->param(
410
        $template->param(
388
            found          => 1,
411
            found          => 1,
Lines 399-415 if ( $messages->{'ResFound'}) { Link Here
399
            borcity        => $borr->{'city'},
422
            borcity        => $borr->{'city'},
400
            borzip         => $borr->{'zipcode'},
423
            borzip         => $borr->{'zipcode'},
401
            borcnum        => $borr->{'cardnumber'},
424
            borcnum        => $borr->{'cardnumber'},
402
            debarred       => $borr->{'debarred'},
425
            debarred       => $debarred,
403
            gonenoaddress  => $borr->{'gonenoaddress'},
426
            gonenoaddress  => $borr->{'gonenoaddress'},
404
            barcode        => $barcode,
427
            barcode        => $barcode,
405
            destbranch     => $reserve->{'branchcode'},
428
            reservenumber  => $reserve->{'reservenumber'},
429
            destbranch	   => $reserve->{'branchcode'},
406
            borrowernumber => $reserve->{'borrowernumber'},
430
            borrowernumber => $reserve->{'borrowernumber'},
407
            itemnumber     => $reserve->{'itemnumber'},
431
            itemnumber     => $reserve->{'itemnumber'},
408
            reservenotes   => $reserve->{'reservenotes'},
432
            reservenotes   => $reserve->{'reservenotes'},
409
        );
433
        );
410
    } # else { ; }  # error?
434
    } # else { ; }  # error?
411
}
435
}
412
436
$borrower->{'flags'}= C4::Members::patronflags($borrower);
413
# Error Messages
437
# Error Messages
414
my @errmsgloop;
438
my @errmsgloop;
415
foreach my $code ( keys %$messages ) {
439
foreach my $code ( keys %$messages ) {
Lines 435-440 foreach my $code ( keys %$messages ) { Link Here
435
    elsif ( $code eq 'WasTransfered' ) {
459
    elsif ( $code eq 'WasTransfered' ) {
436
        ;    # FIXME... anything to do here?
460
        ;    # FIXME... anything to do here?
437
    }
461
    }
462
    elsif ( $code eq 'NotForLoan' ) {
463
        my $fw               = GetFrameworkCode($biblio->{'biblionumber'});
464
        my $category         = GetAuthValCode('items.notforloan',$fw);
465
        my $authorizedvalues = GetAuthorisedValues($category, $messages->{$code});
466
467
        foreach my $authvalue (@$authorizedvalues){
468
            $err{notforloan} = $authvalue->{lib} if $authvalue->{'authorised_value'} eq $messages->{$code};
469
        }
470
    }
471
    elsif ( $code eq 'Damaged' ) {
472
        my $fw               = GetFrameworkCode($biblio->{'biblionumber'});
473
        my $category         = GetAuthValCode('items.damaged',$fw);
474
        my $authorizedvalues = GetAuthorisedValues($category, $messages->{$code});
475
476
        foreach my $authvalue (@$authorizedvalues){
477
            $err{damaged} = $authvalue->{lib} if $authvalue->{'authorised_value'} eq $messages->{$code};
478
        }
479
    }
480
    elsif( $code eq 'Debarred' ){
481
        $err{debarred}            = format_date($messages->{'Debarred'});
482
        $err{debarcardnumber}     = $borrower->{cardnumber};
483
        $err{debarborrowernumber} = $borrower->{borrowernumber};
484
        $err{debarname}           = "$borrower->{firstname} $borrower->{surname}";
485
    }
486
    elsif( $code eq 'HaveFines' ){
487
        $err{havefines}       = $borrower->{'flags'}->{'CHARGES'}->{'amount'} . %{GetCurrency()}->{symbol};
488
        $err{finecardnumber} = $borrower->{cardnumber};
489
        $err{finename}       = "$borrower->{firstname} $borrower->{surname}";
490
    }
438
    elsif ( $code eq 'wthdrawn' ) {
491
    elsif ( $code eq 'wthdrawn' ) {
439
        $err{withdrawn} = 1;
492
        $err{withdrawn} = 1;
440
        $exit_required_p = 1;
493
        $exit_required_p = 1;
Lines 456-462 foreach my $code ( keys %$messages ) { Link Here
456
    }
509
    }
457
    elsif ( $code eq 'Wrongbranch' ) {
510
    elsif ( $code eq 'Wrongbranch' ) {
458
    }
511
    }
459
460
    else {
512
    else {
461
        die "Unknown error code $code";    # note we need all the (empty) elsif's above, or we die.
513
        die "Unknown error code $code";    # note we need all the (empty) elsif's above, or we die.
462
        # This forces the issue of staying in sync w/ Circulation.pm
514
        # This forces the issue of staying in sync w/ Circulation.pm
Lines 470-483 $template->param( errmsgloop => \@errmsgloop ); Link Here
470
522
471
# patrontable ....
523
# patrontable ....
472
if ($borrower) {
524
if ($borrower) {
473
    my $flags = $borrower->{'flags'};
474
    my @flagloop;
525
    my @flagloop;
475
    my $flagset;
526
    my $flags=$borrower->{flags};
476
    foreach my $flag ( sort keys %$flags ) {
527
    foreach my $flag ( sort keys %$flags ) {
477
        my %flaginfo;
528
        my %flaginfo;
478
        unless ($flagset) { $flagset = 1; }
479
        $flaginfo{redfont} = ( $flags->{$flag}->{'noissues'} );
480
        $flaginfo{flag}    = $flag;
481
        if ( $flag eq 'CHARGES' ) {
529
        if ( $flag eq 'CHARGES' ) {
482
            $flaginfo{msg}            = $flag;
530
            $flaginfo{msg}            = $flag;
483
            $flaginfo{charges}        = 1;
531
            $flaginfo{charges}        = 1;
Lines 492-505 if ($borrower) { Link Here
492
            foreach my $item (@$items) {
540
            foreach my $item (@$items) {
493
                my $biblio = GetBiblioFromItemNumber( $item->{'itemnumber'});
541
                my $biblio = GetBiblioFromItemNumber( $item->{'itemnumber'});
494
                push @waitingitemloop, {
542
                push @waitingitemloop, {
495
                    biblionum => $biblio->{'biblionumber'},
543
                    biblionumber=> $biblio->{'biblionumber'},
496
                    barcode   => $biblio->{'barcode'},
544
                    author      => $biblio->{'author'},
497
                    title     => $biblio->{'title'},
545
                    itemtype    => $item->{'ccode'},
498
                    brname    => $branches->{ $biblio->{'holdingbranch'} }->{'branchname'},
546
                    reservedate => format_date($item->{'reservedate'}),
547
                    waitingdate => format_date($item->{'waitingdate'}),
548
                    barcode     => $item->{'barcode'},
549
                    maxpickupdate=> format_date( sprintf("%d-%02d-%02d",GetMaxPickupDate($item->{'waitingdate'}, $borrower->{borrowernumber},$item ))),
550
                    title       => $biblio->{'title'},
551
                    brname      => $branches->{ $item->{'branchcode'} }->{'branchname'},
552
                    waitinghere => ($item->{'branchcode'} eq $userenv_branch)
499
                };
553
                };
500
            }
554
            }
501
            $flaginfo{itemloop} = \@waitingitemloop;
555
            $flaginfo{itemloop} = \@waitingitemloop;
502
        }
556
        }
557
        elsif ( $flag =~ /DEBARRED|LOST|GNA/ ) {
558
            if ($flag ne "GNA"){
559
                $flag=lc($flag);
560
            }
561
            else{
562
                $flag="gonenoaddress";
563
            }
564
            %flaginfo=( $flag =>1, $flag."comment"=>$borrower->{$flag."comment"},dateend=>$flags->{uc($flag)}->{dateend});
565
        }
503
        elsif ( $flag eq 'ODUES' ) {
566
        elsif ( $flag eq 'ODUES' ) {
504
            my $items = $flags->{$flag}->{'itemlist'};
567
            my $items = $flags->{$flag}->{'itemlist'};
505
            my @itemloop;
568
            my @itemloop;
Lines 525-531 if ($borrower) { Link Here
525
        push( @flagloop, \%flaginfo );
588
        push( @flagloop, \%flaginfo );
526
    }
589
    }
527
    $template->param(
590
    $template->param(
528
        flagset          => $flagset,
529
        flagloop         => \@flagloop,
591
        flagloop         => \@flagloop,
530
        riborrowernumber => $borrower->{'borrowernumber'},
592
        riborrowernumber => $borrower->{'borrowernumber'},
531
        riborcnum        => $borrower->{'cardnumber'},
593
        riborcnum        => $borrower->{'cardnumber'},
Lines 536-542 if ($borrower) { Link Here
536
}
598
}
537
599
538
#set up so only the last 8 returned items display (make for faster loading pages)
600
#set up so only the last 8 returned items display (make for faster loading pages)
539
my $returned_counter = ( C4::Context->preference('numReturnedItemsToShow') ) ? C4::Context->preference('numReturnedItemsToShow') : 8;
601
my $returned_counter = ( C4::Context->preference('numReturnedItemsToShow') ) ? C4::Context->preference('numReturnedItemsToShow') : 10;
540
my $count = 0;
602
my $count = 0;
541
my @riloop;
603
my @riloop;
542
my $shelflocations = GetKohaAuthorisedValues('items.location','');
604
my $shelflocations = GetKohaAuthorisedValues('items.location','');
Lines 564-572 foreach ( sort { $a <=> $b } keys %returneditems ) { Link Here
564
        else {
626
        else {
565
            $ri{borrowernumber} = $riborrowernumber{$_};
627
            $ri{borrowernumber} = $riborrowernumber{$_};
566
        }
628
        }
567
568
        #        my %ri;
629
        #        my %ri;
569
        my $biblio = GetBiblioFromItemNumber(GetItemnumberFromBarcode($bar_code));
630
        my $biblio = GetBiblioFromItemNumber(GetItemnumberFromBarcode($bar_code));
631
        my $item = GetItem(GetItemnumberFromBarcode($bar_code));
570
        # fix up item type for display
632
        # fix up item type for display
571
        $biblio->{'itemtype'} = C4::Context->preference('item-level_itypes') ? $biblio->{'itype'} : $biblio->{'itemtype'};
633
        $biblio->{'itemtype'} = C4::Context->preference('item-level_itypes') ? $biblio->{'itype'} : $biblio->{'itemtype'};
572
        $ri{itembiblionumber} = $biblio->{'biblionumber'};
634
        $ri{itembiblionumber} = $biblio->{'biblionumber'};
Lines 575-588 foreach ( sort { $a <=> $b } keys %returneditems ) { Link Here
575
        $ri{itemcallnumber}   = $biblio->{'itemcallnumber'};
637
        $ri{itemcallnumber}   = $biblio->{'itemcallnumber'};
576
        $ri{itemtype}         = $biblio->{'itemtype'};
638
        $ri{itemtype}         = $biblio->{'itemtype'};
577
        $ri{itemnote}         = $biblio->{'itemnotes'};
639
        $ri{itemnote}         = $biblio->{'itemnotes'};
578
        $ri{ccode}            = $biblio->{'ccode'};
579
        $ri{itemnumber}       = $biblio->{'itemnumber'};
640
        $ri{itemnumber}       = $biblio->{'itemnumber'};
641
        $ri{itemtype}         = $item->{'itype'};
642
        $ri{ccode}            = $item->{'ccode'};
643
        $ri{itemcallnumber}   = $item->{'itemcallnumber'};
644
        $ri{homebranch}       = $item->{'homebranch'};
645
        $ri{holdingbranch}    = $item->{'holdingbranch'};
580
        $ri{barcode}          = $bar_code;
646
        $ri{barcode}          = $bar_code;
581
647
582
        $ri{location}         = $biblio->{'location'};
648
        my $shelflocations    = GetKohaAuthorisedValues('items.location','');
583
        my $shelfcode = $ri{'location'};
649
        $ri{itemlocation}     = $shelflocations->{$biblio->{'location'}};
584
        $ri{'location'} = $shelflocations->{$shelfcode} if ( defined( $shelfcode ) && defined($shelflocations) && exists( $shelflocations->{$shelfcode} ) );
585
586
    }
650
    }
587
    else {
651
    else {
588
        last;
652
        last;
(-)a/installer/data/mysql/de-DE/mandatory/sysprefs.sql (-1 / +1 lines)
Lines 314-317 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
314
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHiddenItems' ,'','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/O    pacHiddenItems.txt for more informations.','','Textarea');
314
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHiddenItems' ,'','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/O    pacHiddenItems.txt for more informations.','','Textarea');
315
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
315
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
316
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
316
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
317
317
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('ReservesControlBranch','PatronLibrary','Which branch to use do check holds limits','ItemHomeLibrary|PatronLibrary','Choice');    
(-)a/installer/data/mysql/en/mandatory/sysprefs.sql (-1 / +2 lines)
Lines 313-316 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
313
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('AlternateHoldingsSeparator','','The string to use to separate subfields in alternate holdings displays.',NULL,'free');
313
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('AlternateHoldingsSeparator','','The string to use to separate subfields in alternate holdings displays.',NULL,'free');
314
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/OpacHiddenItems.txt for more informations.','','Textarea');
314
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/OpacHiddenItems.txt for more informations.','','Textarea');
315
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
315
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
316
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
316
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
317
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('ReservesControlBranch','PatronLibrary','Which branch to use do check holds limits','ItemHomeLibrary|PatronLibrary','Choice');    
(-)a/installer/data/mysql/fr-FR/1-Obligatoire/unimarc_standard_systemprefs.sql (-1 / +1 lines)
Lines 315-318 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
315
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/OpacHiddenItems.txt for more informations.','','Textarea');
315
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/OpacHiddenItems.txt for more informations.','','Textarea');
316
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
316
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
317
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
317
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
318
318
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('ReservesControlBranch','PatronLibrary','Which branch to use do check holds limits','ItemHomeLibrary|PatronLibrary','Choice');    
(-)a/installer/data/mysql/it-IT/necessari/sysprefs.sql (+1 lines)
Lines 301-303 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
301
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/O    pacHiddenItems.txt for more informations.','','Textarea');
301
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/O    pacHiddenItems.txt for more informations.','','Textarea');
302
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
302
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
303
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
303
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
304
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('ReservesControlBranch','PatronLibrary','Which branch to use do check holds limits','ItemHomeLibrary|PatronLibrary','Choice');    
(-)a/installer/data/mysql/kohastructure.sql (-3 / +11 lines)
Lines 974-982 CREATE TABLE `issuingrules` ( Link Here
974
  `maxissueqty` int(4) default NULL,
974
  `maxissueqty` int(4) default NULL,
975
  `issuelength` int(4) default NULL,
975
  `issuelength` int(4) default NULL,
976
  `hardduedate` date default NULL,
976
  `hardduedate` date default NULL,
977
  `hardduedatecompare` tinyint NOT NULL default "0",
977
  `holdspickupdelay` int(11) default NULL,
978
  `renewalsallowed` smallint(6) NOT NULL default "0",
978
  `renewalperiod` int(11) default NULL,
979
  `reservesallowed` smallint(6) NOT NULL default "0",
979
  `allowonshelfholds` tinyint(1) default NULL,
980
  `holdrestricted` tinyint(1) default NULL,
981
  `hardduedatecompare` tinyint NULL default "0",
982
  `renewalsallowed` smallint(6) NULL default "0",
983
  `reservesallowed` smallint(6) NULL default "0",
980
  `branchcode` varchar(10) NOT NULL default '',
984
  `branchcode` varchar(10) NOT NULL default '',
981
  PRIMARY KEY  (`branchcode`,`categorycode`,`itemtype`),
985
  PRIMARY KEY  (`branchcode`,`categorycode`,`itemtype`),
982
  KEY `categorycode` (`categorycode`),
986
  KEY `categorycode` (`categorycode`),
Lines 1362-1367 CREATE TABLE `old_issues` ( Link Here
1362
--
1366
--
1363
DROP TABLE IF EXISTS `old_reserves`;
1367
DROP TABLE IF EXISTS `old_reserves`;
1364
CREATE TABLE `old_reserves` (
1368
CREATE TABLE `old_reserves` (
1369
  `reservenumber` int(11) NOT NULL AUTO_INCREMENT,
1365
  `borrowernumber` int(11) default NULL,
1370
  `borrowernumber` int(11) default NULL,
1366
  `reservedate` date default NULL,
1371
  `reservedate` date default NULL,
1367
  `biblionumber` int(11) default NULL,
1372
  `biblionumber` int(11) default NULL,
Lines 1378-1383 CREATE TABLE `old_reserves` ( Link Here
1378
  `waitingdate` date default NULL,
1383
  `waitingdate` date default NULL,
1379
  `expirationdate` DATE DEFAULT NULL,
1384
  `expirationdate` DATE DEFAULT NULL,
1380
  `lowestPriority` tinyint(1) NOT NULL,
1385
  `lowestPriority` tinyint(1) NOT NULL,
1386
  PRIMARY KEY (`reservenumber`),
1381
  KEY `old_reserves_borrowernumber` (`borrowernumber`),
1387
  KEY `old_reserves_borrowernumber` (`borrowernumber`),
1382
  KEY `old_reserves_biblionumber` (`biblionumber`),
1388
  KEY `old_reserves_biblionumber` (`biblionumber`),
1383
  KEY `old_reserves_itemnumber` (`itemnumber`),
1389
  KEY `old_reserves_itemnumber` (`itemnumber`),
Lines 1537-1542 CREATE TABLE `reserveconstraints` ( Link Here
1537
1543
1538
DROP TABLE IF EXISTS `reserves`;
1544
DROP TABLE IF EXISTS `reserves`;
1539
CREATE TABLE `reserves` (
1545
CREATE TABLE `reserves` (
1546
  `reservenumber` int(11) NOT NULL AUTO_INCREMENT,
1540
  `borrowernumber` int(11) NOT NULL default 0,
1547
  `borrowernumber` int(11) NOT NULL default 0,
1541
  `reservedate` date default NULL,
1548
  `reservedate` date default NULL,
1542
  `biblionumber` int(11) NOT NULL default 0,
1549
  `biblionumber` int(11) NOT NULL default 0,
Lines 1553-1558 CREATE TABLE `reserves` ( Link Here
1553
  `waitingdate` date default NULL,
1560
  `waitingdate` date default NULL,
1554
  `expirationdate` DATE DEFAULT NULL,
1561
  `expirationdate` DATE DEFAULT NULL,
1555
  `lowestPriority` tinyint(1) NOT NULL,
1562
  `lowestPriority` tinyint(1) NOT NULL,
1563
  PRIMARY KEY (`reservenumber`),
1556
  KEY `borrowernumber` (`borrowernumber`),
1564
  KEY `borrowernumber` (`borrowernumber`),
1557
  KEY `biblionumber` (`biblionumber`),
1565
  KEY `biblionumber` (`biblionumber`),
1558
  KEY `itemnumber` (`itemnumber`),
1566
  KEY `itemnumber` (`itemnumber`),
(-)a/installer/data/mysql/nb-NO/1-Obligatorisk/sysprefs.sql (+1 lines)
Lines 321-323 INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ( Link Here
321
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacFavicon','','Enter a complete URL to an image to replace the default Koha favicon on the OPAC','','free');
321
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacFavicon','','Enter a complete URL to an image to replace the default Koha favicon on the OPAC','','free');
322
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('IntranetFavicon','','Enter a complete URL to an image to replace the default Koha favicon on the Staff client','','free');
322
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('IntranetFavicon','','Enter a complete URL to an image to replace the default Koha favicon on the Staff client','','free');
323
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('TraceSubjectSubdivisions', '0', 'Create searches on all subdivisions for subject tracings.','1','YesNo');
323
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('TraceSubjectSubdivisions', '0', 'Create searches on all subdivisions for subject tracings.','1','YesNo');
324
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('ReservesControlBranch','PatronLibrary','Which branch to use do check holds limits','ItemHomeLibrary|PatronLibrary','Choice');    
(-)a/installer/data/mysql/pl-PL/mandatory/sysprefs.sql (-1 / +1 lines)
Lines 313-316 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
313
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/OpacHiddenItems.txt for more informations.','','Textarea');
313
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/OpacHiddenItems.txt for more informations.','','Textarea');
314
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
314
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
315
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
315
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
316
316
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('ReservesControlBranch','PatronLibrary','Which branch to use do check holds limits','ItemHomeLibrary|PatronLibrary','Choice');    
(-)a/installer/data/mysql/ru-RU/mandatory/system_preferences_full_optimal_for_install_only.sql (-1 / +1 lines)
Lines 368-371 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
368
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/OpacHiddenItems.txt for more informations.','','Textarea');
368
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/OpacHiddenItems.txt for more informations.','','Textarea');
369
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
369
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
370
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
370
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
371
371
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('ReservesControlBranch','PatronLibrary','Which branch to use do check holds limits','ItemHomeLibrary|PatronLibrary','Choice');    
(-)a/installer/data/mysql/uk-UA/mandatory/system_preferences_full_optimal_for_install_only.sql (+1 lines)
Lines 393-395 INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES Link Here
393
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/O    pacHiddenItems.txt for more informations.','','Textarea');
393
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('OpacHiddenItems','','This syspref allows to define custom rules for hiding specific items at opac. See docs/opac/O    pacHiddenItems.txt for more informations.','','Textarea');
394
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
394
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES('numSearchRSSResults',50,'Specify the maximum number of results to display on a RSS page of results',NULL,'Integer');
395
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
395
INSERT INTO systempreferences (variable,value,explanation,options,type) VALUES ('OpacRenewalBranch','checkoutbranch','Choose how the branch for an OPAC renewal is recorded in statistics','itemhomebranch|patronhomebranch|checkoutbranch|null','Choice');
396
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('ReservesControlBranch','PatronLibrary','Which branch to use do check holds limits','ItemHomeLibrary|PatronLibrary','Choice');    
(-)a/installer/data/mysql/updatedatabase.pl (+53 lines)
Lines 4369-4374 if (C4::Context->preference("Version") < TransformToNum($DBversion)) { Link Here
4369
    print "Upgrade to $DBversion done (Add syspref ShowReviewerPhoto)\n";
4369
    print "Upgrade to $DBversion done (Add syspref ShowReviewerPhoto)\n";
4370
    SetVersion($DBversion);
4370
    SetVersion($DBversion);
4371
}
4371
}
4372
$DBversion = '3.05.00.005';
4373
if (C4::Context->preference("Version") < TransformToNum($DBversion)) {
4374
    $dbh->do("ALTER TABLE issuingrules ADD holdspickupdelay int(11) default NULL");
4375
    $dbh->do("ALTER TABLE issuingrules ADD renewalperiod int(11) default NULL");
4376
    $dbh->do("ALTER TABLE issuingrules ADD allowonshelfholds tinyint(1) default NULL");
4377
    $dbh->do("ALTER TABLE issuingrules ADD holdrestricted tinyint(1) default NULL");
4378
4379
    my $sth = $dbh->prepare("SELECT value from systempreferences where variable = 'AllowOnShelfHolds';");
4380
    $sth->execute();
4381
    my $data = $sth->fetchrow_hashref();
4382
            
4383
    if ($data->{value}){
4384
        my $updsth = $dbh->prepare("UPDATE issuingrules SET allowonshelfholds = ?");
4385
        $updsth->execute( $data->{value} );
4386
    }
4387
    $dbh->do(
4388
        'INSERT IGNORE INTO issuingrules (branchcode, categorycode, itemtype,holdrestricted,maxissueqty)
4389
                SELECT "*","*","*",holdallowed,maxissueqty
4390
                FROM default_circ_rules defaults
4391
              ON DUPLICATE KEY update maxissueqty=defaults.maxissueqty, holdrestricted=defaults.holdallowed'
4392
    );
4393
    $dbh->do(
4394
        'INSERT IGNORE INTO issuingrules (branchcode, itemtype, categorycode,maxissueqty)
4395
                    SELECT "*","*",categorycode,maxissueqty from default_borrower_circ_rules defaults
4396
              ON DUPLICATE KEY update maxissueqty=defaults.maxissueqty'
4397
    );
4398
    $dbh->do(
4399
        'INSERT IGNORE INTO issuingrules (branchcode, categorycode, itemtype,holdrestricted,maxissueqty)
4400
                    SELECT branchcode,"*","*",holdallowed,maxissueqty from default_branch_circ_rules defaults
4401
              ON DUPLICATE KEY update maxissueqty=defaults.maxissueqty, holdrestricted=defaults.holdallowed'
4402
    );
4403
    $dbh->do(
4404
        'INSERT IGNORE INTO issuingrules (branchcode, categorycode, itemtype,holdrestricted)
4405
                    SELECT "*","*",itemtype,holdallowed from default_branch_item_rules defaults 
4406
              ON DUPLICATE KEY update holdrestricted=defaults.holdallowed'
4407
    );
4408
    $dbh->do('ALTER TABLE issuingrules CHANGE reservesallowed reservesallowed smallint(6) NULL');
4409
    $dbh->do('ALTER TABLE issuingrules CHANGE renewalsallowed renewalsallowed smallint(6) NULL');
4410
#    for my $tablename qw(default_circ_rules default_branch_circ_rules default_branch_item_rules default_borrower_circ_rules) {
4411
#        $dbh->do("DROP TABLE $tablename");
4412
#    }
4413
4414
    $dbh->do("INSERT INTO systempreferences (variable,value, options, explanation, type) VALUES('ReservesControlBranch','PatronLibrary','ItemHomeLibrary|PatronLibrary','Which branch to use do check holds limits','Choice')");
4415
    $dbh->do(q{
4416
      ALTER TABLE reserves ADD `reservenumber` int(11) NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`reservenumber`);
4417
});
4418
    $dbh->do(q{
4419
      ALTER TABLE old_reserves ADD `reservenumber` int(11) NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`reservenumber`);
4420
});
4421
4422
    print "Upgrade to $DBversion done (Improved circulation rules : holds and renewals at granular level)\n";
4423
    SetVersion ($DBversion);
4424
}
4372
4425
4373
=head1 FUNCTIONS
4426
=head1 FUNCTIONS
4374
4427
(-)a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css (+3 lines)
Lines 2081-2083 fieldset.rows+h3 {clear:both;padding-top:.5em;} Link Here
2081
    color : #cc0000;
2081
    color : #cc0000;
2082
    }
2082
    }
2083
2083
2084
.herited {
2085
    color: #ccc;
2086
}
(-)a/koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/jeditable (+1 lines)
Line 0 Link Here
1
Subproject commit 29b70035bbd60fc9412df3a5186367034114c9b2
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/smart-rules.tt (-314 / +361 lines)
Lines 2-14 Link Here
2
<title>Koha &rsaquo; Administration &rsaquo; Circulation and Fine Rules</title>
2
<title>Koha &rsaquo; Administration &rsaquo; Circulation and Fine Rules</title>
3
[% INCLUDE 'doc-head-close.inc' %]
3
[% INCLUDE 'doc-head-close.inc' %]
4
4
5
<link href="/content/ui-lightness/jquery-ui-1.8.1.custom.css" rel="stylesheet" />
6
<script src="/scripts/jquery-ui-1.8.1.custom.min.js" type="text/javascript"></script>
7
<script type="text/javascript" src="/intranet-tmpl/prog/en/lib/jquery/plugins/jquery.uitablefilter.js"></script>
8
<script type="text/javascript" src="/intranet-tmpl/prog/en/lib/jquery/plugins/ui.tabs.js"></script>
9
<script src="/intranet-tmpl/prog/en/lib/jquery/plugins/jeditable/jquery.jeditable.js" type="text/javascript" charset="utf-8"></script>
10
<script src="/intranet-tmpl/prog/en/lib/jquery/plugins/jeditable/jquery.jeditable.datepicker.js" type="text/javascript" charset="utf-8"></script>
11
<script src="/intranet-tmpl/prog/en/lib/jquery/plugins/jeditable/js/jquery.datePicker.js" type="text/javascript" charset="utf-8"></script>
12
<script src="/intranet-tmpl/prog/en/lib/jquery/plugins/jeditable/js/date.js" type="text/javascript" charset="utf-8"></script>
13
14
<link rel="stylesheet" type="text/css" href="/intranet-tmpl/prog/en/lib/jquery/plugins/jeditable/css/datePicker.css" />
15
<link rel="stylesheet" type="text/css" href="/intranet-tmpl/prog/en/lib/jquery/plugins/ui.tabs.css" />
16
5
<script type="text/javascript">
17
<script type="text/javascript">
6
//<![CDATA[
18
//<![CDATA[
7
$(document).ready(function() {
19
$(document).ready(function() {
8
        $('#selectlibrary').find("input:submit").hide();
20
        $('#selectlibrary').find("input:submit").hide();
9
        $('#branch').change(function() {
21
        $('#branchcode').change(function() {
10
                $('#selectlibrary').submit();
22
                $('#selectlibrary').submit();
11
        });
23
        });
24
        $('#filter').keyup(function() {
25
                $.uiTableFilter( $('#smartrules'), this.value );
26
        });
27
        $('#nofilter').click(function() {
28
            $('.issues').show();
29
            $('.fines').show();
30
            $('.reserves').show();
31
            $('.issues :input').removeAttr('disabled',true);
32
            $('.fines :input').removeAttr('disabled',true);
33
            $('.reserves :input').removeAttr('disabled',true);
34
            $(this).parent().attr('class','ui-tabs-selected');
35
            $('#issuesfilter').parent().attr('class',null);
36
            $('#finesfilter').parent().attr('class',null);
37
            $('#reservesfilter').parent().attr('class',null);
38
        });
39
        $('#issuesfilter').click(function() {
40
            $('.issues').show();
41
            $('.fines').hide();
42
            $('.reserves').hide();
43
            $('.issues :input').removeAttr('disabled',true);
44
            $('.fines :input').attr('disabled',true);
45
            $('.reserves :input').attr('disabled',true);
46
            $(this).parent().attr('class','ui-tabs-selected');
47
            $('#nofilter').parent().attr('class',null);
48
            $('#finesfilter').parent().attr('class',null);
49
            $('#reservesfilter').parent().attr('class',null);
50
        });
51
        $('#finesfilter').click(function() {
52
            $('.issues').hide();
53
            $('.fines').show();
54
            $('.reserves').hide();
55
            $('.issues :input').attr('disabled',true);
56
            $('.fines :input').removeAttr('disabled',true);
57
            $('.reserves :input').attr('disabled',true);
58
            $(this).parent().attr('class','ui-tabs-selected');
59
            $('#issuesfilter').parent().attr('class',null);
60
            $('#nofilter').parent().attr('class',null);
61
            $('#reservesfilter').parent().attr('class',null);
62
        });
63
        $('#reservesfilter').click(function() {
64
            $('.issues').hide();
65
            $('.fines').hide();
66
            $('.reserves').show();
67
            $('.issues :input').attr('disabled',true);
68
            $('.fines :input').attr('disabled',true);
69
            $('.reserves :input').removeAttr('disabled',true);
70
            $(this).parent().attr('class','ui-tabs-selected');
71
            $('#issuesfilter').parent().attr('class',null);
72
            $('#finesfilter').parent().attr('class',null);
73
            $('#nofilter').parent().attr('class',null);
74
        });
75
        $('.editabledatepicker').editable('/cgi-bin/koha/admin/smart-rules-service.pl', {
76
             submitdata   : function(){
77
                    return {
78
                        branchcode   : $('#branchcode').val(),
79
                        categorycode : $(this).parent().find('td.categorycode > span:first').text(),
80
                        itemtype     : $(this).parent().find('td.itemtype > span:first').text(),
81
                        varname      : $(this).attr('varname')
82
                        };
83
                    },
84
            name         : 'inputvalue',
85
            type: 'datepicker',
86
            onblur: 'submit',
87
            tooltip: _("Click to edit....")
88
        });
89
        $('.datecompare').editable('/cgi-bin/koha/admin/smart-rules-service.pl', {
90
             submitdata   : function(){
91
                    return {
92
                        branchcode   : $('#branchcode').val(),
93
                        categorycode : $(this).parent().find('td.categorycode > span:first').text(),
94
                        itemtype     : $(this).parent().find('td.itemtype > span:first').text(),
95
                        varname      : $(this).attr('varname')
96
                        };
97
                    },
98
             name         : 'inputvalue',
99
             data   : "{'':'','1':"+_("'After'")+",'-1':"+_("'Before'")+",0:"+_("'Exactly On'")+"}",
100
             type   : 'select',
101
             submit : 'OK'
102
         });
103
        $('.editable').editable('/cgi-bin/koha/admin/smart-rules-service.pl', {
104
             submitdata   : function(){
105
                    return {
106
                        branchcode   : $('#branchcode').val(),
107
                        categorycode : $(this).parent().find('td.categorycode > span:first').text(),
108
                        itemtype     : $(this).parent().find('td.itemtype > span:first').text(),
109
                        varname      : $(this).attr('varname')
110
                        };
111
                    },
112
             name         : 'inputvalue',
113
             data: function(value, settings) {
114
                    var retval = value.replace(/^\s+/gi, '').replace(/\s+$/gi, '');
115
                    return retval;
116
            },
117
             submit : 'OK'
118
         });
119
        $('.triple').editable('/cgi-bin/koha/admin/smart-rules-service.pl', {
120
             submitdata   : function(){
121
                    return {
122
                        branchcode   : $('#branchcode').val(),
123
                        categorycode : $(this).parent().find('td.categorycode > span:first').text(),
124
                        itemtype     : $(this).parent().find('td.itemtype > span:first').text(),
125
                        varname      : $(this).attr('varname')
126
                        };
127
                    },
128
             name         : 'inputvalue',
129
             data   : "{'':'','1':"+_("'Yes'")+",'0':"+_("'No'")+"}",
130
             type   : 'select',
131
            tooltip: _("Click to edit...."),
132
             submit : 'OK'
133
         });
12
});
134
});
13
//]]>
135
//]]>
14
</script>
136
</script>
Lines 37-60 $(document).ready(function() { Link Here
37
            Defining circulation and fine rules for all libraries
159
            Defining circulation and fine rules for all libraries
38
        [% END %]
160
        [% END %]
39
    </h1>
161
    </h1>
40
    <div class="help">
162
    <div id="bloc100">
41
        <p>The rules are applied from most specific to less specific, using the first found in this order:</p>
42
        <ul>
43
            <li>same library, same patron type, same item type</li>
44
            <li>same library, same patron type, all item types</li>
45
            <li>same library, all patron types, same item type</li>
46
            <li>same library, all patron types, all item types</li>
47
            <li>all libraries, same patron type, same item type</li>
48
            <li>all libraries, same patron type, all item types</li>
49
            <li>all libraries, all patron types, same item type</li>
50
            <li>all libraries, all patron types, all item types</li>
51
        </ul>
52
        <p>To modify a rule, create a new one with the same patron type and item type.</p>
53
    </div>
54
    <div>
55
        <form method="get" action="/cgi-bin/koha/admin/smart-rules.pl" id="selectlibrary">
163
        <form method="get" action="/cgi-bin/koha/admin/smart-rules.pl" id="selectlibrary">
56
        Select a library :
164
        Select a library :
57
            <select name="branch" id="branch" style="width:20em;">
165
            <select name="branchcode" id="branchcode" style="width:20em;">
58
                <option value="*">All libraries</option>
166
                <option value="*">All libraries</option>
59
            [% FOREACH branchloo IN branchloop %]
167
            [% FOREACH branchloo IN branchloop %]
60
				[% IF ( branchloo.selected ) %]<option value="[% branchloo.value %]" selected="selected">[% branchloo.branchname %]</option>[% ELSE %]<option value="[% branchloo.value %]">[% branchloo.branchname %]</option>[% END %]
168
				[% IF ( branchloo.selected ) %]<option value="[% branchloo.value %]" selected="selected">[% branchloo.branchname %]</option>[% ELSE %]<option value="[% branchloo.value %]">[% branchloo.branchname %]</option>[% END %]
Lines 64-367 $(document).ready(function() { Link Here
64
[% IF ( definedbranch ) %]<form action="/cgi-bin/koha/admin/clone-rules.pl" method="post"><label 
172
[% IF ( definedbranch ) %]<form action="/cgi-bin/koha/admin/clone-rules.pl" method="post"><label 
65
for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidden" name="frombranch" value="[% current_branch %]" />
173
for="tobranch"><strong>Clone these rules to:</strong></label> <input type="hidden" name="frombranch" value="[% current_branch %]" />
66
            <select name="tobranch" id="tobranch">[% FOREACH branchloo IN branchloop %]<option value="[% branchloo.value %]">[% branchloo.branchname %]</option>[% END %]</select> <input type="submit" value="Clone" /></form>[% END %]</fieldset>
174
            <select name="tobranch" id="tobranch">[% FOREACH branchloo IN branchloop %]<option value="[% branchloo.value %]">[% branchloo.branchname %]</option>[% END %]</select> <input type="submit" value="Clone" /></form>[% END %]</fieldset>
67
175
        <div class="toptabs">
68
        <form method="post" action="/cgi-bin/koha/admin/smart-rules.pl">
176
            <ul class="ui-tabs-nav">
69
            <input type="hidden" name="op" value="add" />
177
                <li class="ui-tabs-selected"><a id="nofilter">All</a></li>
70
            <table>
178
                <li><a id="issuesfilter">Issues</a></li>
71
            <tr>
179
                <li><a id="finesfilter">Fines</a></li>
72
                <th>Patron Category</th>
180
                <li><a id="reservesfilter">Holds</a></li>
73
                <th>Item Type</th>
181
                <div style="text-align:right;">
74
                <th>Current Checkouts Allowed</th>
182
                    <label for="filter" style="float:none;">Filter: </label>
75
                <th>Loan Period (day)</th>
183
                    <input type="text" name="filter" id="filter" title="Dynamic filter on itemtype/patron category"/>
76
                <th>Hard Due Date</th>
184
                </div>
77
                <th>Fine Amount</th>
185
            </ul>
78
                <th>Fine Charging Interval</th>
186
            <div class="tabs-container">
79
                <th>Fine Grace period (day)</th>
187
                    <table id="smartrules" width="100%">
80
                <th>Suspension in Days (day)</th>
188
                        <thead>
81
                <th>Renewals Allowed (count)</th>
189
                            <tr>
82
                <th>Holds Allowed (count)</th>
190
                                <th>Patron category</th>
83
		        <th>Rental Discount (%)</th>
191
                                <th>Item type</th>
84
				<th>&nbsp;</th>
192
                                <th class="issues">Current checkouts allowed</th>
85
            </tr>
193
                                <th class="issues">Loan period (day)</th>
86
				[% FOREACH rule IN rules %]
194
                                <th class="issues">Hard due date compare</th>
87
					[% UNLESS ( loop.odd ) %]
195
                                <th class="issues">Hard due date</th>
88
					<tr class="highlight">
196
                                <th class="fines">Fine amount</th>
89
					[% ELSE %]
197
                                <th class="fines">Fine charging interval</th>
90
					<tr>
198
                                <th class="fines">Grace period (day)</th>
91
					[% END %]
199
                                <th class="fines">Suspension duration (day)</th>
92
							<td>[% IF ( rule.default_humancategorycode ) %]
200
                                <th class="issues">Renewals allowed (count)</th>
93
									<em>All</em>
201
                                <th class="issues">Renewals period (days)</th>
94
								[% ELSE %]
202
                                <th class="reserves">Holds allowed (count)</th>
95
									[% rule.humancategorycode %]
203
                                <th class="reserves">Holds pickup delay (day)</th>
96
								[% END %]
204
                                <th class="reserves">Allow on shelf holds</th>
97
							</td>
205
                                <th class="reserves">Holds restricted to library</th>
98
							<td>[% IF ( rule.default_humanitemtype ) %]
206
                                <th class="issues">Rental discount (%)</th>
99
									<em>All</em>
207
                                <th>&nbsp;</th>
100
								[% ELSE %]
208
                            </tr>
101
									[% rule.humanitemtype %]
209
                        </thead>
102
								[% END %]
210
                        <tbody>
103
							</td>
211
                        [% FOREACH rule IN rules %]
104
							<td>[% IF ( rule.unlimited_maxissueqty ) %]
212
                            <tr>
105
									Unlimited
213
                                    <td class="categorycode">
106
								[% ELSE %]
214
                                        <span style="display:none;">[% rule.categorycode %]</span>
107
									[% rule.maxissueqty %]
215
                                        [% IF ( rule.default_humancategorycode ) %]
108
								[% END %]
216
                                            <em>Default</em>
109
							</td>
217
                                        [% ELSE %]
110
							<td>[% rule.issuelength %]</td>
218
                                            [% rule.humancategorycode %]
111
                                                        <td>[% IF ( rule.hardduedate ) %]
219
                                        [% END %]
112
                                                               [% IF ( rule.hardduedatebefore ) %]before [% rule.hardduedate %]</td>
220
                                    </td>
113
                                                               [% ELSE %][% IF ( rule.hardduedateexact ) %]on [% rule.hardduedate %]</td>
221
                                    <td class="itemtype">
114
                                                                                 [% ELSE %][% IF ( rule.hardduedateafter ) %]after [% rule.hardduedate %]</td>[% END %]
222
                                        <span style="display:none;">[% rule.itemtype %]</span>
115
                                                                                 [% END %]
223
                                        [% IF ( rule.default_humanitemtype ) %]
116
                                                               [% END %]
224
                                            <em>Default</em>
117
                                                            [% ELSE %]None defined[% END %]   
225
                                        [% ELSE %]
118
							<td>[% rule.fine %]</td>
226
                                            [% rule.humanitemtype %]
119
							<td>[% rule.chargeperiod %]</td>
227
                                        [% END %]
120
							<td>[% rule.firstremind %]</td>
228
                                    </td>
121
							<td>[% rule.finedays %]</td>
229
                                    [% IF ( rule.herited_maxissueqty ) %]
122
							<td>[% rule.renewalsallowed %]</td>
230
                                    <td class="maxissueqty editable issues herited" varname="maxissueqty">
123
							<td>[% rule.reservesallowed %]</td>
231
                                    [% ELSE %]
124
							<td>[% rule.rentaldiscount %]</td>
232
                                    <td class="issues editable" varname="maxissueqty">
125
							<td>
233
                                    [% END %]
126
								<a class="button" href="/cgi-bin/koha/admin/smart-rules.pl?op=delete&amp;itemtype=[% rule.itemtype %]&amp;categorycode=[% rule.categorycode %]&amp;branch=[% rule.current_branch %]">Delete</a>
234
                                        [% IF ( rule.unlimited_maxissueqty ) %]
127
							</td>
235
                                            Unlimited
128
                	</tr>
236
                                        [% ELSE %]
129
            	[% END %]
237
                                            [% rule.maxissueqty %]
130
                <tr>
238
                                        [% END %]
131
                    <td>
239
                                    </td>
132
                        <select name="categorycode">
240
                                    [% IF ( rule.herited_issuelength ) %]
133
                            <option value="*">All</option>
241
                                    <td class="issuelength editable issues herited" varname="issuelength">
134
                        [% FOREACH categoryloo IN categoryloop %]
242
                                    [% ELSE %]
135
                            <option value="[% categoryloo.categorycode %]">[% categoryloo.description %]</option>
243
                                    <td class="issuelength editable issues" varname="issuelength">
136
                        [% END %]
244
                                    [% END %][% rule.issuelength %]
137
                        </select>
245
                                    </td>
138
                    </td>
246
                                    [% IF ( rule.herited_hardduedatecompare ) %]
139
                    <td>
247
                                    <td class="hardduedatecompare issues datecompare herited" varname="hardduedatecompare">
140
                        <select name="itemtype" style="width:13em;">
248
                                    [% ELSE %]
141
                            <option value="*">All</option>
249
                                    <td class="hardduedatecompare issues datecompare" varname="hardduedatecompare">
142
                        [% FOREACH itemtypeloo IN itemtypeloop %]
250
                                    [% END %]
143
                            <option value="[% itemtypeloo.itemtype %]">[% itemtypeloo.description %]</option>
251
                                    [% rule.hardduedatecompare %]
144
                        [% END %]
252
                                    </td>
145
                        </select>
253
                                    [% IF (rule.herited_hardduedate ) %]
146
                    </td>
254
                                    <td class="hardduedate editabledatepicker issues herited" varname="hardduedate">
147
                    <td><input name="maxissueqty" size="3" /></td>
255
                                    [% ELSE %]
148
                    <td><input name="issuelength" size="3" /> </td>
256
                                    <td class="hardduedate editabledatepicker issues" varname="hardduedate">
149
                    <td><select name="hardduedatecompare">
257
                                    [% END %]
150
                           <option value="-1">Before</option>
258
                                    [% rule.hardduedate %]
151
                           <option value="0">Exactly on</option>
259
                                    </td>
152
                           <option value="1">After</option>
260
                                    [% IF (rule.herited_fine ) %]
153
                        </select>
261
                                    <td class="fine editable fines herited" varname="fine">
154
                        <input type="text" size="10" id="hardduedate" name="hardduedate" value="[% hardduedate %]" />
262
                                    [% ELSE %]
155
                        [% INCLUDE 'date-format.inc' %]
263
                                    <td class="fine editable fines" varname="fine">
156
                        <img src="[% themelang %]/lib/calendar/cal.gif" alt="Show Calendar"  border="0" id="CalendarDueDate" style="cursor: pointer;"/>
264
                                    [% END %]
157
                        <script language="JavaScript" type="text/javascript">
265
                                    [% fine %]
158
                             function refocus(calendar) {
266
                                    </td>
159
                                 document.getElementById('hardduedate').focus();
267
                                    [% IF ( rule.herited_chargeperiod ) %]
160
                                 calendar.hide();
268
                                    <td class="chargeperiod editable fines herited" varname="chargeperiod">
161
                             };
269
                                    [% ELSE %]
162
                             Calendar.setup(
270
                                    <td class="chargeperiod editable fines" varname="chargeperiod">
163
                             {
271
                                    [% END %]
164
                             inputField : "hardduedate",
272
                                    [% rule.chargeperiod %]
165
                             ifFormat : "%m/%d/%Y",
273
                                    </td>
166
                             button : "CalendarDueDate",
274
                                    [% IF ( rule.herited_firstremind ) %]
167
                             onClose: refocus
275
                                    <td class="firstremind editable fines herited" varname="firstremind">
168
                             }
276
                                    [% ELSE %]
169
                             );
277
                                    <td class="firstremind editable fines" varname="firstremind">
170
                 </script>
278
                                    [% END %]
171
                    </td>
279
                                    [% rule.firstremind %]
172
                    <td><input name="fine" size="4" /></td>
280
                                    </td>
173
                    <td><input name="chargeperiod" size="2" /></td>
281
                                    [% IF ( rule.herited_finedays ) %]
174
                    <td><input name="firstremind" size="2" /> </td>
282
                                    <td class="finedays editable fines herited" varname="finedays">
175
                    <td><input name="finedays" size="3" /> </td>
283
                                    [% ELSE %]
176
                    <td><input name="renewalsallowed" size="2" /></td>
284
                                    <td class="finedays editable fines" varname="finedays">
177
                    <td><input name="reservesallowed" size="2" /></td>
285
                                    [% END %]
178
		    <td><input name="rentaldiscount" size="2" /></td>
286
                                    [% rule.finedays %]
179
                    <td><input type="hidden" name="branch" value="[% current_branch %]"/><input type="submit" value="Add" class="submit" /></td>
287
                                    </td>
180
                </tr>
288
                                    [% IF ( rule.herited_renewalsallowed ) %]
181
            </table>
289
                                    <td class="renewalsallowed editable issues herited" varname="renewalsallowed">
182
        </form>
290
                                    [% ELSE %]
183
    </div>
291
                                    <td class="renewalsallowed editable issues" varname="renewalsallowed">
184
    <div id="defaults-for-this-library" class="container">
292
                                    [% END %]
185
    <h3>Default checkout and hold policy for [% IF ( humanbranch ) %][% humanbranch %][% ELSE %]all libraries[% END %]</h3>
293
                                    [% rule.renewalsallowed %]
186
        <p>You can set a default maximum number of checkouts and hold policy that will be used if none is defined below for a particular item type or category.</p>
294
                                    </td>
187
        <form method="post" action="/cgi-bin/koha/admin/smart-rules.pl">
295
                                    [% IF ( rule.herited_renewalperiod ) %]
188
            <input type="hidden" name="op" value="set-branch-defaults" />
296
                                    <td class="renewalperiod editable issues herited" varname="renewalperiod">
189
            <input type="hidden" name="branch" value="[% current_branch %]"/>
297
                                    [% ELSE %]
190
            <table>
298
                                    <td class="renewalperiod editable issues" varname="renewalperiod">
191
                <tr>
299
                                    [% END %]
192
                    <th>&nbsp;</th>
300
                                    [% rule.renewalperiod %]
193
                    <th>Total Current Checkouts Allowed</th>
301
                                    </td>
194
                    <th>Hold Policy</th>
302
                                    [% IF ( rule.herited_reservesallowed ) %]
195
                    <th>&nbsp;</th>
303
                                    <td class="reservesallowed editable reserves herited" varname="reservesallowed">
196
                    <th>&nbsp;</th>
304
                                    [% ELSE %]
197
                </tr>
305
                                    <td class="reservesallowed editable reserves" varname="reservesallowed">
198
                <tr>
306
                                    [% END %]
199
                    <td><em>Defaults[% UNLESS ( default_rules ) %] (not set)[% END %]</em></td>
307
                                    [% rule.reservesallowed %]
200
                    <td><input type="text" name="maxissueqty" size="3" value="[% default_maxissueqty %]"/></td>
308
                                    </td>
201
                    <td>
309
                                     [% IF ( rule.herited_holdspickupdelay ) %]
202
                        <select name="holdallowed">
310
                                    <td class="holdspickupdelay editable reserves herited" varname="holdspickupdelay">
203
                            [% IF ( default_holdallowed_any ) %]
311
                                    [% ELSE %]
204
                            <option value="2" selected="selected">
312
                                    <td class="holdspickupdelay editable reserves" varname="holdspickupdelay">
205
                            [% ELSE %]
313
                                    [% END %]
206
                            <option value="2">
314
                                    [% rule.holdspickupdelay %]
315
                                    </td>
316
                                    [% IF ( rule.herited_allowonshelfholds ) %]
317
                                    <td class="allowonshelfholds reserves triple herited" varname="allowonshelfholds">
318
                                    [% ELSE %]
319
                                    <td class="allowonshelfholds reserves triple" varname="allowonshelfholds">
320
				                    [% END %]
321
                                    [% IF ( rule.allowonshelfholds ) %]
322
                                    Yes
323
                                    [% ELSE %]
324
                                    No
325
                                    [% END %]
326
                                    </td>
327
                                    [% IF ( rule.herited_holdrestricted ) %]
328
                                    <td class="holdrestricted reserves triple herited" varname="holdrestricted">
329
                                    [% ELSE %]
330
                                     <td class="holdrestricted reserves triple" varname="holdrestricted">
331
                                    [% END %]
332
                                    [% IF ( rule.holdrestricted ) %]
333
                                    Yes
334
                                    [% ELSE %]
335
                                    No
336
                                    [% END %]
337
                                    </td>
338
                                    [% IF ( rule.herited_rentaldiscount ) %]
339
                                    <td class="rentaldiscount editable issues herited" varname="rentaldiscount">
340
                                    [% ELSE %]
341
                                    <td class="rentaldiscount editable issues" varname="rentaldiscount">
342
                                    [% END %]
343
                                    [% rule.rentaldiscount %]
344
                                    </td>
345
                                    <td>
346
                                        <a class="button" href="/cgi-bin/koha/admin/smart-rules.pl?op=delete&amp;itemtype=[% rule.itemtype %]&amp;categorycode=[% rule.categorycode %]&amp;branchcode=[% rule.branchcode %]">Delete</a>
347
                                    </td>
348
                                </tr>
207
                            [% END %]
349
                            [% END %]
208
                                From Any Library
350
                        </tbody>
209
                            </option>
351
                        <form method="post" name="inputrules" action="/cgi-bin/koha/admin/smart-rules.pl">
210
                            [% IF ( default_holdallowed_same ) %]
352
                            <input type="hidden" name="op" value="add" />
211
                            <option value="1" selected="selected">
353
                        <tfoot>
212
                            [% ELSE %]
354
                            <tr>
213
                            <option value="1">
355
                                <td>
214
                            [% END %]
356
                                    <select name="categorycode" id="categorycode" style="width:12em;">
215
                                From Home Library
357
                                        <option value="*">Default</option>
216
                            </option>
358
                                    [% FOREACH category IN categoryloop %]
217
                            [% IF ( default_holdallowed_none ) %]
359
                                        [% IF ( category.selected ) %]
218
                            <option value="0" selected="selected">
360
                                        <option value="[% category.categorycode %]" selected="selected">[% category.description %]</option>
219
                            [% ELSE %]
361
                                        [% ELSE %] <option value="[% category.categorycode %]" >[% category.description %]</option>
220
                            <option value="0">
362
                                        [% END %]
221
                            [% END %]
363
                                    [% END %]
222
                                No Holds Allowed
364
                                    </select>
223
                            </option>
365
                                </td>
224
                        </select>
366
                                <td>
225
                    </td>
367
                                    <select name="itemtype" style="width:12em;">
226
                    <td><input type="submit" value="Save" class="submit" /></td>
368
                                        <option value="*">Default</option>
227
                    <td>
369
                                    [% FOREACH itemtypeL IN itemtypeloop %]
228
                        <a class="button" href="/cgi-bin/koha/admin/smart-rules.pl?op=delete-branch-cat&amp;categorycode=*&amp;branch=[% current_branch %]">Unset</a>
370
                                        [% IF itemtypeL.selected %]
229
                    </td>
371
                                        <option value="[% itemtypeL.itemtype %]" selected="selected">[% itemtypeL.description %]</option>
230
                </tr>
372
                                        [% ELSE %] <option value="[% itemtypeL.itemtype %]">[% itemtypeL.description %]</option>
231
            </table>
373
                                        [% END %]
232
        </form>
374
                                    [% END %]
233
    </div>
375
                                    </select>
234
    [% IF ( show_branch_cat_rule_form ) %]
376
                                </td>
235
    <div id="holds-policy-by-patron-category" class="container">
377
                                <td class="issues"><input name="maxissueqty" size="3" value="[% maxissueqty %]"/></td>
236
    <h3>Checkout limit by patron category for [% IF ( humanbranch ) %][% humanbranch %][% ELSE %]all libraries[% END %]</h3>
378
                                <td class="issues"><input name="issuelength" size="3" value="[% issuelength %]"/> </td>
237
        <p>For this library, you can specify the maximum number of loans that
379
                                <td class="issues"><select name="hardduedatecompare" >
238
            a patron of a given category can make, regardless of the item type.
380
                                                        <option value="-1">Before</option>
239
        </p>
381
                                                        <option value="0">Exactly on</option>
240
        <p>If the total amount loanable for a given patron category is left blank,
382
                                                        <option value="1">After</option>
241
           no limit applies, except possibly for a limit you define for a specific item type.
383
                                                   </select>
242
        </p>
384
                                    </td>
243
        <form method="post" action="/cgi-bin/koha/admin/smart-rules.pl">
385
                                <td class="issues">
244
            <input type="hidden" name="op" value="add-branch-cat" />
386
                                    <input type="text" size="10" name="hardduedate" value="[% hardduedate %]" />
245
            <input type="hidden" name="branch" value="[% current_branch %]"/>
387
                                 </td>
246
            <table>
388
                                <td class="fines"><input name="fine" size="4" value="[% fine %]"/></td>
247
                <tr>
389
                                <td class="fines"><input name="chargeperiod" size="2" value="[% chargeperiod %]"/></td>
248
                    <th>Patron Category</th>
390
                                <td class="fines"><input name="firstremind" size="2" value="[% firstremind %]"/> </td>
249
                    <th>Total Current Checkouts Allowed</th>
391
                                <td class="fines"><input name="finedays" size="3" value="[% finedays %]"/> </td>
250
                    <th>&nbsp;</th>
392
                                <td class="issues"><input name="renewalsallowed" size="2" value="[% renewalsallowed %]"/></td>
251
                </tr>
393
                                <td class="issues"><input name="renewalperiod" size="2" value="[% renewalperiod %]"/></td>
252
                [% FOREACH branch_cat_rule_loo IN branch_cat_rule_loop %]
394
                                <td class="reserves"><input name="reservesallowed" size="2" value="[% reservesallowed %]"/></td>
253
                    [% UNLESS ( loop.odd ) %]
395
                                <td class="reserves"><input name="holdspickupdelay" size="2" value="[% holdspickupdelay %]"/></td>
254
                    <tr class="highlight">
396
                                <td class="reserves">
255
                    [% ELSE %]
397
                                    <select name="allowonshelfholds">
256
                    <tr>
398
                                        <option value=""></option>
257
                    [% END %]
399
                                        <option value="1">Yes</option>
258
                        <td>[% IF ( branch_cat_rule_loo.default_humancategorycode ) %]
400
                                        <option value="0">No</option>
259
                                <em>Default</em>
401
                                    </select>
260
                            [% ELSE %]
402
                                </td>
261
                                [% branch_cat_rule_loo.humancategorycode %]
403
                                <td class="reserves">[% IF ( holdrestricted ) %]<input type="checkbox" name="holdrestricted" checked="checked" value="1"/> [% ELSE %]<input type="checkbox" name="holdrestricted" value="1"/> [% END %]</td>
262
                            [% END %]
404
		                        <td class="issues"><input name="rentaldiscount" size="2" /></td>
263
                        </td>
405
                                <td><input type="hidden" name="branchcode" value="[% branchcode %]"/><input type="submit" value="Add" class="submit" /></td>
264
                        <td>[% IF ( branch_cat_rule_loo.unlimited_maxissueqty ) %]
406
                            </tr>
265
                                Unlimited
407
                        </tfoot>
266
                            [% ELSE %]
408
                </form>
267
                                [% branch_cat_rule_loo.maxissueqty %]
409
                    </table>
268
                            [% END %]
410
            </div><!-- tabs-container -->
269
                        </td>
411
        </div><!-- toptabs -->
270
                        <td>
271
                            <a class="button" href="/cgi-bin/koha/admin/smart-rules.pl?op=delete-branch-cat&amp;categorycode=[% branch_cat_rule_loo.categorycode %]&amp;branch=[% branch_cat_rule_loo.current_branch %]">Delete</a>
272
                        </td>
273
                    </tr>
274
                [% END %]
275
                <tr>
276
                    <td>
277
                        <select name="categorycode">
278
                        [% FOREACH categoryloo IN categoryloop %]
279
                            <option value="[% categoryloo.categorycode %]">[% categoryloo.description %]</option>
280
                        [% END %]
281
                        </select>
282
                    </td>
283
                    <td><input name="maxissueqty" size="3" /></td>
284
                    <td><input type="submit" value="Add" class="submit" /></td>
285
                </tr>
286
            </table>
287
        </form>
288
    </div>
289
    [% END %]
290
    <div id="holds-policy-by-item-type" class="container">
291
    <h3>Holds policy by item type for [% IF ( humanbranch ) %][% humanbranch %][% ELSE %]all libraries[% END %]</h3>
292
        <p>
293
            For this library, you can edit rules for given itemtypes, regardless
294
            of the patron's category.
295
        </p>
296
        <p>
297
            Currently, this means hold policies.
298
            The various policies have the following effects:
299
        </p>
300
        <ul>
301
            <li><strong>From Any Library:</strong> Patrons from any library may put this item on hold. <cite>(default if none is defined)</cite></li>
302
            <li><strong>From Home Library:</strong> Only patrons from the item's home library may put this book on hold.</li>
303
            <li><strong>No Holds Allowed:</strong> No patron may put this book on hold.</li>
304
        </ul>
305
        <p>
306
            Note that if the system preference
307
            <code>AllowHoldPolicyOverride</code> is enabled, these policies can
308
            be overridden by your circulation staff. Also, these policies are
309
            based on the patron's home library, <em>not</em> the library where the hold is being placed..
310
        </p>
311
312
        <form method="post" action="/cgi-bin/koha/admin/smart-rules.pl">
313
            <input type="hidden" name="op" value="add-branch-item" />
314
            <input type="hidden" name="branch" value="[% current_branch %]"/>
315
            <table>
316
                <tr>
317
                    <th>Item Type</th>
318
                    <th>Hold Policy</th>
319
                    <th>&nbsp;</th>
320
                </tr>
321
                [% FOREACH branch_item_rule_loo IN branch_item_rule_loop %]
322
                    [% UNLESS ( loop.odd ) %]
323
                    <tr class="highlight">
324
                    [% ELSE %]
325
                    <tr>
326
                    [% END %]
327
                        <td>[% IF ( branch_item_rule_loo.default_humanitemtype ) %]
328
                                <em>Default</em>
329
                            [% ELSE %]
330
                                [% branch_item_rule_loo.humanitemtype %]
331
                            [% END %]
332
                        </td>
333
                        <td>[% IF ( branch_item_rule_loo.holdallowed_any ) %]
334
                                From Any Library
335
                            [% ELSIF ( branch_item_rule_loo.holdallowed_same ) %]
336
                                From Home Library
337
                            [% ELSE %]
338
                                No Holds Allowed
339
                            [% END %]
340
                        </td>
341
                        <td>
342
                            <a class="button" href="/cgi-bin/koha/admin/smart-rules.pl?op=delete-branch-item&amp;itemtype=[% branch_item_rule_loo.itemtype %]&amp;branch=[% branch_item_rule_loo.current_branch %]">Delete</a>
343
                        </td>
344
                    </tr>
345
                [% END %]
346
                <tr>
347
                    <td>
348
                        <select name="itemtype">
349
                        [% FOREACH itemtypeloo IN itemtypeloop %]
350
                            <option value="[% itemtypeloo.itemtype %]">[% itemtypeloo.description %]</option>
351
                        [% END %]
352
                        </select>
353
                    </td>
354
                    <td>
355
                        <select name="holdallowed">
356
                            <option value="2">From Any Library</option>
357
                            <option value="1">From Home Library</option>
358
                            <option value="0">No Holds Allowed</option>
359
                        </select>
360
                    </td>
361
                    <td><input type="submit" value="Add" class="submit" /></td>
362
                </tr>
363
            </table>
364
        </form>
365
    </div>
412
    </div>
366
</div>
413
</div>
367
414
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/returns.tt (+3 lines)
Lines 144-149 function Dopop(link) { Link Here
144
                <input type="hidden" name="diffBranch" value="[% destbranch %]" />
144
                <input type="hidden" name="diffBranch" value="[% destbranch %]" />
145
                <input type="hidden" name="exemptfine" value="[% exemptfine %]" />
145
                <input type="hidden" name="exemptfine" value="[% exemptfine %]" />
146
                <input type="hidden" name="dropboxmode" value="[% dropboxmode %]" />
146
                <input type="hidden" name="dropboxmode" value="[% dropboxmode %]" />
147
                <input type="hidden" name="reservenumber" value="[% reservenumber %]" />
147
                </form>
148
                </form>
148
	</div>
149
	</div>
149
    [% END %]
150
    [% END %]
Lines 180-185 function Dopop(link) { Link Here
180
            <input type="hidden" name="diffBranch" value="[% destbranch %]" />
181
            <input type="hidden" name="diffBranch" value="[% destbranch %]" />
181
            <input type="hidden" name="exemptfine" value="[% exemptfine %]" />
182
            <input type="hidden" name="exemptfine" value="[% exemptfine %]" />
182
            <input type="hidden" name="dropboxmode" value="[% dropboxmode %]" />
183
            <input type="hidden" name="dropboxmode" value="[% dropboxmode %]" />
184
            <input type="hidden" name="reservenumber" value="[% reservenumber %]" />
183
            <input type="hidden" name="barcode" value="0" />
185
            <input type="hidden" name="barcode" value="0" />
184
        </form>
186
        </form>
185
		</div>
187
		</div>
Lines 281-286 function Dopop(link) { Link Here
281
            <input type="hidden" name="diffBranch" value="[% destbranch %]" />
283
            <input type="hidden" name="diffBranch" value="[% destbranch %]" />
282
            <input type="hidden" name="exemptfine" value="[% exemptfine %]" />
284
            <input type="hidden" name="exemptfine" value="[% exemptfine %]" />
283
            <input type="hidden" name="dropboxmode" value="[% dropboxmode %]" />
285
            <input type="hidden" name="dropboxmode" value="[% dropboxmode %]" />
286
            <input type="hidden" name="reservenumber" value="[% reservenumber %]" />
284
        </form>
287
        </form>
285
	</div>
288
	</div>
286
    [% END %]
289
    [% END %]
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/reserve/request.tt (-9 / +32 lines)
Lines 23-32 function check() { Link Here
23
	var count_reserv = 0;
23
	var count_reserv = 0;
24
	var alreadyreserved = 0;
24
	var alreadyreserved = 0;
25
25
26
    var hold_type="";    
26
    // check if we have checkitem form
27
    // check if we have checkitem form
27
    if (document.form.checkitem){
28
    if (document.form.checkitem){
28
        for (i=0;i<document.form.checkitem.length;i++){
29
        for (i=0;i<document.form.checkitem.length;i++){
29
            if (document.form.checkitem[i].checked == true) {
30
            if (document.form.checkitem[i].checked == true) {
31
                if (hold_type=="" || hold_type=="single"){
32
                    hold_type=document.form.hold_type[i].value;
33
                }
30
				count_reserv++ ;
34
				count_reserv++ ;
31
			}
35
			}
32
        }
36
        }
Lines 49-59 function check() { Link Here
49
    if (count_reserv == "0"){
53
    if (count_reserv == "0"){
50
		msg += (_("- Please select an item to place a hold") + "\n");
54
		msg += (_("- Please select an item to place a hold") + "\n");
51
    }
55
    }
52
    if (count_reserv >= "2"){
56
    if (count_reserv >= "2" && hold_type != "multiple"){
53
		msg += (_("- You may only place a hold on one item at a time") + "\n");
57
		msg += (_("- You may only place a hold on one item at a time") + "\n");
54
    }
58
    }
55
59
56
    if (alreadyreserved > "0"){
60
    if (alreadyreserved > "0" && hold_type != "multiple"){
57
		msg += (_("- This patron had already placed a hold on this item") + "\n" + _("Please cancel the previous hold first") + "\n");
61
		msg += (_("- This patron had already placed a hold on this item") + "\n" + _("Please cancel the previous hold first") + "\n");
58
    }
62
    }
59
63
Lines 395-408 function checkMultiHold() { Link Here
395
        [% UNLESS ( itemloo.hide ) %]
399
        [% UNLESS ( itemloo.hide ) %]
396
        <tr class="[% itemloo.backgroundcolor %]">
400
        <tr class="[% itemloo.backgroundcolor %]">
397
            <td>
401
            <td>
398
            [% IF ( itemloo.available ) %]
402
            [% IF ( itemloo.canholdmultiple ) %]
399
                <input type="radio" name="checkitem" value="[% itemloo.itemnumber %]" />
403
                <input type="hidden" name="hold_type" value="multiple" />
404
            [% ELSIF ( itemloo.available ) %]
405
                <input type="hidden" name="hold_type" value="single" />
400
            [% ELSIF ( itemloo.override ) %]
406
            [% ELSIF ( itemloo.override ) %]
401
                <input type="radio" name="checkitem" class="needsoverride" value="[% itemloo.itemnumber %]" />
407
                <input type="hidden" name="hold_type" value="single" />
402
                <img src="/intranet-tmpl/[% theme %]/img/famfamfam/silk/error.png" alt="Requires override of hold policy" />
408
            [% END %]
409
            [% IF ( itemloo.cannothold ) %]
410
                <input disabled="disabled" type="radio" name="checkitem" value="[% itemloo.itemnumber %]" />                            
411
                <img src="/intranet-tmpl/[% theme %]/img/famfamfam/silk/cross.png" alt="Cannot be put on hold" />               
403
            [% ELSE %]
412
            [% ELSE %]
404
                <input disabled="disabled" type="radio" name="checkitem" value="[% itemloo.itemnumber %]" />
413
                [% IF ( itemloo.canholdmultiple ) %]
405
                <img src="/intranet-tmpl/[% theme %]/img/famfamfam/silk/cross.png" alt="Cannot be put on hold" />
414
                    <input type="checkbox" name="checkitem" value="[% itemnumber %]" />
415
                [% ELSIF ( itemloo.available ) %]
416
                    [% IF ( itemloo.available ) %]
417
                        <input type="radio" name="checkitem" value="[% itemloo.itemnumber %]" />
418
                    [% ELSIF ( itemloo.override ) %]
419
                        <input type="radio" name="checkitem" class="needsoverride" value="[% itemloo.itemnumber %]" />
420
                        <img src="/intranet-tmpl/[% theme %]/img/famfamfam/silk/error.png" alt="Requires override of hold policy" />
421
                    [% ELSE %]
422
                        <input disabled="disabled" type="radio" name="checkitem" value="[% itemloo.itemnumber %]" />
423
                        <img src="/intranet-tmpl/[% theme %]/img/famfamfam/silk/cross.png" alt="Cannot be put on hold" />
424
                    [% END %]
425
                [% ELSE %]
426
                    <input disabled="disabled" type="radio" name="checkitem" value="[% itemnumber %]" />
427
                    <img src="/intranet-tmpl/[% theme %]/img/famfamfam/silk/cross.png" alt="Cannot be put on hold" />
428
                [% END %]
406
            [% END %]
429
            [% END %]
407
            </td>
430
            </td>
408
            [% IF ( item_level_itypes ) %]
431
            [% IF ( item_level_itypes ) %]
Lines 713-719 function checkMultiHold() { Link Here
713
    [% END %]
736
    [% END %]
714
737
715
	<td>
738
	<td>
716
		<a title="Cancel Hold" href="request.pl?action=cancel&amp;borrowernumber=[% reserveloo.borrowernumber %]&amp;biblionumber=[% reserveloo.biblionumber %]&amp;date=[% reserveloo.date %]">
739
		<a title="Cancel Hold" href="request.pl?action=cancel&amp;reservenumber=[% reserveloo.reservenumber %]&amp;biblionumber=[% reserveloo.biblionumber %]">
717
                    <img src="/intranet-tmpl/[% theme %]/img/x.png" border="0" alt="Cancel" />
740
                    <img src="/intranet-tmpl/[% theme %]/img/x.png" border="0" alt="Cancel" />
718
                </a>
741
                </a>
719
	</td>
742
	</td>
(-)a/kohaversion.pl (-1 / +1 lines)
Lines 16-22 the kohaversion is divided in 4 parts : Link Here
16
use strict;
16
use strict;
17
17
18
sub kohaversion {
18
sub kohaversion {
19
    our $VERSION = '3.05.00.004';
19
    our $VERSION = '3.05.00.005';
20
    # version needs to be set this way
20
    # version needs to be set this way
21
    # so that it can be picked up by Makefile.PL
21
    # so that it can be picked up by Makefile.PL
22
    # during install
22
    # during install
(-)a/opac/opac-modrequest.pl (-1 / +3 lines)
Lines 42-48 my ( $template, $borrowernumber, $cookie ) = get_template_and_user( Link Here
42
);
42
);
43
43
44
my $biblionumber = $query->param('biblionumber');
44
my $biblionumber = $query->param('biblionumber');
45
my $reservenumber = $query->param('reservenumber');
46
45
if ($biblionumber and $borrowernumber) {
47
if ($biblionumber and $borrowernumber) {
46
	CancelReserve($biblionumber, '', $borrowernumber);
48
	CancelReserve( $reservenumber, $biblionumber );
47
}
49
}
48
print $query->redirect("/cgi-bin/koha/opac-user.pl#opac-user-holds");
50
print $query->redirect("/cgi-bin/koha/opac-user.pl#opac-user-holds");
(-)a/opac/opac-reserve.pl (-26 / +41 lines)
Lines 1-5 Link Here
1
#!/usr/bin/perl
1
#!/usr/bin/perl
2
2
3
# Parts Copyright Biblibre 2010
4
3
# This file is part of Koha.
5
# This file is part of Koha.
4
#
6
#
5
# Koha is free software; you can redistribute it and/or modify it under the
7
# Koha is free software; you can redistribute it and/or modify it under the
Lines 28-38 use C4::Output; Link Here
28
use C4::Dates qw/format_date/;
30
use C4::Dates qw/format_date/;
29
use C4::Context;
31
use C4::Context;
30
use C4::Members;
32
use C4::Members;
33
use C4::Overdues;
31
use C4::Branch; # GetBranches
34
use C4::Branch; # GetBranches
32
use C4::Debug;
35
use C4::Debug;
36
use C4::Items;
33
# use Data::Dumper;
37
# use Data::Dumper;
34
38
35
my $MAXIMUM_NUMBER_OF_RESERVES = C4::Context->preference("maxreserves");
36
39
37
my $query = new CGI;
40
my $query = new CGI;
38
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
41
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
Lines 77-83 if ((! $biblionumbers) && (! $query->param('place_reserve'))) { Link Here
77
80
78
# Pass the numbers to the page so they can be fed back
81
# Pass the numbers to the page so they can be fed back
79
# when the hold is confirmed. TODO: Not necessary?
82
# when the hold is confirmed. TODO: Not necessary?
80
$template->param( biblionumbers => $biblionumbers );
83
$template->param( biblionumbers      => $biblionumbers,
84
		  OPACPickupLocation => "" . C4::Context->preference("OPACPickupLocation"),
85
             );
81
86
82
# Each biblio number is suffixed with '/', e.g. "1/2/3/"
87
# Each biblio number is suffixed with '/', e.g. "1/2/3/"
83
my @biblionumbers = split /\//, $biblionumbers;
88
my @biblionumbers = split /\//, $biblionumbers;
Lines 91-96 if (($#biblionumbers < 0) && (! $query->param('place_reserve'))) { Link Here
91
my $branch = $query->param('branch') || $borr->{'branchcode'} || C4::Context->userenv->{branch} || '' ;
96
my $branch = $query->param('branch') || $borr->{'branchcode'} || C4::Context->userenv->{branch} || '' ;
92
($branches->{$branch}) or $branch = "";     # Confirm branch is real
97
($branches->{$branch}) or $branch = "";     # Confirm branch is real
93
$template->param( branch => $branch );
98
$template->param( branch => $branch );
99
$template->param( branchname => $branches->{$branch}->{branchname} );
94
100
95
# make branch selection options...
101
# make branch selection options...
96
my $CGIbranchloop = GetBranchesLoop($branch);
102
my $CGIbranchloop = GetBranchesLoop($branch);
Lines 252-258 if ( $borr->{lost} && ($borr->{lost} eq 1) ) { Link Here
252
                     lost    => 1
258
                     lost    => 1
253
                    );
259
                    );
254
}
260
}
255
if ( $borr->{debarred} && ($borr->{debarred} eq 1) ) {
261
if ( CheckBorrowerDebarred($borrowernumber) ) {
256
    $noreserves = 1;
262
    $noreserves = 1;
257
    $template->param(
263
    $template->param(
258
                     message  => 1,
264
                     message  => 1,
Lines 262-272 if ( $borr->{debarred} && ($borr->{debarred} eq 1) ) { Link Here
262
268
263
my @reserves = GetReservesFromBorrowernumber( $borrowernumber );
269
my @reserves = GetReservesFromBorrowernumber( $borrowernumber );
264
$template->param( RESERVES => \@reserves );
270
$template->param( RESERVES => \@reserves );
265
if ( $MAXIMUM_NUMBER_OF_RESERVES && (scalar(@reserves) >= $MAXIMUM_NUMBER_OF_RESERVES) ) {
266
    $template->param( message => 1 );
267
    $noreserves = 1;
268
    $template->param( too_many_reserves => scalar(@reserves));
269
}
270
foreach my $res (@reserves) {
271
foreach my $res (@reserves) {
271
    foreach my $biblionumber (@biblionumbers) {
272
    foreach my $biblionumber (@biblionumbers) {
272
        if ( $res->{'biblionumber'} == $biblionumber && $res->{'borrowernumber'} == $borrowernumber) {
273
        if ( $res->{'biblionumber'} == $biblionumber && $res->{'borrowernumber'} == $borrowernumber) {
Lines 342-351 foreach my $biblioNum (@biblionumbers) { Link Here
342
        }
343
        }
343
    }
344
    }
344
345
346
    $biblioLoopIter{itemtype}            = $biblioData->{itemtype};
347
    $biblioLoopIter{itemTypeDescription} = $itemTypes->{ $biblioData->{itemtype} }{description};
345
    $biblioLoopIter{itemLoop} = [];
348
    $biblioLoopIter{itemLoop} = [];
346
    my $numCopiesAvailable = 0;
349
    my $numCopiesAvailable = 0;
347
    foreach my $itemInfo (@{$biblioData->{itemInfos}}) {
350
348
        my $itemNum = $itemInfo->{itemnumber};
351
    # $canReserveMultiple is set to "yes" ( >0 ) if multiple items can be reserved
352
    # it is set to 0 otherwise. depends on item-level_itypes syspref
353
    # and the list of itypes that can be multiple reserved
354
    my $canReserveMultiple = 0;
355
    unless ( C4::Context->preference("item-level_itypes") ) {
356
        $canReserveMultiple = CanHoldMultipleItems( $biblioLoopIter{itemtype} );
</