Lines 27-39
use C4::Koha;
Link Here
|
27 |
use C4::Biblio; |
27 |
use C4::Biblio; |
28 |
use C4::Items; |
28 |
use C4::Items; |
29 |
use C4::Members; |
29 |
use C4::Members; |
30 |
use C4::Dates; |
30 |
use C4::IssuingRules; |
|
|
31 |
use C4::Dates qw/format_date/; |
31 |
use C4::Calendar; |
32 |
use C4::Calendar; |
32 |
use C4::Accounts; |
33 |
use C4::Accounts; |
|
|
34 |
use C4::Overdues ; |
33 |
use C4::ItemCirculationAlertPreference; |
35 |
use C4::ItemCirculationAlertPreference; |
34 |
use C4::Dates qw(format_date); |
36 |
use C4::Dates qw(format_date); |
35 |
use C4::Message; |
37 |
use C4::Message; |
36 |
use C4::Debug; |
38 |
use C4::Debug; |
|
|
39 |
use YAML; |
37 |
use Date::Calc qw( |
40 |
use Date::Calc qw( |
38 |
Today |
41 |
Today |
39 |
Today_and_Now |
42 |
Today_and_Now |
Lines 42-47
use Date::Calc qw(
Link Here
|
42 |
Date_to_Days |
45 |
Date_to_Days |
43 |
Day_of_Week |
46 |
Day_of_Week |
44 |
Add_Delta_Days |
47 |
Add_Delta_Days |
|
|
48 |
Delta_Days |
49 |
check_date |
50 |
Add_Delta_Days |
45 |
); |
51 |
); |
46 |
use POSIX qw(strftime); |
52 |
use POSIX qw(strftime); |
47 |
use C4::Branch; # GetBranches |
53 |
use C4::Branch; # GetBranches |
Lines 73-81
BEGIN {
Link Here
|
73 |
&GetItemIssues |
79 |
&GetItemIssues |
74 |
&GetBorrowerIssues |
80 |
&GetBorrowerIssues |
75 |
&GetIssuingCharges |
81 |
&GetIssuingCharges |
76 |
&GetIssuingRule |
|
|
77 |
&GetBranchBorrowerCircRule |
78 |
&GetBranchItemRule |
79 |
&GetBiblioIssues |
82 |
&GetBiblioIssues |
80 |
&GetOpenIssue |
83 |
&GetOpenIssue |
81 |
&AnonymiseIssueHistory |
84 |
&AnonymiseIssueHistory |
Lines 98-103
BEGIN {
Link Here
|
98 |
&CreateBranchTransferLimit |
101 |
&CreateBranchTransferLimit |
99 |
&DeleteBranchTransferLimits |
102 |
&DeleteBranchTransferLimits |
100 |
); |
103 |
); |
|
|
104 |
|
105 |
# subs to deal with offline circulation |
106 |
push @EXPORT, qw( |
107 |
&GetOfflineOperations |
108 |
&GetOfflineOperation |
109 |
&AddOfflineOperation |
110 |
&DeleteOfflineOperation |
111 |
&ProcessOfflineOperation |
112 |
); |
101 |
} |
113 |
} |
102 |
|
114 |
|
103 |
=head1 NAME |
115 |
=head1 NAME |
Lines 346-461
sub TooMany {
Link Here
|
346 |
my $item = shift; |
358 |
my $item = shift; |
347 |
my $cat_borrower = $borrower->{'categorycode'}; |
359 |
my $cat_borrower = $borrower->{'categorycode'}; |
348 |
my $dbh = C4::Context->dbh; |
360 |
my $dbh = C4::Context->dbh; |
349 |
my $branch; |
361 |
my $exactbranch; |
350 |
# Get which branchcode we need |
362 |
# Get which branchcode we need |
351 |
$branch = _GetCircControlBranch($item,$borrower); |
363 |
$exactbranch = _GetCircControlBranch($item,$borrower); |
352 |
my $type = (C4::Context->preference('item-level_itypes')) |
364 |
my $itype = (C4::Context->preference('item-level_itypes')) |
353 |
? $item->{'itype'} # item-level |
365 |
? $item->{'itype'} # item-level |
354 |
: $item->{'itemtype'}; # biblio-level |
366 |
: $item->{'itemtype'}; # biblio-level |
355 |
|
367 |
|
356 |
# given branch, patron category, and item type, determine |
368 |
# given branch, patron category, and item type, determine |
357 |
# applicable issuing rule |
369 |
# applicable issuing rule |
358 |
my $issuing_rule = GetIssuingRule($cat_borrower, $type, $branch); |
370 |
my $branchfield = C4::Context->Preference('HomeOrHoldingBranch') || "homebranch"; |
359 |
|
371 |
#By default, Patron is supposed not to be able to borrow |
360 |
# if a rule is found and has a loan limit set, count |
372 |
my $toomany = 1; |
361 |
# how many loans the patron already has that meet that |
373 |
|
362 |
# rule |
374 |
foreach my $branch ( $exactbranch, '*' ) { |
363 |
if (defined($issuing_rule) and defined($issuing_rule->{'maxissueqty'})) { |
375 |
foreach my $type ( $itype, '*' ) { |
364 |
my @bind_params; |
376 |
my $issuing_rule = GetIssuingRule( $cat_borrower, $type, $branch ); |
365 |
my $count_query = "SELECT COUNT(*) FROM issues |
377 |
|
366 |
JOIN items USING (itemnumber) "; |
378 |
# if a rule is found and has a loan limit set, count |
367 |
|
379 |
# how many loans the patron already has that meet that |
368 |
my $rule_itemtype = $issuing_rule->{itemtype}; |
380 |
# rule |
369 |
if ($rule_itemtype eq "*") { |
381 |
if ( defined($issuing_rule) and defined( $issuing_rule->{'maxissueqty'} ) ) { |
370 |
# matching rule has the default item type, so count only |
382 |
my @bind_params; |
371 |
# those existing loans that don't fall under a more |
383 |
my $count_query = "SELECT COUNT(*) FROM issues |
372 |
# specific rule |
384 |
JOIN items USING (itemnumber) "; |
373 |
if (C4::Context->preference('item-level_itypes')) { |
385 |
|
374 |
$count_query .= " WHERE items.itype NOT IN ( |
386 |
my $rule_itemtype = $issuing_rule->{itemtype}; |
375 |
SELECT itemtype FROM issuingrules |
387 |
if ($rule_itemtype eq "*") { |
376 |
WHERE branchcode = ? |
388 |
# matching rule has the default item type, so count all the items issued for that branch no |
377 |
AND (categorycode = ? OR categorycode = ?) |
389 |
# those existing loans that don't fall under a more |
378 |
AND itemtype <> '*' |
390 |
# specific rule Not QUITE |
379 |
) "; |
391 |
if (C4::Context->preference('item-level_itypes')) { |
380 |
} else { |
392 |
$count_query .= " WHERE items.itype NOT IN ( |
381 |
$count_query .= " JOIN biblioitems USING (biblionumber) |
393 |
SELECT itemtype FROM issuingrules |
382 |
WHERE biblioitems.itemtype NOT IN ( |
394 |
WHERE branchcode = ? |
383 |
SELECT itemtype FROM issuingrules |
395 |
AND (categorycode = ? OR categorycode = ?) |
384 |
WHERE branchcode = ? |
396 |
AND itemtype <> '*' |
385 |
AND (categorycode = ? OR categorycode = ?) |
397 |
)"; |
386 |
AND itemtype <> '*' |
398 |
} else { |
387 |
) "; |
399 |
$count_query .= " JOIN biblioitems USING (biblionumber) |
388 |
} |
400 |
WHERE biblioitems.itemtype NOT IN ( |
389 |
push @bind_params, $issuing_rule->{branchcode}; |
401 |
SELECT itemtype FROM issuingrules |
390 |
push @bind_params, $issuing_rule->{categorycode}; |
402 |
WHERE branchcode = ? |
391 |
push @bind_params, $cat_borrower; |
403 |
AND (categorycode = ? OR categorycode = ?) |
392 |
} else { |
404 |
AND itemtype <> '*' |
393 |
# rule has specific item type, so count loans of that |
405 |
)"; |
394 |
# specific item type |
406 |
} |
395 |
if (C4::Context->preference('item-level_itypes')) { |
407 |
push @bind_params, $issuing_rule->{branchcode}; |
396 |
$count_query .= " WHERE items.itype = ? "; |
408 |
push @bind_params, $issuing_rule->{categorycode}; |
397 |
} else { |
409 |
push @bind_params, $cat_borrower; |
398 |
$count_query .= " JOIN biblioitems USING (biblionumber) |
410 |
} else { |
399 |
WHERE biblioitems.itemtype= ? "; |
411 |
# rule has specific item type, so count loans of that |
400 |
} |
412 |
# specific item type |
401 |
push @bind_params, $type; |
413 |
if (C4::Context->preference('item-level_itypes')) { |
402 |
} |
414 |
$count_query .= " WHERE items.itype = ? "; |
403 |
|
415 |
} else { |
404 |
$count_query .= " AND borrowernumber = ? "; |
416 |
$count_query .= " JOIN biblioitems USING (biblionumber) |
405 |
push @bind_params, $borrower->{'borrowernumber'}; |
417 |
WHERE biblioitems.itemtype= ? "; |
406 |
my $rule_branch = $issuing_rule->{branchcode}; |
418 |
} |
407 |
if ($rule_branch ne "*") { |
419 |
push @bind_params, $type; |
408 |
if (C4::Context->preference('CircControl') eq 'PickupLibrary') { |
420 |
} |
409 |
$count_query .= " AND issues.branchcode = ? "; |
|
|
410 |
push @bind_params, $branch; |
411 |
} elsif (C4::Context->preference('CircControl') eq 'PatronLibrary') { |
412 |
; # if branch is the patron's home branch, then count all loans by patron |
413 |
} else { |
414 |
$count_query .= " AND items.homebranch = ? "; |
415 |
push @bind_params, $branch; |
416 |
} |
417 |
} |
418 |
|
419 |
my $count_sth = $dbh->prepare($count_query); |
420 |
$count_sth->execute(@bind_params); |
421 |
my ($current_loan_count) = $count_sth->fetchrow_array; |
422 |
|
421 |
|
423 |
my $max_loans_allowed = $issuing_rule->{'maxissueqty'}; |
422 |
$count_query .= " AND borrowernumber = ? "; |
424 |
if ($current_loan_count >= $max_loans_allowed) { |
423 |
push @bind_params, $borrower->{'borrowernumber'}; |
425 |
return ($current_loan_count, $max_loans_allowed); |
424 |
my $rule_branch = $issuing_rule->{branchcode}; |
426 |
} |
425 |
if ( $rule_branch ne "*" ) { |
427 |
} |
426 |
if ( C4::Context->preference('CircControl') eq 'PickupLibrary' ) { |
|
|
427 |
$count_query .= " AND issues.branchcode = ? "; |
428 |
push @bind_params, $branch; |
429 |
} elsif ( C4::Context->preference('CircControl') eq 'PatronLibrary' ) { |
430 |
; # if branch is the patron's home branch, then count all loans by patron |
431 |
} else { |
432 |
$count_query .= " AND items.$branchfield = ? "; |
433 |
push @bind_params, $branch; |
434 |
} |
435 |
} |
428 |
|
436 |
|
429 |
# Now count total loans against the limit for the branch |
437 |
my $count_sth = $dbh->prepare($count_query); |
430 |
my $branch_borrower_circ_rule = GetBranchBorrowerCircRule($branch, $cat_borrower); |
438 |
$count_sth->execute(@bind_params); |
431 |
if (defined($branch_borrower_circ_rule->{maxissueqty})) { |
439 |
my ($current_loan_count) = $count_sth->fetchrow_array; |
432 |
my @bind_params = (); |
|
|
433 |
my $branch_count_query = "SELECT COUNT(*) FROM issues |
434 |
JOIN items USING (itemnumber) |
435 |
WHERE borrowernumber = ? "; |
436 |
push @bind_params, $borrower->{borrowernumber}; |
437 |
|
438 |
if (C4::Context->preference('CircControl') eq 'PickupLibrary') { |
439 |
$branch_count_query .= " AND issues.branchcode = ? "; |
440 |
push @bind_params, $branch; |
441 |
} elsif (C4::Context->preference('CircControl') eq 'PatronLibrary') { |
442 |
; # if branch is the patron's home branch, then count all loans by patron |
443 |
} else { |
444 |
$branch_count_query .= " AND items.homebranch = ? "; |
445 |
push @bind_params, $branch; |
446 |
} |
447 |
my $branch_count_sth = $dbh->prepare($branch_count_query); |
448 |
$branch_count_sth->execute(@bind_params); |
449 |
my ($current_loan_count) = $branch_count_sth->fetchrow_array; |
450 |
|
440 |
|
451 |
my $max_loans_allowed = $branch_borrower_circ_rule->{maxissueqty}; |
441 |
my $max_loans_allowed = $issuing_rule->{'maxissueqty'}; |
452 |
if ($current_loan_count >= $max_loans_allowed) { |
442 |
if ( $current_loan_count >= $max_loans_allowed ) { |
453 |
return ($current_loan_count, $max_loans_allowed); |
443 |
return 1,$current_loan_count,$max_loans_allowed; |
|
|
444 |
} |
445 |
else { |
446 |
$toomany=0; |
447 |
} |
448 |
} |
454 |
} |
449 |
} |
455 |
} |
450 |
} |
456 |
|
451 |
return $toomany; |
457 |
# OK, the patron can issue !!! |
|
|
458 |
return; |
459 |
} |
452 |
} |
460 |
|
453 |
|
461 |
=head2 itemissues |
454 |
=head2 itemissues |
Lines 684-690
sub CanBookBeIssued {
Link Here
|
684 |
my $branch = _GetCircControlBranch($item,$borrower); |
677 |
my $branch = _GetCircControlBranch($item,$borrower); |
685 |
my $itype = ( C4::Context->preference('item-level_itypes') ) ? $item->{'itype'} : $biblioitem->{'itemtype'}; |
678 |
my $itype = ( C4::Context->preference('item-level_itypes') ) ? $item->{'itype'} : $biblioitem->{'itemtype'}; |
686 |
my $loanlength = GetLoanLength( $borrower->{'categorycode'}, $itype, $branch ); |
679 |
my $loanlength = GetLoanLength( $borrower->{'categorycode'}, $itype, $branch ); |
687 |
$duedate = CalcDateDue( C4::Dates->new( $issuedate, 'iso' ), $loanlength, $branch, $borrower ); |
680 |
unless ($loanlength or C4::Context->preference("AllowNotForLoanOverride")) { |
|
|
681 |
$issuingimpossible{LOAN_LENGTH_UNDEFINED} = "$borrower->{'categorycode'}, $itype, $branch"; |
682 |
} |
683 |
$duedate = CalcDateDue( C4::Dates->new( $issuedate, 'iso' ), $loanlength, $branch, $borrower ) ; |
688 |
|
684 |
|
689 |
# Offline circ calls AddIssue directly, doesn't run through here |
685 |
# Offline circ calls AddIssue directly, doesn't run through here |
690 |
# So issuingimpossible should be ok. |
686 |
# So issuingimpossible should be ok. |
Lines 712-726
sub CanBookBeIssued {
Link Here
|
712 |
$issuingimpossible{CARD_LOST} = 1; |
708 |
$issuingimpossible{CARD_LOST} = 1; |
713 |
} |
709 |
} |
714 |
if ( $borrower->{flags}->{'DBARRED'} ) { |
710 |
if ( $borrower->{flags}->{'DBARRED'} ) { |
715 |
$issuingimpossible{DEBARRED} = 1; |
711 |
if (my $dateenddebarred=$borrower->{flags}->{'DBARRED'}->{'dateend'}){ |
|
|
712 |
$issuingimpossible{DEBARRED} = format_date($dateenddebarred); |
713 |
} |
714 |
else { |
715 |
$issuingimpossible{DEBARRED} = 1; |
716 |
} |
716 |
} |
717 |
} |
717 |
if ( $borrower->{'dateexpiry'} eq '0000-00-00') { |
718 |
if ( $borrower->{'dateexpiry'} eq '0000-00-00') { |
718 |
$issuingimpossible{EXPIRED} = 1; |
719 |
$issuingimpossible{EXPIRED} = 1; |
719 |
} else { |
720 |
} else { |
720 |
my @expirydate= split /-/,$borrower->{'dateexpiry'}; |
721 |
my @expirydate = split (/-/, $borrower->{'dateexpiry'}); |
721 |
if($expirydate[0]==0 || $expirydate[1]==0|| $expirydate[2]==0 || |
722 |
if ( $expirydate[0] == 0 |
722 |
Date_to_Days(Today) > Date_to_Days( @expirydate )) { |
723 |
|| $expirydate[1] == 0 |
723 |
$issuingimpossible{EXPIRED} = 1; |
724 |
|| $expirydate[2] == 0 |
|
|
725 |
|| Date_to_Days(Today) > Date_to_Days(@expirydate) ) { |
726 |
$issuingimpossible{EXPIRED} = 1; |
724 |
} |
727 |
} |
725 |
} |
728 |
} |
726 |
# |
729 |
# |
Lines 769-786
sub CanBookBeIssued {
Link Here
|
769 |
# |
772 |
# |
770 |
# JB34 CHECKS IF BORROWERS DONT HAVE ISSUE TOO MANY BOOKS |
773 |
# JB34 CHECKS IF BORROWERS DONT HAVE ISSUE TOO MANY BOOKS |
771 |
# |
774 |
# |
772 |
my ($current_loan_count, $max_loans_allowed) = TooMany( $borrower, $item->{biblionumber}, $item ); |
775 |
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 |
776 |
|
774 |
if ($max_loans_allowed eq 0) { |
777 |
if ( $toomany[0] == 1 && scalar(@toomany)<3) { |
775 |
$needsconfirmation{PATRON_CANT} = 1; |
778 |
$needsconfirmation{PATRON_CANT} = 1; |
776 |
} else { |
779 |
} elsif (scalar(@toomany)==3) { |
777 |
if($max_loans_allowed){ |
780 |
$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 |
} |
781 |
} |
783 |
|
782 |
|
|
|
783 |
|
784 |
# |
784 |
# |
785 |
# ITEM CHECKING |
785 |
# ITEM CHECKING |
786 |
# |
786 |
# |
Lines 817-824
sub CanBookBeIssued {
Link Here
|
817 |
} |
817 |
} |
818 |
} |
818 |
} |
819 |
} |
819 |
} |
820 |
if ( $item->{'wthdrawn'} && $item->{'wthdrawn'} == 1 ) |
820 |
if ( $item->{'damaged'} && $item->{'damaged'} > 0 ){ |
821 |
{ |
821 |
$needsconfirmation{DAMAGED} = $item->{'damaged'}; |
|
|
822 |
my $fw = GetFrameworkCode($item->{biblionumber}); |
823 |
my $category = GetAuthValCode('items.damaged',$fw); |
824 |
my $authorizedvalues = GetAuthorisedValues($category, $item->{damaged}); |
825 |
|
826 |
foreach my $authvalue (@$authorizedvalues){ |
827 |
$needsconfirmation{DAMAGED} = $authvalue->{lib} if $authvalue->{'authorised_value'} eq $item->{'damaged'}; |
828 |
} |
829 |
|
830 |
} |
831 |
if ( $item->{'wthdrawn'} && $item->{'wthdrawn'} == 1 ) { |
822 |
$issuingimpossible{WTHDRAWN} = 1; |
832 |
$issuingimpossible{WTHDRAWN} = 1; |
823 |
} |
833 |
} |
824 |
if ( $item->{'restricted'} |
834 |
if ( $item->{'restricted'} |
Lines 826-840
sub CanBookBeIssued {
Link Here
|
826 |
{ |
836 |
{ |
827 |
$issuingimpossible{RESTRICTED} = 1; |
837 |
$issuingimpossible{RESTRICTED} = 1; |
828 |
} |
838 |
} |
|
|
839 |
my $userenv = C4::Context->userenv; |
840 |
my $branch=$userenv->{branch}; |
841 |
my $hbr= $item->{ C4::Context->preference("HomeOrHoldingBranch") }; |
829 |
if ( C4::Context->preference("IndependantBranches") ) { |
842 |
if ( C4::Context->preference("IndependantBranches") ) { |
830 |
my $userenv = C4::Context->userenv; |
|
|
831 |
if ( ($userenv) && ( $userenv->{flags} % 2 != 1 ) ) { |
843 |
if ( ($userenv) && ( $userenv->{flags} % 2 != 1 ) ) { |
832 |
$issuingimpossible{ITEMNOTSAMEBRANCH} = 1 |
844 |
$issuingimpossible{ITEMNOTSAMEBRANCH} = 1 |
833 |
if ( $item->{C4::Context->preference("HomeOrHoldingBranch")} ne $userenv->{branch} ); |
845 |
if ( $hbr ne $branch ); |
834 |
$needsconfirmation{BORRNOTSAMEBRANCH} = GetBranchName( $borrower->{'branchcode'} ) |
846 |
$needsconfirmation{BORRNOTSAMEBRANCH} = GetBranchName( $borrower->{'branchcode'} ) |
835 |
if ( $borrower->{'branchcode'} ne $userenv->{branch} ); |
847 |
if ( $borrower->{'branchcode'} ne $userenv->{branch} ); |
836 |
} |
848 |
} |
837 |
} |
849 |
} |
|
|
850 |
my $branchtransferfield=C4::Context->preference("BranchTransferLimitsType") eq "ccode" ? "ccode" : "itype"; |
851 |
if ( C4::Context->preference("UseBranchTransferLimits") |
852 |
and !IsBranchTransferAllowed( $branch, $hbr, $item->{ $branchtransferfield } ) ) { |
853 |
$needsconfirmation{BRANCH_TRANSFER_NOT_ALLOWED} = $hbr; |
854 |
} |
855 |
|
838 |
|
856 |
|
839 |
# |
857 |
# |
840 |
# CHECK IF BOOK ALREADY ISSUED TO THIS BORROWER |
858 |
# CHECK IF BOOK ALREADY ISSUED TO THIS BORROWER |
Lines 875-904
sub CanBookBeIssued {
Link Here
|
875 |
my ( $resborrower ) = C4::Members::GetMemberDetails( $resbor, 0 ); |
893 |
my ( $resborrower ) = C4::Members::GetMemberDetails( $resbor, 0 ); |
876 |
my $branches = GetBranches(); |
894 |
my $branches = GetBranches(); |
877 |
my $branchname = $branches->{ $res->{'branchcode'} }->{'branchname'}; |
895 |
my $branchname = $branches->{ $res->{'branchcode'} }->{'branchname'}; |
878 |
if ( $resbor ne $borrower->{'borrowernumber'} && $restype eq "Waiting" ) |
896 |
if( $resbor ne $borrower->{'borrowernumber'}){ |
879 |
{ |
897 |
if ( $restype eq "Waiting" ) { |
880 |
# The item is on reserve and waiting, but has been |
898 |
# The item is on reserve and waiting, but has been |
881 |
# reserved by some other patron. |
899 |
# reserved by some other patron. |
882 |
$needsconfirmation{RESERVE_WAITING} = 1; |
900 |
$needsconfirmation{RESERVE_WAITING} = |
883 |
$needsconfirmation{'resfirstname'} = $resborrower->{'firstname'}; |
901 |
"$resborrower->{'firstname'} $resborrower->{'surname'} ($resborrower->{'cardnumber'}, $branchname)"; |
884 |
$needsconfirmation{'ressurname'} = $resborrower->{'surname'}; |
902 |
} |
885 |
$needsconfirmation{'rescardnumber'} = $resborrower->{'cardnumber'}; |
903 |
elsif ( $restype eq "Reserved" ) { |
886 |
$needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'}; |
904 |
# The item is on reserve for someone else. |
887 |
$needsconfirmation{'resbranchname'} = $branchname; |
905 |
$needsconfirmation{RESERVED} = |
888 |
$needsconfirmation{'reswaitingdate'} = format_date($res->{'waitingdate'}); |
906 |
"$res->{'reservedate'} : $resborrower->{'firstname'} $resborrower->{'surname'} ($resborrower->{'cardnumber'})"; |
889 |
} |
907 |
} |
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 |
} |
908 |
} |
900 |
} |
909 |
} |
901 |
return ( \%issuingimpossible, \%needsconfirmation ); |
910 |
return ( \%issuingimpossible, \%needsconfirmation ); |
902 |
} |
911 |
} |
903 |
|
912 |
|
904 |
=head2 AddIssue |
913 |
=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 |
988 |
# who wants to borrow it now. mark it returned before issuing to the new borrower |
980 |
AddReturn( |
989 |
AddReturn( |
981 |
$item->{'barcode'}, |
990 |
$item->{'barcode'}, |
982 |
C4::Context->userenv->{'branch'} |
991 |
C4::Context->userenv->{'branch'}, |
|
|
992 |
undef, |
993 |
undef, |
994 |
1 |
983 |
); |
995 |
); |
984 |
} |
996 |
} |
985 |
|
997 |
|
Lines 1012-1018
sub AddIssue {
Link Here
|
1012 |
ModReserve(1, |
1024 |
ModReserve(1, |
1013 |
$res->{'biblionumber'}, |
1025 |
$res->{'biblionumber'}, |
1014 |
$res->{'borrowernumber'}, |
1026 |
$res->{'borrowernumber'}, |
1015 |
$res->{'branchcode'} |
1027 |
$res->{'branchcode'}, |
|
|
1028 |
undef, |
1029 |
$res->{'reservenumber'} |
1016 |
); |
1030 |
); |
1017 |
} |
1031 |
} |
1018 |
} |
1032 |
} |
Lines 1102-1111
sub AddIssue {
Link Here
|
1102 |
branch => $branch, |
1116 |
branch => $branch, |
1103 |
}); |
1117 |
}); |
1104 |
} |
1118 |
} |
|
|
1119 |
|
1120 |
logaction( "CIRCULATION", "ISSUE", $borrower->{'borrowernumber'}, $item->{'itemnumber'} ) |
1121 |
if C4::Context->preference("IssueLog"); |
1105 |
} |
1122 |
} |
1106 |
|
1123 |
|
1107 |
logaction("CIRCULATION", "ISSUE", $borrower->{'borrowernumber'}, $biblio->{'biblionumber'}) |
|
|
1108 |
if C4::Context->preference("IssueLog"); |
1109 |
} |
1124 |
} |
1110 |
return ($datedue); # not necessarily the same as when it came in! |
1125 |
return ($datedue); # not necessarily the same as when it came in! |
1111 |
} |
1126 |
} |
Lines 1120-1373
Get loan length for an itemtype, a borrower type and a branch
Link Here
|
1120 |
|
1135 |
|
1121 |
sub GetLoanLength { |
1136 |
sub GetLoanLength { |
1122 |
my ( $borrowertype, $itemtype, $branchcode ) = @_; |
1137 |
my ( $borrowertype, $itemtype, $branchcode ) = @_; |
1123 |
my $dbh = C4::Context->dbh; |
1138 |
my $loanlength=GetIssuingRule($borrowertype,$itemtype,$branchcode); |
1124 |
my $sth = |
1139 |
return $loanlength->{issuelength}; |
1125 |
$dbh->prepare( |
|
|
1126 |
"select issuelength from issuingrules where categorycode=? and itemtype=? and branchcode=? and issuelength is not null" |
1127 |
); |
1128 |
# warn "in get loan lenght $borrowertype $itemtype $branchcode "; |
1129 |
# try to find issuelength & return the 1st available. |
1130 |
# check with borrowertype, itemtype and branchcode, then without one of those parameters |
1131 |
$sth->execute( $borrowertype, $itemtype, $branchcode ); |
1132 |
my $loanlength = $sth->fetchrow_hashref; |
1133 |
return $loanlength->{issuelength} |
1134 |
if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; |
1135 |
|
1136 |
$sth->execute( $borrowertype, "*", $branchcode ); |
1137 |
$loanlength = $sth->fetchrow_hashref; |
1138 |
return $loanlength->{issuelength} |
1139 |
if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; |
1140 |
|
1141 |
$sth->execute( "*", $itemtype, $branchcode ); |
1142 |
$loanlength = $sth->fetchrow_hashref; |
1143 |
return $loanlength->{issuelength} |
1144 |
if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; |
1145 |
|
1146 |
$sth->execute( "*", "*", $branchcode ); |
1147 |
$loanlength = $sth->fetchrow_hashref; |
1148 |
return $loanlength->{issuelength} |
1149 |
if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; |
1150 |
|
1151 |
$sth->execute( $borrowertype, $itemtype, "*" ); |
1152 |
$loanlength = $sth->fetchrow_hashref; |
1153 |
return $loanlength->{issuelength} |
1154 |
if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; |
1155 |
|
1156 |
$sth->execute( $borrowertype, "*", "*" ); |
1157 |
$loanlength = $sth->fetchrow_hashref; |
1158 |
return $loanlength->{issuelength} |
1159 |
if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; |
1160 |
|
1161 |
$sth->execute( "*", $itemtype, "*" ); |
1162 |
$loanlength = $sth->fetchrow_hashref; |
1163 |
return $loanlength->{issuelength} |
1164 |
if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; |
1165 |
|
1166 |
$sth->execute( "*", "*", "*" ); |
1167 |
$loanlength = $sth->fetchrow_hashref; |
1168 |
return $loanlength->{issuelength} |
1169 |
if defined($loanlength) && $loanlength->{issuelength} ne 'NULL'; |
1170 |
|
1171 |
# if no rule is set => 21 days (hardcoded) |
1172 |
return 21; |
1173 |
} |
1174 |
|
1175 |
=head2 GetIssuingRule |
1176 |
|
1177 |
my $irule = &GetIssuingRule($borrowertype,$itemtype,branchcode) |
1178 |
|
1179 |
FIXME - This is a copy-paste of GetLoanLength |
1180 |
as a stop-gap. Do not wish to change API for GetLoanLength |
1181 |
this close to release, however, Overdues::GetIssuingRules is broken. |
1182 |
|
1183 |
Get the issuing rule for an itemtype, a borrower type and a branch |
1184 |
Returns a hashref from the issuingrules table. |
1185 |
|
1186 |
=cut |
1187 |
|
1188 |
sub GetIssuingRule { |
1189 |
my ( $borrowertype, $itemtype, $branchcode ) = @_; |
1190 |
my $dbh = C4::Context->dbh; |
1191 |
my $sth = $dbh->prepare( "select * from issuingrules where categorycode=? and itemtype=? and branchcode=? and issuelength is not null" ); |
1192 |
my $irule; |
1193 |
|
1194 |
$sth->execute( $borrowertype, $itemtype, $branchcode ); |
1195 |
$irule = $sth->fetchrow_hashref; |
1196 |
return $irule if defined($irule) ; |
1197 |
|
1198 |
$sth->execute( $borrowertype, "*", $branchcode ); |
1199 |
$irule = $sth->fetchrow_hashref; |
1200 |
return $irule if defined($irule) ; |
1201 |
|
1202 |
$sth->execute( "*", $itemtype, $branchcode ); |
1203 |
$irule = $sth->fetchrow_hashref; |
1204 |
return $irule if defined($irule) ; |
1205 |
|
1206 |
$sth->execute( "*", "*", $branchcode ); |
1207 |
$irule = $sth->fetchrow_hashref; |
1208 |
return $irule if defined($irule) ; |
1209 |
|
1210 |
$sth->execute( $borrowertype, $itemtype, "*" ); |
1211 |
$irule = $sth->fetchrow_hashref; |
1212 |
return $irule if defined($irule) ; |
1213 |
|
1214 |
$sth->execute( $borrowertype, "*", "*" ); |
1215 |
$irule = $sth->fetchrow_hashref; |
1216 |
return $irule if defined($irule) ; |
1217 |
|
1218 |
$sth->execute( "*", $itemtype, "*" ); |
1219 |
$irule = $sth->fetchrow_hashref; |
1220 |
return $irule if defined($irule) ; |
1221 |
|
1222 |
$sth->execute( "*", "*", "*" ); |
1223 |
$irule = $sth->fetchrow_hashref; |
1224 |
return $irule if defined($irule) ; |
1225 |
|
1226 |
# if no rule matches, |
1227 |
return undef; |
1228 |
} |
1229 |
|
1230 |
=head2 GetBranchBorrowerCircRule |
1231 |
|
1232 |
my $branch_cat_rule = GetBranchBorrowerCircRule($branchcode, $categorycode); |
1233 |
|
1234 |
Retrieves circulation rule attributes that apply to the given |
1235 |
branch and patron category, regardless of item type. |
1236 |
The return value is a hashref containing the following key: |
1237 |
|
1238 |
maxissueqty - maximum number of loans that a |
1239 |
patron of the given category can have at the given |
1240 |
branch. If the value is undef, no limit. |
1241 |
|
1242 |
This will first check for a specific branch and |
1243 |
category match from branch_borrower_circ_rules. |
1244 |
|
1245 |
If no rule is found, it will then check default_branch_circ_rules |
1246 |
(same branch, default category). If no rule is found, |
1247 |
it will then check default_borrower_circ_rules (default |
1248 |
branch, same category), then failing that, default_circ_rules |
1249 |
(default branch, default category). |
1250 |
|
1251 |
If no rule has been found in the database, it will default to |
1252 |
the buillt in rule: |
1253 |
|
1254 |
maxissueqty - undef |
1255 |
|
1256 |
C<$branchcode> and C<$categorycode> should contain the |
1257 |
literal branch code and patron category code, respectively - no |
1258 |
wildcards. |
1259 |
|
1260 |
=cut |
1261 |
|
1262 |
sub GetBranchBorrowerCircRule { |
1263 |
my $branchcode = shift; |
1264 |
my $categorycode = shift; |
1265 |
|
1266 |
my $branch_cat_query = "SELECT maxissueqty |
1267 |
FROM branch_borrower_circ_rules |
1268 |
WHERE branchcode = ? |
1269 |
AND categorycode = ?"; |
1270 |
my $dbh = C4::Context->dbh(); |
1271 |
my $sth = $dbh->prepare($branch_cat_query); |
1272 |
$sth->execute($branchcode, $categorycode); |
1273 |
my $result; |
1274 |
if ($result = $sth->fetchrow_hashref()) { |
1275 |
return $result; |
1276 |
} |
1277 |
|
1278 |
# try same branch, default borrower category |
1279 |
my $branch_query = "SELECT maxissueqty |
1280 |
FROM default_branch_circ_rules |
1281 |
WHERE branchcode = ?"; |
1282 |
$sth = $dbh->prepare($branch_query); |
1283 |
$sth->execute($branchcode); |
1284 |
if ($result = $sth->fetchrow_hashref()) { |
1285 |
return $result; |
1286 |
} |
1287 |
|
1288 |
# try default branch, same borrower category |
1289 |
my $category_query = "SELECT maxissueqty |
1290 |
FROM default_borrower_circ_rules |
1291 |
WHERE categorycode = ?"; |
1292 |
$sth = $dbh->prepare($category_query); |
1293 |
$sth->execute($categorycode); |
1294 |
if ($result = $sth->fetchrow_hashref()) { |
1295 |
return $result; |
1296 |
} |
1297 |
|
1298 |
# try default branch, default borrower category |
1299 |
my $default_query = "SELECT maxissueqty |
1300 |
FROM default_circ_rules"; |
1301 |
$sth = $dbh->prepare($default_query); |
1302 |
$sth->execute(); |
1303 |
if ($result = $sth->fetchrow_hashref()) { |
1304 |
return $result; |
1305 |
} |
1306 |
|
1307 |
# built-in default circulation rule |
1308 |
return { |
1309 |
maxissueqty => undef, |
1310 |
}; |
1311 |
} |
1312 |
|
1313 |
=head2 GetBranchItemRule |
1314 |
|
1315 |
my $branch_item_rule = GetBranchItemRule($branchcode, $itemtype); |
1316 |
|
1317 |
Retrieves circulation rule attributes that apply to the given |
1318 |
branch and item type, regardless of patron category. |
1319 |
|
1320 |
The return value is a hashref containing the following key: |
1321 |
|
1322 |
holdallowed => Hold policy for this branch and itemtype. Possible values: |
1323 |
0: No holds allowed. |
1324 |
1: Holds allowed only by patrons that have the same homebranch as the item. |
1325 |
2: Holds allowed from any patron. |
1326 |
|
1327 |
This searches branchitemrules in the following order: |
1328 |
|
1329 |
* Same branchcode and itemtype |
1330 |
* Same branchcode, itemtype '*' |
1331 |
* branchcode '*', same itemtype |
1332 |
* branchcode and itemtype '*' |
1333 |
|
1334 |
Neither C<$branchcode> nor C<$categorycode> should be '*'. |
1335 |
|
1336 |
=cut |
1337 |
|
1338 |
sub GetBranchItemRule { |
1339 |
my ( $branchcode, $itemtype ) = @_; |
1340 |
my $dbh = C4::Context->dbh(); |
1341 |
my $result = {}; |
1342 |
|
1343 |
my @attempts = ( |
1344 |
['SELECT holdallowed |
1345 |
FROM branch_item_rules |
1346 |
WHERE branchcode = ? |
1347 |
AND itemtype = ?', $branchcode, $itemtype], |
1348 |
['SELECT holdallowed |
1349 |
FROM default_branch_circ_rules |
1350 |
WHERE branchcode = ?', $branchcode], |
1351 |
['SELECT holdallowed |
1352 |
FROM default_branch_item_rules |
1353 |
WHERE itemtype = ?', $itemtype], |
1354 |
['SELECT holdallowed |
1355 |
FROM default_circ_rules'], |
1356 |
); |
1357 |
|
1358 |
foreach my $attempt (@attempts) { |
1359 |
my ($query, @bind_params) = @{$attempt}; |
1360 |
|
1361 |
# Since branch/category and branch/itemtype use the same per-branch |
1362 |
# defaults tables, we have to check that the key we want is set, not |
1363 |
# just that a row was returned |
1364 |
return $result if ( defined( $result->{'holdallowed'} = $dbh->selectrow_array( $query, {}, @bind_params ) ) ); |
1365 |
} |
1366 |
|
1367 |
# built-in default circulation rule |
1368 |
return { |
1369 |
holdallowed => 2, |
1370 |
}; |
1371 |
} |
1140 |
} |
1372 |
|
1141 |
|
1373 |
=head2 AddReturn |
1142 |
=head2 AddReturn |
Lines 1445-1452
patron who last borrowed the book.
Link Here
|
1445 |
=cut |
1214 |
=cut |
1446 |
|
1215 |
|
1447 |
sub AddReturn { |
1216 |
sub AddReturn { |
1448 |
my ( $barcode, $branch, $exemptfine, $dropbox ) = @_; |
1217 |
my ( $barcode, $branch, $exemptfine, $dropbox, $force) = @_; |
1449 |
if ($branch and not GetBranchDetail($branch)) { |
1218 |
if ( $branch and not GetBranchDetail($branch) ) { |
1450 |
warn "AddReturn error: branch '$branch' not found. Reverting to " . C4::Context->userenv->{'branch'}; |
1219 |
warn "AddReturn error: branch '$branch' not found. Reverting to " . C4::Context->userenv->{'branch'}; |
1451 |
undef $branch; |
1220 |
undef $branch; |
1452 |
} |
1221 |
} |
Lines 1490-1498
sub AddReturn {
Link Here
|
1490 |
my $branches = GetBranches(); # a potentially expensive call for a non-feature. |
1259 |
my $branches = GetBranches(); # a potentially expensive call for a non-feature. |
1491 |
$branches->{$hbr}->{PE} and $messages->{'IsPermanent'} = $hbr; |
1260 |
$branches->{$hbr}->{PE} and $messages->{'IsPermanent'} = $hbr; |
1492 |
} |
1261 |
} |
1493 |
|
1262 |
my $branchtransferfield=C4::Context->preference("BranchTransferLimitsType") eq "ccode" ? "ccode" : "itype"; |
|
|
1263 |
$debug && warn "$branch, $hbr, ",C4::Context->preference("BranchTransferLimitsType")," ,",$item->{ $branchtransferfield } ; |
1264 |
$debug && warn Dump($item); |
1265 |
$debug && warn IsBranchTransferAllowed( $branch, $hbr, $item->{ C4::Context->preference("BranchTransferLimitsType") } ); |
1494 |
# if indy branches and returning to different branch, refuse the return |
1266 |
# if indy branches and returning to different branch, refuse the return |
1495 |
if ($hbr ne $branch && C4::Context->preference("IndependantBranches")){ |
1267 |
if ( !$force && ($hbr ne $branch) |
|
|
1268 |
&& (C4::Context->preference("IndependantBranches") |
1269 |
or ( C4::Context->preference("UseBranchTransferLimits") |
1270 |
and !IsBranchTransferAllowed( $branch, $hbr, $item->{$branchtransferfield } ) ) |
1271 |
) |
1272 |
){ |
1496 |
$messages->{'Wrongbranch'} = { |
1273 |
$messages->{'Wrongbranch'} = { |
1497 |
Wrongbranch => $branch, |
1274 |
Wrongbranch => $branch, |
1498 |
Rightbranch => $hbr, |
1275 |
Rightbranch => $hbr, |
Lines 1503-1509
sub AddReturn {
Link Here
|
1503 |
# FIXME - even in an indy branches situation, there should |
1280 |
# FIXME - even in an indy branches situation, there should |
1504 |
# still be an option for the library to accept the item |
1281 |
# still be an option for the library to accept the item |
1505 |
# and transfer it to its owning library. |
1282 |
# and transfer it to its owning library. |
1506 |
return ( $doreturn, $messages, $issue, $borrower ); |
|
|
1507 |
} |
1283 |
} |
1508 |
|
1284 |
|
1509 |
if ( $item->{'wthdrawn'} ) { # book has been cancelled |
1285 |
if ( $item->{'wthdrawn'} ) { # book has been cancelled |
Lines 1514-1525
sub AddReturn {
Link Here
|
1514 |
# case of a return of document (deal with issues and holdingbranch) |
1290 |
# case of a return of document (deal with issues and holdingbranch) |
1515 |
if ($doreturn) { |
1291 |
if ($doreturn) { |
1516 |
$borrower or warn "AddReturn without current borrower"; |
1292 |
$borrower or warn "AddReturn without current borrower"; |
1517 |
my $circControlBranch; |
1293 |
my $circControlBranch; |
1518 |
if ($dropbox) { |
1294 |
if ($dropbox) { |
1519 |
# define circControlBranch only if dropbox mode is set |
1295 |
$circControlBranch = _GetCircControlBranch( $item, $borrower ); |
1520 |
# don't allow dropbox mode to create an invalid entry in issues (issuedate > today) |
1296 |
# don't allow dropbox mode to create an invalid entry in issues (issuedate > returndate) FIXME: actually checks eq, not gt |
1521 |
# FIXME: check issuedate > returndate, factoring in holidays |
1297 |
undef($dropbox) if ( $item->{'issuedate'} eq C4::Dates->today('iso') ); |
1522 |
$circControlBranch = _GetCircControlBranch($item,$borrower) unless ( $item->{'issuedate'} eq C4::Dates->today('iso') );; |
|
|
1523 |
} |
1298 |
} |
1524 |
|
1299 |
|
1525 |
if ($borrowernumber) { |
1300 |
if ($borrowernumber) { |
Lines 1527-1541
sub AddReturn {
Link Here
|
1527 |
$messages->{'WasReturned'} = 1; # FIXME is the "= 1" right? This could be the borrower hash. |
1302 |
$messages->{'WasReturned'} = 1; # FIXME is the "= 1" right? This could be the borrower hash. |
1528 |
} |
1303 |
} |
1529 |
|
1304 |
|
1530 |
ModItem({ onloan => undef }, $issue->{'biblionumber'}, $item->{'itemnumber'}); |
1305 |
ModItem( { renewals=>0, onloan => undef }, $issue->{'biblionumber'}, $item->{'itemnumber'} ); |
|
|
1306 |
# the holdingbranch is updated if the document is returned to another location. |
1307 |
# this is always done regardless of whether the item was on loan or not |
1308 |
if ( $item->{'holdingbranch'} ne $branch ) { |
1309 |
UpdateHoldingbranch( $branch, $item->{'itemnumber'} ); |
1310 |
$item->{'holdingbranch'} = $branch; # update item data holdingbranch too |
1311 |
} |
1531 |
} |
1312 |
} |
1532 |
|
1313 |
|
1533 |
# the holdingbranch is updated if the document is returned to another location. |
|
|
1534 |
# this is always done regardless of whether the item was on loan or not |
1535 |
if ($item->{'holdingbranch'} ne $branch) { |
1536 |
UpdateHoldingbranch($branch, $item->{'itemnumber'}); |
1537 |
$item->{'holdingbranch'} = $branch; # update item data holdingbranch too |
1538 |
} |
1539 |
ModDateLastSeen( $item->{'itemnumber'} ); |
1314 |
ModDateLastSeen( $item->{'itemnumber'} ); |
1540 |
|
1315 |
|
1541 |
# check if we have a transfer for this document |
1316 |
# check if we have a transfer for this document |
Lines 1562-1572
sub AddReturn {
Link Here
|
1562 |
_FixAccountForLostAndReturned($item->{'itemnumber'}, $borrowernumber, $barcode); # can tolerate undef $borrowernumber |
1337 |
_FixAccountForLostAndReturned($item->{'itemnumber'}, $borrowernumber, $barcode); # can tolerate undef $borrowernumber |
1563 |
$messages->{'WasLost'} = 1; |
1338 |
$messages->{'WasLost'} = 1; |
1564 |
} |
1339 |
} |
|
|
1340 |
if ($item->{'notforloan'}){ |
1341 |
$messages->{'NotForLoan'} = $item->{'notforloan'}; |
1342 |
} |
1343 |
if ($item->{'damaged'}){ |
1344 |
$messages->{'Damaged'} = $item->{'damaged'}; |
1345 |
} |
1565 |
|
1346 |
|
1566 |
# fix up the overdues in accounts... |
1347 |
if ($borrowernumber && $doreturn) { |
1567 |
if ($borrowernumber) { |
1348 |
# fix up the overdues in accounts... |
1568 |
my $fix = _FixOverduesOnReturn($borrowernumber, $item->{itemnumber}, $exemptfine, $dropbox); |
1349 |
my $fix = _FixOverduesOnReturn($borrowernumber, $item->{itemnumber}, $exemptfine, $dropbox); |
1569 |
defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $item->{itemnumber}...) failed!"; # zero is OK, check defined |
1350 |
defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $item->{itemnumber}...) failed!"; # zero is OK, check defined |
|
|
1351 |
|
1352 |
# fix fine days |
1353 |
my $debardate = _FixFineDaysOnReturn($borrower, $item, $issue->{date_due}); |
1354 |
$messages->{'Debarred'} = $debardate if($debardate); |
1355 |
|
1356 |
# get fines for the borrower |
1357 |
my $fineamount = C4::Overdues::GetFine($borrowernumber); |
1358 |
$messages->{'HaveFines'} = $fineamount if($fineamount); |
1359 |
|
1570 |
} |
1360 |
} |
1571 |
|
1361 |
|
1572 |
# find reserves..... |
1362 |
# find reserves..... |
Lines 1602-1621
sub AddReturn {
Link Here
|
1602 |
branch => $branch, |
1392 |
branch => $branch, |
1603 |
}); |
1393 |
}); |
1604 |
} |
1394 |
} |
1605 |
|
1395 |
|
1606 |
logaction("CIRCULATION", "RETURN", $borrowernumber, $item->{'biblionumber'}) |
1396 |
logaction( "CIRCULATION", "RETURN", $borrowernumber, $item->{'itemnumber'} ) |
1607 |
if C4::Context->preference("ReturnLog"); |
1397 |
if C4::Context->preference("ReturnLog"); |
1608 |
|
1398 |
|
1609 |
# FIXME: make this comment intelligible. |
1399 |
# FIXME: make this comment intelligible. |
1610 |
#adding message if holdingbranch is non equal a userenv branch to return the document to homebranch |
1400 |
#adding message if holdingbranch is non equal a userenv branch to return the document to homebranch |
1611 |
#we check, if we don't have reserv or transfert for this document, if not, return it to homebranch . |
1401 |
#we check, if we don't have reserv or transfert for this document, if not, return it to homebranch . |
1612 |
|
1402 |
|
1613 |
if ($doreturn and ($branch ne $hbr) and not $messages->{'WrongTransfer'} and ($validTransfert ne 1) ){ |
1403 |
if ( $doreturn and ( $branch ne $hbr ) and not $messages->{'WrongTransfer'} and ( $validTransfert ne 1 ) ) { |
1614 |
if ( C4::Context->preference("AutomaticItemReturn" ) or |
1404 |
if (C4::Context->preference("AutomaticItemReturn") |
1615 |
(C4::Context->preference("UseBranchTransferLimits") and |
1405 |
or ( C4::Context->preference("UseBranchTransferLimits") |
1616 |
! IsBranchTransferAllowed($branch, $hbr, $item->{C4::Context->preference("BranchTransferLimitsType")} ) |
1406 |
and !IsBranchTransferAllowed( $branch, $hbr, $item->{ $branchtransferfield } ) ) |
1617 |
)) { |
1407 |
) { |
1618 |
$debug and warn sprintf "about to call ModItemTransfer(%s, %s, %s)", $item->{'itemnumber'},$branch, $hbr; |
1408 |
$debug and warn sprintf "about to call ModItemTransfer(%s, %s, %s)", $item->{'itemnumber'}, $branch, $hbr; |
1619 |
$debug and warn "item: " . Dumper($item); |
1409 |
$debug and warn "item: " . Dumper($item); |
1620 |
ModItemTransfer($item->{'itemnumber'}, $branch, $hbr); |
1410 |
ModItemTransfer($item->{'itemnumber'}, $branch, $hbr); |
1621 |
$messages->{'WasTransfered'} = 1; |
1411 |
$messages->{'WasTransfered'} = 1; |
Lines 1690-1695
sub MarkIssueReturned {
Link Here
|
1690 |
$sth_del->execute($borrowernumber, $itemnumber); |
1480 |
$sth_del->execute($borrowernumber, $itemnumber); |
1691 |
} |
1481 |
} |
1692 |
|
1482 |
|
|
|
1483 |
=head2 _FixFineDaysOnReturn |
1484 |
|
1485 |
&_FixFineDaysOnReturn($borrower, $item, $datedue); |
1486 |
|
1487 |
C<$borrower> borrower hashref |
1488 |
|
1489 |
C<$item> item hashref |
1490 |
|
1491 |
C<$datedue> date due |
1492 |
|
1493 |
Internal function, called only by AddReturn that calculate and update the user fine days, and debars him |
1494 |
|
1495 |
=cut |
1496 |
|
1497 |
sub _FixFineDaysOnReturn { |
1498 |
my ($borrower, $item, $datedue) = @_; |
1499 |
|
1500 |
if($datedue){ |
1501 |
$datedue = C4::Dates->new($datedue,"iso"); |
1502 |
}else{ |
1503 |
return; |
1504 |
} |
1505 |
|
1506 |
my $branchcode =_GetCircControlBranch($item, $borrower); |
1507 |
my $calendar = C4::Calendar->new( branchcode => $branchcode ); |
1508 |
my $today = C4::Dates->new(); |
1509 |
|
1510 |
my $deltadays = $calendar->daysBetween($datedue, C4::Dates->new()); |
1511 |
|
1512 |
my $circcontrol = C4::Context::preference('CircControl'); |
1513 |
my $issuingrule = GetIssuingRule($borrower->{categorycode}, $item->{itype}, $branchcode); |
1514 |
my $finedays = $issuingrule->{finedays}; |
1515 |
# exit if no finedays defined |
1516 |
return unless $finedays; |
1517 |
my $grace = $issuingrule->{firstremind}; |
1518 |
|
1519 |
if( $deltadays - $grace > 0){ |
1520 |
my @newdate = Add_Delta_Days(Today(), $deltadays * $finedays ); |
1521 |
my $isonewdate = join('-',@newdate); |
1522 |
my ($deby, $debm, $debd) = split(/-/,$borrower->{debarred}); |
1523 |
if(check_date($deby, $debm, $debd)){ |
1524 |
my @olddate = split(/-/, $borrower->{debarred}); |
1525 |
|
1526 |
if(Delta_Days(@olddate,@newdate) > 0){ |
1527 |
C4::Members::DebarMember($borrower->{borrowernumber}, $isonewdate); |
1528 |
return $isonewdate; |
1529 |
} |
1530 |
}else{ |
1531 |
C4::Members::DebarMember($borrower->{borrowernumber}, $isonewdate); |
1532 |
return $isonewdate; |
1533 |
} |
1534 |
} |
1535 |
} |
1536 |
|
1537 |
|
1693 |
=head2 _FixOverduesOnReturn |
1538 |
=head2 _FixOverduesOnReturn |
1694 |
|
1539 |
|
1695 |
&_FixOverduesOnReturn($brn,$itm, $exemptfine, $dropboxmode); |
1540 |
&_FixOverduesOnReturn($brn,$itm, $exemptfine, $dropboxmode); |
Lines 1864-1870
sub _GetCircControlBranch {
Link Here
|
1864 |
my $circcontrol = C4::Context->preference('CircControl'); |
1709 |
my $circcontrol = C4::Context->preference('CircControl'); |
1865 |
my $branch; |
1710 |
my $branch; |
1866 |
|
1711 |
|
1867 |
if ($circcontrol eq 'PickupLibrary') { |
1712 |
if ($circcontrol eq 'PickupLibrary' && C4::Context->userenv->{'branch'}) { |
1868 |
$branch= C4::Context->userenv->{'branch'}; |
1713 |
$branch= C4::Context->userenv->{'branch'}; |
1869 |
} elsif ($circcontrol eq 'PatronLibrary') { |
1714 |
} elsif ($circcontrol eq 'PatronLibrary') { |
1870 |
$branch=$borrower->{branchcode}; |
1715 |
$branch=$borrower->{branchcode}; |
Lines 1901-1907
sub GetItemIssue {
Link Here
|
1901 |
my ($itemnumber) = @_; |
1746 |
my ($itemnumber) = @_; |
1902 |
return unless $itemnumber; |
1747 |
return unless $itemnumber; |
1903 |
my $sth = C4::Context->dbh->prepare( |
1748 |
my $sth = C4::Context->dbh->prepare( |
1904 |
"SELECT * |
1749 |
"SELECT *, issues.renewals as 'issues.renewals' |
1905 |
FROM issues |
1750 |
FROM issues |
1906 |
LEFT JOIN items ON issues.itemnumber=items.itemnumber |
1751 |
LEFT JOIN items ON issues.itemnumber=items.itemnumber |
1907 |
WHERE issues.itemnumber=?"); |
1752 |
WHERE issues.itemnumber=?"); |
Lines 1972-1978
sub GetItemIssues {
Link Here
|
1972 |
} |
1817 |
} |
1973 |
my $results = $sth->fetchall_arrayref({}); |
1818 |
my $results = $sth->fetchall_arrayref({}); |
1974 |
foreach (@$results) { |
1819 |
foreach (@$results) { |
1975 |
$_->{'overdue'} = ($_->{'date_due'} lt $today) ? 1 : 0; |
1820 |
$_->{'overdue'} = ( $_->{'date_due'} lt $today && !defined($_->{return_date}) ) ? 1 : 0; |
1976 |
} |
1821 |
} |
1977 |
return $results; |
1822 |
return $results; |
1978 |
} |
1823 |
} |
Lines 2078-2146
already renewed the loan. $error will contain the reason the renewal can not pro
Link Here
|
2078 |
sub CanBookBeRenewed { |
1923 |
sub CanBookBeRenewed { |
2079 |
|
1924 |
|
2080 |
# check renewal status |
1925 |
# check renewal status |
2081 |
my ( $borrowernumber, $itemnumber, $override_limit ) = @_; |
1926 |
my ( $borrowernumber, $itemnumber ) = @_; |
2082 |
my $dbh = C4::Context->dbh; |
1927 |
my $dbh = C4::Context->dbh; |
2083 |
my $renews = 1; |
1928 |
my $renews = 1; |
2084 |
my $renewokay = 0; |
1929 |
my $renewokay = 1; |
2085 |
my $error; |
1930 |
my $error; |
2086 |
|
1931 |
|
2087 |
# Look in the issues table for this item, lent to this borrower, |
1932 |
# Look in the issues table for this item, lent to this borrower, |
2088 |
# and not yet returned. |
1933 |
# and not yet returned. |
2089 |
|
1934 |
|
2090 |
# Look in the issues table for this item, lent to this borrower, |
1935 |
# Look in the issues table for this item, lent to this borrower, |
2091 |
# and not yet returned. |
1936 |
# and not yet returned. |
2092 |
my %branch = ( |
1937 |
my $borrower = C4::Members::GetMemberDetails( $borrowernumber, 0 ) or return undef; |
2093 |
'ItemHomeLibrary' => 'items.homebranch', |
1938 |
my $item = GetItem($itemnumber) or return undef; |
2094 |
'PickupLibrary' => 'items.holdingbranch', |
1939 |
my $itemissue = GetItemIssue($itemnumber) or return undef; |
2095 |
'PatronLibrary' => 'borrowers.branchcode' |
1940 |
my $branchcode = _GetCircControlBranch($item, $borrower); |
2096 |
); |
1941 |
if ($itemissue->{'overdue'}){ |
2097 |
my $controlbranch = $branch{C4::Context->preference('CircControl')}; |
1942 |
$renewokay=0; |
2098 |
my $itype = C4::Context->preference('item-level_itypes') ? 'items.itype' : 'biblioitems.itemtype'; |
1943 |
$error->{message}='overdue'; |
|
|
1944 |
} |
2099 |
|
1945 |
|
2100 |
my $sthcount = $dbh->prepare(" |
1946 |
my $issuingrule = GetIssuingRule($borrower->{categorycode}, $item->{itype}, $branchcode); |
2101 |
SELECT |
1947 |
|
2102 |
borrowers.categorycode, biblioitems.itemtype, issues.renewals, renewalsallowed, $controlbranch |
1948 |
if ( $issuingrule->{renewalsallowed} <= $itemissue->{'issues.renewals'} ) { |
2103 |
FROM issuingrules, |
1949 |
$renewokay=0; |
2104 |
issues |
1950 |
$error->{message} = "too_many"; |
2105 |
LEFT JOIN items USING (itemnumber) |
1951 |
} |
2106 |
LEFT JOIN borrowers USING (borrowernumber) |
|
|
2107 |
LEFT JOIN biblioitems USING (biblioitemnumber) |
2108 |
|
2109 |
WHERE |
2110 |
(issuingrules.categorycode = borrowers.categorycode OR issuingrules.categorycode = '*') |
2111 |
AND |
2112 |
(issuingrules.itemtype = $itype OR issuingrules.itemtype = '*') |
2113 |
AND |
2114 |
(issuingrules.branchcode = $controlbranch OR issuingrules.branchcode = '*') |
2115 |
AND |
2116 |
borrowernumber = ? |
2117 |
AND |
2118 |
itemnumber = ? |
2119 |
ORDER BY |
2120 |
issuingrules.categorycode desc, |
2121 |
issuingrules.itemtype desc, |
2122 |
issuingrules.branchcode desc |
2123 |
LIMIT 1; |
2124 |
"); |
2125 |
|
2126 |
$sthcount->execute( $borrowernumber, $itemnumber ); |
2127 |
if ( my $data1 = $sthcount->fetchrow_hashref ) { |
2128 |
|
2129 |
if ( ( $data1->{renewalsallowed} && $data1->{renewalsallowed} > $data1->{renewals} ) || $override_limit ) { |
2130 |
$renewokay = 1; |
2131 |
} |
2132 |
else { |
2133 |
$error="too_many"; |
2134 |
} |
2135 |
|
2136 |
my ( $resfound, $resrec ) = C4::Reserves::CheckReserves($itemnumber); |
2137 |
if ($resfound) { |
2138 |
$renewokay = 0; |
2139 |
$error="on_reserve" |
2140 |
} |
2141 |
|
1952 |
|
|
|
1953 |
my ( $resfound, $resrec ) = C4::Reserves::CheckReserves($itemnumber); |
1954 |
if ($resfound) { |
1955 |
$renewokay = 0; |
1956 |
$error->{message} = "on_reserve"; |
2142 |
} |
1957 |
} |
2143 |
return ($renewokay,$error); |
1958 |
$error->{renewals} = $itemissue->{'issues.renewals'}; |
|
|
1959 |
$error->{renewalsallowed}= $issuingrule->{renewalsallowed}; |
1960 |
|
1961 |
return ( $renewokay, $error ); |
2144 |
} |
1962 |
} |
2145 |
|
1963 |
|
2146 |
=head2 AddRenewal |
1964 |
=head2 AddRenewal |
Lines 2195-2216
sub AddRenewal {
Link Here
|
2195 |
# based on the value of the RenewalPeriodBase syspref. |
2013 |
# based on the value of the RenewalPeriodBase syspref. |
2196 |
unless ($datedue) { |
2014 |
unless ($datedue) { |
2197 |
|
2015 |
|
2198 |
my $borrower = C4::Members::GetMemberDetails( $borrowernumber, 0 ) or return undef; |
2016 |
my $borrower = C4::Members::GetMemberDetails( $borrowernumber, 0 ) or return undef; |
2199 |
my $loanlength = GetLoanLength( |
2017 |
my $branchcode = _GetCircControlBranch($item, $borrower); |
2200 |
$borrower->{'categorycode'}, |
2018 |
my $loanlength = GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $branchcode ); |
2201 |
(C4::Context->preference('item-level_itypes')) ? $biblio->{'itype'} : $biblio->{'itemtype'} , |
2019 |
|
2202 |
$issuedata->{'branchcode'} ); # that's the circ control branch. |
2020 |
$datedue = |
|
|
2021 |
( C4::Context->preference('RenewalPeriodBase') eq 'date_due' ) |
2022 |
? C4::Dates->new( $issuedata->{date_due}, 'iso' ) |
2023 |
: C4::Dates->new(); |
2024 |
|
2025 |
my $itype = ( C4::Context->preference('item-level_itypes') ) ? $biblio->{'itype'} : $biblio->{'itemtype'}; |
2026 |
my $controlbranch = _GetCircControlBranch( $item, $borrower ); |
2027 |
my $renewalperiod = $loanlength->{renewalperiod} || GetLoanLength( $borrower->{'categorycode'}, $itype, $controlbranch ); |
2028 |
|
2029 |
$datedue = CalcDateDue( $datedue, $renewalperiod, $issuedata->{'branchcode'}, $borrower ); |
2203 |
|
2030 |
|
2204 |
$datedue = (C4::Context->preference('RenewalPeriodBase') eq 'date_due') ? |
|
|
2205 |
C4::Dates->new($issuedata->{date_due}, 'iso') : |
2206 |
C4::Dates->new(); |
2207 |
$datedue = CalcDateDue($datedue,$loanlength,$issuedata->{'branchcode'},$borrower); |
2208 |
} |
2031 |
} |
2209 |
|
2032 |
|
2210 |
# Update the issues record to have the new due date, and a new count |
2033 |
# Update the issues record to have the new due date, and a new count |
2211 |
# of how many times it has been renewed. |
2034 |
# of how many times it has been renewed. |
2212 |
my $renews = $issuedata->{'renewals'} + 1; |
2035 |
my $renews = $issuedata->{'renewals'} + 1; |
2213 |
$sth = $dbh->prepare("UPDATE issues SET date_due = ?, renewals = ?, lastreneweddate = ? |
2036 |
$sth = $dbh->prepare( |
|
|
2037 |
"UPDATE issues SET date_due = ?, renewals = ?, lastreneweddate = ? |
2214 |
WHERE borrowernumber=? |
2038 |
WHERE borrowernumber=? |
2215 |
AND itemnumber=?" |
2039 |
AND itemnumber=?" |
2216 |
); |
2040 |
); |
Lines 2218-2225
sub AddRenewal {
Link Here
|
2218 |
$sth->finish; |
2042 |
$sth->finish; |
2219 |
|
2043 |
|
2220 |
# Update the renewal count on the item, and tell zebra to reindex |
2044 |
# Update the renewal count on the item, and tell zebra to reindex |
2221 |
$renews = $biblio->{'renewals'} + 1; |
2045 |
$renews = $item->{'renewals'} + 1; |
2222 |
ModItem({ renewals => $renews, onloan => $datedue->output('iso') }, $biblio->{'biblionumber'}, $itemnumber); |
2046 |
ModItem( { renewals => $renews, onloan => $datedue->output('iso') }, undef, $itemnumber ); |
2223 |
|
2047 |
|
2224 |
# Charge a new rental fee, if applicable? |
2048 |
# Charge a new rental fee, if applicable? |
2225 |
my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber ); |
2049 |
my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber ); |
Lines 2600-2614
sub CalcDateDue {
Link Here
|
2600 |
my ($startdate,$loanlength,$branch,$borrower) = @_; |
2424 |
my ($startdate,$loanlength,$branch,$borrower) = @_; |
2601 |
my $datedue; |
2425 |
my $datedue; |
2602 |
|
2426 |
|
2603 |
if(C4::Context->preference('useDaysMode') eq 'Days') { # ignoring calendar |
2427 |
my $calendar = C4::Calendar->new( branchcode => $branch ); |
2604 |
my $timedue = time + ($loanlength) * 86400; |
2428 |
$datedue = $calendar->addDate($startdate, $loanlength); |
2605 |
#FIXME - assumes now even though we take a startdate |
|
|
2606 |
my @datearr = localtime($timedue); |
2607 |
$datedue = C4::Dates->new( sprintf("%04d-%02d-%02d", 1900 + $datearr[5], $datearr[4] + 1, $datearr[3]), 'iso'); |
2608 |
} else { |
2609 |
my $calendar = C4::Calendar->new( branchcode => $branch ); |
2610 |
$datedue = $calendar->addDate($startdate, $loanlength); |
2611 |
} |
2612 |
|
2429 |
|
2613 |
# if ReturnBeforeExpiry ON the datedue can't be after borrower expirydate |
2430 |
# if ReturnBeforeExpiry ON the datedue can't be after borrower expirydate |
2614 |
if ( C4::Context->preference('ReturnBeforeExpiry') && $datedue->output('iso') gt $borrower->{dateexpiry} ) { |
2431 |
if ( C4::Context->preference('ReturnBeforeExpiry') && $datedue->output('iso') gt $borrower->{dateexpiry} ) { |
Lines 2818-2835
sub CreateBranchTransferLimit {
Link Here
|
2818 |
|
2635 |
|
2819 |
=head2 DeleteBranchTransferLimits |
2636 |
=head2 DeleteBranchTransferLimits |
2820 |
|
2637 |
|
2821 |
DeleteBranchTransferLimits(); |
2638 |
DeleteBranchTransferLimits($tobranch); |
2822 |
|
2639 |
|
2823 |
=cut |
2640 |
=cut |
2824 |
|
2641 |
|
2825 |
sub DeleteBranchTransferLimits { |
2642 |
sub DeleteBranchTransferLimits { |
2826 |
my $dbh = C4::Context->dbh; |
2643 |
my $branch = shift; |
2827 |
my $sth = $dbh->prepare("TRUNCATE TABLE branch_transfer_limits"); |
2644 |
my $dbh = C4::Context->dbh; |
2828 |
$sth->execute(); |
2645 |
my $sth = $dbh->prepare("DELETE FROM branch_transfer_limits WHERE toBranch = ?"); |
|
|
2646 |
$sth->execute($branch); |
2647 |
} |
2648 |
|
2649 |
sub GetOfflineOperations { |
2650 |
my $dbh = C4::Context->dbh; |
2651 |
my $sth = $dbh->prepare("SELECT * FROM pending_offline_operations WHERE branchcode=? ORDER BY timestamp"); |
2652 |
$sth->execute(C4::Context->userenv->{'branch'}); |
2653 |
my $results = $sth->fetchall_arrayref({}); |
2654 |
$sth->finish; |
2655 |
return $results; |
2656 |
} |
2657 |
|
2658 |
sub GetOfflineOperation { |
2659 |
my $dbh = C4::Context->dbh; |
2660 |
my $sth = $dbh->prepare("SELECT * FROM pending_offline_operations WHERE operationid=?"); |
2661 |
$sth->execute( shift ); |
2662 |
my $result = $sth->fetchrow_hashref; |
2663 |
$sth->finish; |
2664 |
return $result; |
2665 |
} |
2666 |
|
2667 |
sub AddOfflineOperation { |
2668 |
my $dbh = C4::Context->dbh; |
2669 |
warn Data::Dumper::Dumper(@_); |
2670 |
my $sth = $dbh->prepare("INSERT INTO pending_offline_operations VALUES('',?,?,?,?,?,?)"); |
2671 |
$sth->execute( @_ ); |
2672 |
return "Added."; |
2673 |
} |
2674 |
|
2675 |
sub DeleteOfflineOperation { |
2676 |
my $dbh = C4::Context->dbh; |
2677 |
my $sth = $dbh->prepare("DELETE FROM pending_offline_operations WHERE operationid=?"); |
2678 |
$sth->execute( shift ); |
2679 |
return "Deleted."; |
2680 |
} |
2681 |
|
2682 |
sub ProcessOfflineOperation { |
2683 |
my $operation = shift; |
2684 |
|
2685 |
my $report; |
2686 |
if ( $operation->{action} eq 'return' ) { |
2687 |
$report = ProcessOfflineReturn( $operation ); |
2688 |
} elsif ( $operation->{action} eq 'issue' ) { |
2689 |
$report = ProcessOfflineIssue( $operation ); |
2690 |
} |
2691 |
|
2692 |
DeleteOfflineOperation( $operation->{operationid} ) if $operation->{operationid}; |
2693 |
|
2694 |
return $report; |
2695 |
} |
2696 |
|
2697 |
sub ProcessOfflineReturn { |
2698 |
my $operation = shift; |
2699 |
|
2700 |
my $itemnumber = C4::Items::GetItemnumberFromBarcode( $operation->{barcode} ); |
2701 |
|
2702 |
if ( $itemnumber ) { |
2703 |
my $issue = GetOpenIssue( $itemnumber ); |
2704 |
if ( $issue ) { |
2705 |
MarkIssueReturned( |
2706 |
$issue->{borrowernumber}, |
2707 |
$itemnumber, |
2708 |
undef, |
2709 |
$operation->{timestamp}, |
2710 |
); |
2711 |
return "Success."; |
2712 |
} else { |
2713 |
return "Item not issued."; |
2714 |
} |
2715 |
} else { |
2716 |
return "Item not found."; |
2717 |
} |
2718 |
} |
2719 |
|
2720 |
sub ProcessOfflineIssue { |
2721 |
my $operation = shift; |
2722 |
|
2723 |
my $borrower = C4::Members::GetMemberDetails( undef, $operation->{cardnumber} ); # Get borrower from operation cardnumber |
2724 |
|
2725 |
if ( $borrower->{borrowernumber} ) { |
2726 |
my $itemnumber = C4::Items::GetItemnumberFromBarcode( $operation->{barcode} ); |
2727 |
my $issue = GetOpenIssue( $itemnumber ); |
2728 |
|
2729 |
if ( $issue and ( $issue->{borrowernumber} ne $borrower->{borrowernumber} ) ) { # Item already issued to another borrower, mark it returned |
2730 |
MarkIssueReturned( |
2731 |
$issue->{borrowernumber}, |
2732 |
$itemnumber, |
2733 |
undef, |
2734 |
$operation->{timestamp}, |
2735 |
); |
2736 |
} |
2737 |
AddIssue( |
2738 |
$borrower, |
2739 |
$operation->{'barcode'}, |
2740 |
undef, |
2741 |
1, |
2742 |
$operation->{timestamp}, |
2743 |
undef, |
2744 |
); |
2745 |
return "Success."; |
2746 |
} else { |
2747 |
return "Borrower not found."; |
2748 |
} |
2829 |
} |
2749 |
} |
2830 |
|
2750 |
|
2831 |
|
2751 |
|
2832 |
1; |
2752 |
1; |
2833 |
|
2753 |
|
2834 |
__END__ |
2754 |
__END__ |
2835 |
|
2755 |
|