Bugzilla – Attachment 23163 Details for
Bug 10993
Transfer limits should be checked when placing a hold/reservation in OPAC.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 10993 - Transfer limits should be checked when placing a hold/reservation in OPAC.
Bug-10993---Transfer-limits-should-be-checked-when.patch (text/plain), 164.12 KB, created by
Olli-Antti Kivilahti
on 2013-11-26 16:31:44 UTC
(
hide
)
Description:
Bug 10993 - Transfer limits should be checked when placing a hold/reservation in OPAC.
Filename:
MIME Type:
Creator:
Olli-Antti Kivilahti
Created:
2013-11-26 16:31:44 UTC
Size:
164.12 KB
patch
obsolete
>From a7ded43b6f159e36cdc01432d579d9dcd869647e Mon Sep 17 00:00:00 2001 >From: Olli-Antti Kivilahti <olli-antti.kivilahti@jns.fi> >Date: Tue, 15 Oct 2013 13:35:01 +0300 >Subject: [PATCH] Bug 10993 - Transfer limits should be checked when placing a > hold/reservation in OPAC. > >Depends on bug 11005, 11020 > >Prevents a user from placing holds on material whose branch transfer is denied. Displays clear messages that items are >unavailable and re-checks in the business layer in case of UI blocks failing. >Enables choosing another pickup location. > >Manual test plan included. > >Formatted with perltidy and Perl::Critic level 5 >--- > C4/Circulation.pm | 2298 ++++++++++++-------- > .../opac-tmpl/prog/en/modules/opac-reserve.tt | 85 +- > opac/opac-reserve.pl | 95 +- > 3 files changed, 1461 insertions(+), 1017 deletions(-) > >diff --git a/C4/Circulation.pm b/C4/Circulation.pm >index dff0a1d..36afedf 100644 >--- a/C4/Circulation.pm >+++ b/C4/Circulation.pm >@@ -18,8 +18,8 @@ package C4::Circulation; > # with Koha; if not, write to the Free Software Foundation, Inc., > # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > >- > use strict; >+ > #use warnings; FIXME - Bug 2505 > use DateTime; > use C4::Context; >@@ -34,12 +34,12 @@ use C4::Accounts; > use C4::ItemCirculationAlertPreference; > use C4::Message; > use C4::Debug; >-use C4::Branch; # GetBranches >-use C4::Log; # logaction >+use C4::Branch; # GetBranches >+use C4::Log; # logaction > use C4::Koha qw( >- GetAuthorisedValueByCode >- GetAuthValCode >- GetKohaAuthorisedValueLib >+ GetAuthorisedValueByCode >+ GetAuthValCode >+ GetKohaAuthorisedValueLib > ); > use C4::Overdues qw(CalcFine UpdateFine); > use Algorithm::CheckDigits; >@@ -62,54 +62,54 @@ use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); > > BEGIN { > require Exporter; >- $VERSION = 3.07.00.049; # for version checking >- @ISA = qw(Exporter); >+ $VERSION = 3.07.00.049; # for version checking >+ @ISA = qw(Exporter); > > # FIXME subs that should probably be elsewhere > push @EXPORT, qw( >- &barcodedecode >- &LostItem >- &ReturnLostItem >+ &barcodedecode >+ &LostItem >+ &ReturnLostItem > ); > > # subs to deal with issuing a book > push @EXPORT, qw( >- &CanBookBeIssued >- &CanBookBeRenewed >- &AddIssue >- &AddRenewal >- &GetRenewCount >- &GetItemIssue >- &GetItemIssues >- &GetIssuingCharges >- &GetIssuingRule >- &GetBranchBorrowerCircRule >- &GetBranchItemRule >- &GetBiblioIssues >- &GetOpenIssue >- &AnonymiseIssueHistory >- &CheckIfIssuedToPatron >- &IsItemIssued >+ &CanBookBeIssued >+ &CanBookBeRenewed >+ &AddIssue >+ &AddRenewal >+ &GetRenewCount >+ &GetItemIssue >+ &GetItemIssues >+ &GetIssuingCharges >+ &GetIssuingRule >+ &GetBranchBorrowerCircRule >+ &GetBranchItemRule >+ &GetBiblioIssues >+ &GetOpenIssue >+ &AnonymiseIssueHistory >+ &CheckIfIssuedToPatron >+ &IsItemIssued > ); > > # subs to deal with returns > push @EXPORT, qw( >- &AddReturn >- &MarkIssueReturned >+ &AddReturn >+ &MarkIssueReturned > ); > > # subs to deal with transfers > push @EXPORT, qw( >- &transferbook >- &GetTransfers >- &GetTransfersFromTo >- &updateWrongTransfer >- &DeleteTransfer >- &CanItemBeTransferred >- &IsBranchTransferAllowed >- &CreateBranchTransferLimit >- &DeleteBranchTransferLimits >- &TransferSlip >+ &transferbook >+ &GetTransfers >+ &GetTransfersFromTo >+ &updateWrongTransfer >+ &DeleteTransfer >+ &CanItemBeTransferred >+ &IsBranchTransferAllowed >+ &CreateBranchTransferLimit >+ &DeleteBranchTransferLimits >+ &TransferSlip > ); > > # subs to deal with offline circulation >@@ -159,40 +159,53 @@ System Pref options. > # FIXME -- these plugins should be moved out of Circulation.pm > # > sub barcodedecode { >- my ($barcode, $filter) = @_; >+ my ( $barcode, $filter ) = @_; > my $branch = C4::Branch::mybranch(); > $filter = C4::Context->preference('itemBarcodeInputFilter') unless $filter; >- $filter or return $barcode; # ensure filter is defined, else return untouched barcode >- if ($filter eq 'whitespace') { >+ $filter >+ or >+ return $barcode; # ensure filter is defined, else return untouched barcode >+ if ( $filter eq 'whitespace' ) { > $barcode =~ s/\s//g; >- } elsif ($filter eq 'cuecat') { >+ } >+ elsif ( $filter eq 'cuecat' ) { > chomp($barcode); > my @fields = split( /\./, $barcode ); > my @results = map( decode($_), @fields[ 1 .. $#fields ] ); >- ($#results == 2) and return $results[2]; >- } elsif ($filter eq 'T-prefix') { >- if ($barcode =~ /^[Tt](\d)/) { >- (defined($1) and $1 eq '0') and return $barcode; >- $barcode = substr($barcode, 2) + 0; # FIXME: probably should be substr($barcode, 1) >- } >- return sprintf("T%07d", $barcode); >- # FIXME: $barcode could be "T1", causing warning: substr outside of string >- # Why drop the nonzero digit after the T? >- # Why pass non-digits (or empty string) to "T%07d"? >- } elsif ($filter eq 'libsuite8') { >- unless($barcode =~ m/^($branch)-/i){ #if barcode starts with branch code its in Koha style. Skip it. >- if($barcode =~ m/^(\d)/i){ #Some barcodes even start with 0's & numbers and are assumed to have b as the item type in the libsuite8 software >- $barcode =~ s/^[0]*(\d+)$/$branch-b-$1/i; >- }else{ >+ ( $#results == 2 ) and return $results[2]; >+ } >+ elsif ( $filter eq 'T-prefix' ) { >+ if ( $barcode =~ /^[Tt](\d)/ ) { >+ ( defined($1) and $1 eq '0' ) and return $barcode; >+ $barcode = substr( $barcode, 2 ) + >+ 0; # FIXME: probably should be substr($barcode, 1) >+ } >+ return sprintf( "T%07d", $barcode ); >+ >+ # FIXME: $barcode could be "T1", causing warning: substr outside of string >+ # Why drop the nonzero digit after the T? >+ # Why pass non-digits (or empty string) to "T%07d"? >+ } >+ elsif ( $filter eq 'libsuite8' ) { >+ unless ( $barcode =~ m/^($branch)-/i ) >+ { #if barcode starts with branch code its in Koha style. Skip it. >+ if ( $barcode =~ m/^(\d)/i ) >+ { #Some barcodes even start with 0's & numbers and are assumed to have b as the item type in the libsuite8 software >+ $barcode =~ s/^[0]*(\d+)$/$branch-b-$1/i; >+ } >+ else { > $barcode =~ s/^(\D+)[0]*(\d+)$/$branch-$1-$2/i; > } > } >- } elsif ($filter eq 'EAN13') { >+ } >+ elsif ( $filter eq 'EAN13' ) { > my $ean = CheckDigits('ean'); > if ( $ean->is_valid($barcode) ) { >- #$barcode = sprintf('%013d',$barcode); # this doesn't work on 32-bit systems >+ >+ #$barcode = sprintf('%013d',$barcode); # this doesn't work on 32-bit systems > $barcode = '0' x ( 13 - length($barcode) ) . $barcode; >- } else { >+ } >+ else { > warn "# [$barcode] not valid EAN-13/UPC-A\n"; > } > } >@@ -219,6 +232,7 @@ sub decode { > my $l = ( $#s + 1 ) % 4; > if ($l) { > if ( $l == 1 ) { >+ > # warn "Error: Cuecat decode parsing failed!"; > return; > } >@@ -230,8 +244,8 @@ sub decode { > my $n = ( ( $s[0] << 6 | $s[1] ) << 6 | $s[2] ) << 6 | $s[3]; > $r .= > chr( ( $n >> 16 ) ^ 67 ) >- .chr( ( $n >> 8 & 255 ) ^ 67 ) >- .chr( ( $n & 255 ) ^ 67 ); >+ . chr( ( $n >> 8 & 255 ) ^ 67 ) >+ . chr( ( $n & 255 ) ^ 67 ); > @s = @s[ 4 .. $#s ]; > } > $r = substr( $r, 0, length($r) - $l ); >@@ -299,12 +313,12 @@ The item was eligible to be transferred. Barring problems communicating with the > sub transferbook { > my ( $tbr, $barcode, $ignoreRs ) = @_; > my $messages; >- my $dotransfer = 1; >- my $branches = GetBranches(); >- my $item = GetItem(undef,$barcode,undef); >+ my $dotransfer = 1; >+ my $branches = GetBranches(); >+ my $item = GetItem( undef, $barcode, undef ); > my $itemnumber = $item->{itemnumber}; > my $issue = GetItemIssue($itemnumber); >- my $biblio = GetBiblioFromItemNumber($itemnumber); >+ my $biblio = GetBiblioFromItemNumber($itemnumber); > > # bad barcode.. > if ( not $itemnumber ) { >@@ -318,8 +332,9 @@ sub transferbook { > > # if using Branch Transfer Limits > my $errMsg; >- ($dotransfer, $errMsg) = CanItemBeTransferred( $tbr, $fbr, $item, $biblio ); >- if ( ! $dotransfer ) { >+ ( $dotransfer, $errMsg ) = >+ CanItemBeTransferred( $tbr, $fbr, $item, $biblio ); >+ if ( !$dotransfer ) { > $messages->{'NotAllowed'} = $errMsg; > } > >@@ -336,15 +351,14 @@ sub transferbook { > } > > # check if it is still issued to someone, return it... >- if ($issue->{borrowernumber}) { >+ if ( $issue->{borrowernumber} ) { > AddReturn( $barcode, $fbr ); > $messages->{'WasReturned'} = $issue->{borrowernumber}; > } > > # find reserves..... > # That'll save a database query. >- my ( $resfound, $resrec, undef ) = >- CheckReserves( $itemnumber ); >+ my ( $resfound, $resrec, undef ) = CheckReserves($itemnumber); > if ( $resfound and not $ignoreRs ) { > $resrec->{'ResFound'} = $resfound; > >@@ -360,49 +374,52 @@ sub transferbook { > $messages->{'WasTransfered'} = 1; > > } >- ModDateLastSeen( $itemnumber ); >+ ModDateLastSeen($itemnumber); > return ( $dotransfer, $messages, $biblio ); > } > >- > sub TooMany { >- my $borrower = shift; >+ my $borrower = shift; > my $biblionumber = shift; >- my $item = shift; >- my $cat_borrower = $borrower->{'categorycode'}; >- my $dbh = C4::Context->dbh; >+ my $item = shift; >+ my $cat_borrower = $borrower->{'categorycode'}; >+ my $dbh = C4::Context->dbh; > my $branch; >+ > # Get which branchcode we need >- $branch = _GetCircControlBranch($item,$borrower); >- my $type = (C4::Context->preference('item-level_itypes')) >- ? $item->{'itype'} # item-level >- : $item->{'itemtype'}; # biblio-level >- >+ $branch = _GetCircControlBranch( $item, $borrower ); >+ my $type = ( C4::Context->preference('item-level_itypes') ) >+ ? $item->{'itype'} # item-level >+ : $item->{'itemtype'}; # biblio-level >+ > # given branch, patron category, and item type, determine > # applicable issuing rule >- my $issuing_rule = GetIssuingRule($cat_borrower, $type, $branch); >+ my $issuing_rule = GetIssuingRule( $cat_borrower, $type, $branch ); > > # if a rule is found and has a loan limit set, count > # how many loans the patron already has that meet that > # rule >- if (defined($issuing_rule) and defined($issuing_rule->{'maxissueqty'})) { >+ if ( defined($issuing_rule) and defined( $issuing_rule->{'maxissueqty'} ) ) >+ { > my @bind_params; > my $count_query = "SELECT COUNT(*) FROM issues > JOIN items USING (itemnumber) "; > > my $rule_itemtype = $issuing_rule->{itemtype}; >- if ($rule_itemtype eq "*") { >+ if ( $rule_itemtype eq "*" ) { >+ > # matching rule has the default item type, so count only > # those existing loans that don't fall under a more > # specific rule >- if (C4::Context->preference('item-level_itypes')) { >+ if ( C4::Context->preference('item-level_itypes') ) { > $count_query .= " WHERE items.itype NOT IN ( > SELECT itemtype FROM issuingrules > WHERE branchcode = ? > AND (categorycode = ? OR categorycode = ?) > AND itemtype <> '*' > ) "; >- } else { >+ } >+ else { > $count_query .= " JOIN biblioitems USING (biblionumber) > WHERE biblioitems.itemtype NOT IN ( > SELECT itemtype FROM issuingrules >@@ -414,12 +431,14 @@ sub TooMany { > push @bind_params, $issuing_rule->{branchcode}; > push @bind_params, $issuing_rule->{categorycode}; > push @bind_params, $cat_borrower; >- } else { >+ } >+ else { > # rule has specific item type, so count loans of that > # specific item type >- if (C4::Context->preference('item-level_itypes')) { >+ if ( C4::Context->preference('item-level_itypes') ) { > $count_query .= " WHERE items.itype = ? "; >- } else { >+ } >+ else { > $count_query .= " JOIN biblioitems USING (biblionumber) > WHERE biblioitems.itemtype= ? "; > } >@@ -429,13 +448,16 @@ sub TooMany { > $count_query .= " AND borrowernumber = ? "; > push @bind_params, $borrower->{'borrowernumber'}; > my $rule_branch = $issuing_rule->{branchcode}; >- if ($rule_branch ne "*") { >- if (C4::Context->preference('CircControl') eq 'PickupLibrary') { >+ if ( $rule_branch ne "*" ) { >+ if ( C4::Context->preference('CircControl') eq 'PickupLibrary' ) { > $count_query .= " AND issues.branchcode = ? "; > push @bind_params, $branch; >- } elsif (C4::Context->preference('CircControl') eq 'PatronLibrary') { >+ } >+ elsif ( C4::Context->preference('CircControl') eq 'PatronLibrary' ) >+ { > ; # if branch is the patron's home branch, then count all loans by patron >- } else { >+ } >+ else { > $count_query .= " AND items.homebranch = ? "; > push @bind_params, $branch; > } >@@ -446,26 +468,29 @@ sub TooMany { > my ($current_loan_count) = $count_sth->fetchrow_array; > > my $max_loans_allowed = $issuing_rule->{'maxissueqty'}; >- if ($current_loan_count >= $max_loans_allowed) { >- return ($current_loan_count, $max_loans_allowed); >+ if ( $current_loan_count >= $max_loans_allowed ) { >+ return ( $current_loan_count, $max_loans_allowed ); > } > } > > # Now count total loans against the limit for the branch >- my $branch_borrower_circ_rule = GetBranchBorrowerCircRule($branch, $cat_borrower); >- if (defined($branch_borrower_circ_rule->{maxissueqty})) { >- my @bind_params = (); >+ my $branch_borrower_circ_rule = >+ GetBranchBorrowerCircRule( $branch, $cat_borrower ); >+ if ( defined( $branch_borrower_circ_rule->{maxissueqty} ) ) { >+ my @bind_params = (); > my $branch_count_query = "SELECT COUNT(*) FROM issues > JOIN items USING (itemnumber) > WHERE borrowernumber = ? "; > push @bind_params, $borrower->{borrowernumber}; > >- if (C4::Context->preference('CircControl') eq 'PickupLibrary') { >+ if ( C4::Context->preference('CircControl') eq 'PickupLibrary' ) { > $branch_count_query .= " AND issues.branchcode = ? "; > push @bind_params, $branch; >- } elsif (C4::Context->preference('CircControl') eq 'PatronLibrary') { >+ } >+ elsif ( C4::Context->preference('CircControl') eq 'PatronLibrary' ) { > ; # if branch is the patron's home branch, then count all loans by patron >- } else { >+ } >+ else { > $branch_count_query .= " AND items.homebranch = ? "; > push @bind_params, $branch; > } >@@ -474,8 +499,8 @@ sub TooMany { > my ($current_loan_count) = $branch_count_sth->fetchrow_array; > > my $max_loans_allowed = $branch_borrower_circ_rule->{maxissueqty}; >- if ($current_loan_count >= $max_loans_allowed) { >- return ($current_loan_count, $max_loans_allowed); >+ if ( $current_loan_count >= $max_loans_allowed ) { >+ return ( $current_loan_count, $max_loans_allowed ); > } > } > >@@ -562,10 +587,10 @@ sub itemissues { > $data->{'borrower'} = $data2->{'borrowernumber'}; > } > else { >- $data->{'date_due'} = ($data->{'withdrawn'} eq '1') ? 'Cancelled' : 'Available'; >+ $data->{'date_due'} = >+ ( $data->{'withdrawn'} eq '1' ) ? 'Cancelled' : 'Available'; > } > >- > # Find the last 3 people who borrowed this item. > $sth2 = $dbh->prepare( > "SELECT * FROM old_issues >@@ -688,14 +713,16 @@ if the borrower borrows to much things > sub CanBookBeIssued { > my ( $borrower, $barcode, $duedate, $inprocess, $ignore_reserves ) = @_; > my %needsconfirmation; # filled with problems that needs confirmations >- my %issuingimpossible; # filled with problems that causes the issue to be IMPOSSIBLE >- my %alerts; # filled with messages that shouldn't stop issuing, but the librarian should be aware of. >- >- my $item = GetItem(GetItemnumberFromBarcode( $barcode )); >- my $issue = GetItemIssue($item->{itemnumber}); >- my $biblioitem = GetBiblioItemData($item->{biblioitemnumber}); >- $item->{'itemtype'}=$item->{'itype'}; >- my $dbh = C4::Context->dbh; >+ my %issuingimpossible >+ ; # filled with problems that causes the issue to be IMPOSSIBLE >+ my %alerts >+ ; # filled with messages that shouldn't stop issuing, but the librarian should be aware of. >+ >+ my $item = GetItem( GetItemnumberFromBarcode($barcode) ); >+ my $issue = GetItemIssue( $item->{itemnumber} ); >+ my $biblioitem = GetBiblioItemData( $item->{biblioitemnumber} ); >+ $item->{'itemtype'} = $item->{'itype'}; >+ my $dbh = C4::Context->dbh; > > # MANDATORY CHECKS - unless item exists, nothing else matters > unless ( $item->{barcode} ) { >@@ -706,15 +733,18 @@ sub CanBookBeIssued { > # > # DUE DATE is OK ? -- should already have checked. > # >- if ($duedate && ref $duedate ne 'DateTime') { >+ if ( $duedate && ref $duedate ne 'DateTime' ) { > $duedate = dt_from_string($duedate); > } > my $now = DateTime->now( time_zone => C4::Context->tz() ); >- unless ( $duedate ) { >+ unless ($duedate) { > my $issuedate = $now->clone(); > >- my $branch = _GetCircControlBranch($item,$borrower); >- my $itype = ( C4::Context->preference('item-level_itypes') ) ? $item->{'itype'} : $biblioitem->{'itemtype'}; >+ my $branch = _GetCircControlBranch( $item, $borrower ); >+ my $itype = >+ ( C4::Context->preference('item-level_itypes') ) >+ ? $item->{'itype'} >+ : $biblioitem->{'itemtype'}; > $duedate = CalcDateDue( $issuedate, $itype, $branch, $borrower ); > > # Offline circ calls AddIssue directly, doesn't run through here >@@ -722,22 +752,31 @@ sub CanBookBeIssued { > } > if ($duedate) { > my $today = $now->clone(); >- $today->truncate( to => 'minute'); >- if (DateTime->compare($duedate,$today) == -1 ) { # duedate cannot be before now >+ $today->truncate( to => 'minute' ); >+ if ( DateTime->compare( $duedate, $today ) == -1 ) >+ { # duedate cannot be before now > $needsconfirmation{INVALID_DATE} = output_pref($duedate); > } >- } else { >- $issuingimpossible{INVALID_DATE} = output_pref($duedate); >+ } >+ else { >+ $issuingimpossible{INVALID_DATE} = output_pref($duedate); > } > > # > # BORROWER STATUS > # >- if ( $borrower->{'category_type'} eq 'X' && ( $item->{barcode} )) { >- # stats only borrower -- add entry to statistics table, and return issuingimpossible{STATS} = 1 . >- &UpdateStats(C4::Context->userenv->{'branch'},'localuse','','',$item->{'itemnumber'},$item->{'itemtype'},$borrower->{'borrowernumber'}, undef, $item->{'ccode'}); >+ if ( $borrower->{'category_type'} eq 'X' && ( $item->{barcode} ) ) { >+ >+# stats only borrower -- add entry to statistics table, and return issuingimpossible{STATS} = 1 . >+ &UpdateStats( >+ C4::Context->userenv->{'branch'}, 'localuse', >+ '', '', >+ $item->{'itemnumber'}, $item->{'itemtype'}, >+ $borrower->{'borrowernumber'}, undef, >+ $item->{'ccode'} >+ ); > ModDateLastSeen( $item->{'itemnumber'} ); >- return( { STATS => 1 }, {}); >+ return ( { STATS => 1 }, {} ); > } > if ( $borrower->{flags}->{GNA} ) { > $issuingimpossible{GNA} = 1; >@@ -748,23 +787,27 @@ sub CanBookBeIssued { > if ( $borrower->{flags}->{'DBARRED'} ) { > $issuingimpossible{DEBARRED} = 1; > } >- if ( !defined $borrower->{dateexpiry} || $borrower->{'dateexpiry'} eq '0000-00-00') { >+ if ( !defined $borrower->{dateexpiry} >+ || $borrower->{'dateexpiry'} eq '0000-00-00' ) >+ { > $issuingimpossible{EXPIRED} = 1; >- } else { >- my ($y, $m, $d) = split /-/,$borrower->{'dateexpiry'}; >- if ($y && $m && $d) { # are we really writing oinvalid dates to borrs >+ } >+ else { >+ my ( $y, $m, $d ) = split /-/, $borrower->{'dateexpiry'}; >+ if ( $y && $m && $d ) { # are we really writing oinvalid dates to borrs > my $expiry_dt = DateTime->new( >- year => $y, >- month => $m, >- day => $d, >+ year => $y, >+ month => $m, >+ day => $d, > time_zone => C4::Context->tz, > ); >- $expiry_dt->truncate( to => 'day'); >- my $today = $now->clone()->truncate(to => 'day'); >- if (DateTime->compare($today, $expiry_dt) == 1) { >+ $expiry_dt->truncate( to => 'day' ); >+ my $today = $now->clone()->truncate( to => 'day' ); >+ if ( DateTime->compare( $today, $expiry_dt ) == 1 ) { > $issuingimpossible{EXPIRED} = 1; > } >- } else { >+ } >+ else { > carp("Invalid expity date in borr"); > $issuingimpossible{EXPIRED} = 1; > } >@@ -774,64 +817,86 @@ sub CanBookBeIssued { > # > > # DEBTS >- my ($balance, $non_issue_charges, $other_charges) = >+ my ( $balance, $non_issue_charges, $other_charges ) = > C4::Members::GetMemberAccountBalance( $borrower->{'borrowernumber'} ); >- my $amountlimit = C4::Context->preference("noissuescharge"); >- my $allowfineoverride = C4::Context->preference("AllowFineOverride"); >+ my $amountlimit = C4::Context->preference("noissuescharge"); >+ my $allowfineoverride = C4::Context->preference("AllowFineOverride"); > my $allfinesneedoverride = C4::Context->preference("AllFinesNeedOverride"); > if ( C4::Context->preference("IssuingInProcess") ) { >- if ( $non_issue_charges > $amountlimit && !$inprocess && !$allowfineoverride) { >+ if ( $non_issue_charges > $amountlimit >+ && !$inprocess >+ && !$allowfineoverride ) >+ { > $issuingimpossible{DEBT} = sprintf( "%.2f", $non_issue_charges ); >- } elsif ( $non_issue_charges > $amountlimit && !$inprocess && $allowfineoverride) { >+ } >+ elsif ($non_issue_charges > $amountlimit >+ && !$inprocess >+ && $allowfineoverride ) >+ { > $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges ); >- } elsif ( $allfinesneedoverride && $non_issue_charges > 0 && $non_issue_charges <= $amountlimit && !$inprocess ) { >+ } >+ elsif ($allfinesneedoverride >+ && $non_issue_charges > 0 >+ && $non_issue_charges <= $amountlimit >+ && !$inprocess ) >+ { > $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges ); > } > } > else { > if ( $non_issue_charges > $amountlimit && $allowfineoverride ) { > $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges ); >- } elsif ( $non_issue_charges > $amountlimit && !$allowfineoverride) { >+ } >+ elsif ( $non_issue_charges > $amountlimit && !$allowfineoverride ) { > $issuingimpossible{DEBT} = sprintf( "%.2f", $non_issue_charges ); >- } elsif ( $non_issue_charges > 0 && $allfinesneedoverride ) { >+ } >+ elsif ( $non_issue_charges > 0 && $allfinesneedoverride ) { > $needsconfirmation{DEBT} = sprintf( "%.2f", $non_issue_charges ); > } > } >- if ($balance > 0 && $other_charges > 0) { >+ if ( $balance > 0 && $other_charges > 0 ) { > $alerts{OTHER_CHARGES} = sprintf( "%.2f", $other_charges ); > } > >- my ($blocktype, $count) = C4::Members::IsMemberBlocked($borrower->{'borrowernumber'}); >- if ($blocktype == -1) { >+ my ( $blocktype, $count ) = >+ C4::Members::IsMemberBlocked( $borrower->{'borrowernumber'} ); >+ if ( $blocktype == -1 ) { > ## patron has outstanding overdue loans >- if ( C4::Context->preference("OverduesBlockCirc") eq 'block'){ >+ if ( C4::Context->preference("OverduesBlockCirc") eq 'block' ) { > $issuingimpossible{USERBLOCKEDOVERDUE} = $count; > } >- elsif ( C4::Context->preference("OverduesBlockCirc") eq 'confirmation'){ >+ elsif ( C4::Context->preference("OverduesBlockCirc") eq 'confirmation' ) >+ { > $needsconfirmation{USERBLOCKEDOVERDUE} = $count; > } >- } elsif($blocktype == 1) { >+ } >+ elsif ( $blocktype == 1 ) { >+ > # patron has accrued fine days > $issuingimpossible{USERBLOCKEDREMAINING} = $count; > } > >-# >+ # > # JB34 CHECKS IF BORROWERS DONT HAVE ISSUE TOO MANY BOOKS > # >- my ($current_loan_count, $max_loans_allowed) = TooMany( $borrower, $item->{biblionumber}, $item ); >- # if TooMany max_loans_allowed returns 0 the user doesn't have permission to check out this book >- if (defined $max_loans_allowed && $max_loans_allowed == 0) { >+ my ( $current_loan_count, $max_loans_allowed ) = >+ TooMany( $borrower, $item->{biblionumber}, $item ); >+ >+# if TooMany max_loans_allowed returns 0 the user doesn't have permission to check out this book >+ if ( defined $max_loans_allowed && $max_loans_allowed == 0 ) { > $needsconfirmation{PATRON_CANT} = 1; >- } else { >- if($max_loans_allowed){ >+ } >+ else { >+ if ($max_loans_allowed) { > if ( C4::Context->preference("AllowTooManyOverride") ) { >- $needsconfirmation{TOO_MANY} = 1; >+ $needsconfirmation{TOO_MANY} = 1; > $needsconfirmation{current_loan_count} = $current_loan_count; >- $needsconfirmation{max_loans_allowed} = $max_loans_allowed; >- } else { >- $issuingimpossible{TOO_MANY} = 1; >+ $needsconfirmation{max_loans_allowed} = $max_loans_allowed; >+ } >+ else { >+ $issuingimpossible{TOO_MANY} = 1; > $issuingimpossible{current_loan_count} = $current_loan_count; >- $issuingimpossible{max_loans_allowed} = $max_loans_allowed; >+ $issuingimpossible{max_loans_allowed} = $max_loans_allowed; > } > } > } >@@ -839,45 +904,50 @@ sub CanBookBeIssued { > # > # ITEM CHECKING > # >- if ( $item->{'notforloan'} ) >- { >- if(!C4::Context->preference("AllowNotForLoanOverride")){ >- $issuingimpossible{NOT_FOR_LOAN} = 1; >+ if ( $item->{'notforloan'} ) { >+ if ( !C4::Context->preference("AllowNotForLoanOverride") ) { >+ $issuingimpossible{NOT_FOR_LOAN} = 1; > $issuingimpossible{item_notforloan} = $item->{'notforloan'}; >- }else{ >+ } >+ else { > $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1; >- $needsconfirmation{item_notforloan} = $item->{'notforloan'}; >+ $needsconfirmation{item_notforloan} = $item->{'notforloan'}; > } > } > else { > # we have to check itemtypes.notforloan also >- if (C4::Context->preference('item-level_itypes')){ >+ if ( C4::Context->preference('item-level_itypes') ) { >+ > # this should probably be a subroutine >- my $sth = $dbh->prepare("SELECT notforloan FROM itemtypes WHERE itemtype = ?"); >- $sth->execute($item->{'itemtype'}); >- my $notforloan=$sth->fetchrow_hashref(); >- if ($notforloan->{'notforloan'}) { >- if (!C4::Context->preference("AllowNotForLoanOverride")) { >- $issuingimpossible{NOT_FOR_LOAN} = 1; >+ my $sth = $dbh->prepare( >+ "SELECT notforloan FROM itemtypes WHERE itemtype = ?"); >+ $sth->execute( $item->{'itemtype'} ); >+ my $notforloan = $sth->fetchrow_hashref(); >+ if ( $notforloan->{'notforloan'} ) { >+ if ( !C4::Context->preference("AllowNotForLoanOverride") ) { >+ $issuingimpossible{NOT_FOR_LOAN} = 1; > $issuingimpossible{itemtype_notforloan} = $item->{'itype'}; >- } else { >+ } >+ else { > $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1; >- $needsconfirmation{itemtype_notforloan} = $item->{'itype'}; >+ $needsconfirmation{itemtype_notforloan} = $item->{'itype'}; > } > } > } >- elsif ($biblioitem->{'notforloan'} == 1){ >- if (!C4::Context->preference("AllowNotForLoanOverride")) { >+ elsif ( $biblioitem->{'notforloan'} == 1 ) { >+ if ( !C4::Context->preference("AllowNotForLoanOverride") ) { > $issuingimpossible{NOT_FOR_LOAN} = 1; >- $issuingimpossible{itemtype_notforloan} = $biblioitem->{'itemtype'}; >- } else { >+ $issuingimpossible{itemtype_notforloan} = >+ $biblioitem->{'itemtype'}; >+ } >+ else { > $needsconfirmation{NOT_FOR_LOAN_FORCING} = 1; >- $needsconfirmation{itemtype_notforloan} = $biblioitem->{'itemtype'}; >+ $needsconfirmation{itemtype_notforloan} = >+ $biblioitem->{'itemtype'}; > } > } > } >- if ( $item->{'withdrawn'} && $item->{'withdrawn'} > 0 ) >- { >+ if ( $item->{'withdrawn'} && $item->{'withdrawn'} > 0 ) { > $issuingimpossible{WTHDRAWN} = 1; > } > if ( $item->{'restricted'} >@@ -885,19 +955,27 @@ sub CanBookBeIssued { > { > $issuingimpossible{RESTRICTED} = 1; > } >- if ( $item->{'itemlost'} && C4::Context->preference("IssueLostItem") ne 'nothing' ) { >+ if ( $item->{'itemlost'} >+ && C4::Context->preference("IssueLostItem") ne 'nothing' ) >+ { > my $code = GetAuthorisedValueByCode( 'LOST', $item->{'itemlost'} ); >- $needsconfirmation{ITEM_LOST} = $code if ( C4::Context->preference("IssueLostItem") eq 'confirm' ); >- $alerts{ITEM_LOST} = $code if ( C4::Context->preference("IssueLostItem") eq 'alert' ); >+ $needsconfirmation{ITEM_LOST} = $code >+ if ( C4::Context->preference("IssueLostItem") eq 'confirm' ); >+ $alerts{ITEM_LOST} = $code >+ if ( C4::Context->preference("IssueLostItem") eq 'alert' ); > } > if ( C4::Context->preference("IndependentBranches") ) { > my $userenv = C4::Context->userenv; > if ( ($userenv) && ( $userenv->{flags} % 2 != 1 ) ) { >- if ( $item->{C4::Context->preference("HomeOrHoldingBranch")} ne $userenv->{branch} ){ >+ if ( $item->{ C4::Context->preference("HomeOrHoldingBranch") } ne >+ $userenv->{branch} ) >+ { > $issuingimpossible{ITEMNOTSAMEBRANCH} = 1; >- $issuingimpossible{'itemhomebranch'} = $item->{C4::Context->preference("HomeOrHoldingBranch")}; >+ $issuingimpossible{'itemhomebranch'} = >+ $item->{ C4::Context->preference("HomeOrHoldingBranch") }; > } >- $needsconfirmation{BORRNOTSAMEBRANCH} = GetBranchName( $borrower->{'branchcode'} ) >+ $needsconfirmation{BORRNOTSAMEBRANCH} = >+ GetBranchName( $borrower->{'branchcode'} ) > if ( $borrower->{'branchcode'} ne $userenv->{branch} ); > } > } >@@ -905,15 +983,15 @@ sub CanBookBeIssued { > # > # CHECK IF BOOK ALREADY ISSUED TO THIS BORROWER > # >- if ( $issue->{borrowernumber} && $issue->{borrowernumber} eq $borrower->{'borrowernumber'} ) >+ if ( $issue->{borrowernumber} >+ && $issue->{borrowernumber} eq $borrower->{'borrowernumber'} ) > { > > # Already issued to current borrower. Ask whether the loan should > # be renewed. >- my ($CanBookBeRenewed,$renewerror) = CanBookBeRenewed( >- $borrower->{'borrowernumber'}, >- $item->{'itemnumber'} >- ); >+ my ( $CanBookBeRenewed, $renewerror ) = >+ CanBookBeRenewed( $borrower->{'borrowernumber'}, >+ $item->{'itemnumber'} ); > if ( $CanBookBeRenewed == 0 ) { # no more renewals allowed > $issuingimpossible{NO_MORE_RENEWALS} = 1; > } >@@ -921,48 +999,64 @@ sub CanBookBeIssued { > $needsconfirmation{RENEW_ISSUE} = 1; > } > } >- elsif ($issue->{borrowernumber}) { >+ elsif ( $issue->{borrowernumber} ) { > > # issued to someone else >- my $currborinfo = C4::Members::GetMember( borrowernumber => $issue->{borrowernumber} ); >+ my $currborinfo = >+ C4::Members::GetMember( borrowernumber => $issue->{borrowernumber} ); > > # warn "=>.$currborinfo->{'firstname'} $currborinfo->{'surname'} ($currborinfo->{'cardnumber'})"; > $needsconfirmation{ISSUED_TO_ANOTHER} = 1; >- $needsconfirmation{issued_firstname} = $currborinfo->{'firstname'}; >- $needsconfirmation{issued_surname} = $currborinfo->{'surname'}; >+ $needsconfirmation{issued_firstname} = $currborinfo->{'firstname'}; >+ $needsconfirmation{issued_surname} = $currborinfo->{'surname'}; > $needsconfirmation{issued_cardnumber} = $currborinfo->{'cardnumber'}; >- $needsconfirmation{issued_borrowernumber} = $currborinfo->{'borrowernumber'}; >+ $needsconfirmation{issued_borrowernumber} = >+ $currborinfo->{'borrowernumber'}; > } > >- unless ( $ignore_reserves ) { >+ unless ($ignore_reserves) { >+ > # See if the item is on reserve. >- my ( $restype, $res ) = C4::Reserves::CheckReserves( $item->{'itemnumber'} ); >+ my ( $restype, $res ) = >+ C4::Reserves::CheckReserves( $item->{'itemnumber'} ); > if ($restype) { > my $resbor = $res->{'borrowernumber'}; > if ( $resbor ne $borrower->{'borrowernumber'} ) { >- my ( $resborrower ) = C4::Members::GetMember( borrowernumber => $resbor ); >+ my ($resborrower) = >+ C4::Members::GetMember( borrowernumber => $resbor ); > my $branchname = GetBranchName( $res->{'branchcode'} ); >- if ( $restype eq "Waiting" ) >- { >+ if ( $restype eq "Waiting" ) { >+ > # The item is on reserve and waiting, but has been > # reserved by some other patron. > $needsconfirmation{RESERVE_WAITING} = 1; >- $needsconfirmation{'resfirstname'} = $resborrower->{'firstname'}; >- $needsconfirmation{'ressurname'} = $resborrower->{'surname'}; >- $needsconfirmation{'rescardnumber'} = $resborrower->{'cardnumber'}; >- $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'}; >+ $needsconfirmation{'resfirstname'} = >+ $resborrower->{'firstname'}; >+ $needsconfirmation{'ressurname'} = >+ $resborrower->{'surname'}; >+ $needsconfirmation{'rescardnumber'} = >+ $resborrower->{'cardnumber'}; >+ $needsconfirmation{'resborrowernumber'} = >+ $resborrower->{'borrowernumber'}; > $needsconfirmation{'resbranchname'} = $branchname; >- $needsconfirmation{'reswaitingdate'} = format_date($res->{'waitingdate'}); >+ $needsconfirmation{'reswaitingdate'} = >+ format_date( $res->{'waitingdate'} ); > } > elsif ( $restype eq "Reserved" ) { >+ > # The item is on reserve for someone else. > $needsconfirmation{RESERVED} = 1; >- $needsconfirmation{'resfirstname'} = $resborrower->{'firstname'}; >- $needsconfirmation{'ressurname'} = $resborrower->{'surname'}; >- $needsconfirmation{'rescardnumber'} = $resborrower->{'cardnumber'}; >- $needsconfirmation{'resborrowernumber'} = $resborrower->{'borrowernumber'}; >+ $needsconfirmation{'resfirstname'} = >+ $resborrower->{'firstname'}; >+ $needsconfirmation{'ressurname'} = >+ $resborrower->{'surname'}; >+ $needsconfirmation{'rescardnumber'} = >+ $resborrower->{'cardnumber'}; >+ $needsconfirmation{'resborrowernumber'} = >+ $resborrower->{'borrowernumber'}; > $needsconfirmation{'resbranchname'} = $branchname; >- $needsconfirmation{'resreservedate'} = format_date($res->{'reservedate'}); >+ $needsconfirmation{'resreservedate'} = >+ format_date( $res->{'reservedate'} ); > } > } > } >@@ -971,49 +1065,51 @@ sub CanBookBeIssued { > # CHECK AGE RESTRICTION > # > >- # get $marker from preferences. Could be something like "FSK|PEGI|Alter|Age:" >- my $markers = C4::Context->preference('AgeRestrictionMarker' ); >+ # get $marker from preferences. Could be something like "FSK|PEGI|Alter|Age:" >+ my $markers = C4::Context->preference('AgeRestrictionMarker'); > my $bibvalues = $biblioitem->{'agerestriction'}; >- if (($markers)&&($bibvalues)) >- { >+ if ( ($markers) && ($bibvalues) ) { >+ > # Split $bibvalues to something like FSK 16 or PEGI 6 > my @values = split ' ', $bibvalues; > > # Search first occurence of one of the markers > my @markers = split /\|/, $markers; >- my $index = 0; >- my $take = -1; >+ my $index = 0; >+ my $take = -1; > for my $value (@values) { >- $index ++; >+ $index++; > for my $marker (@markers) { >- $marker =~ s/^\s+//; #remove leading spaces >- $marker =~ s/\s+$//; #remove trailing spaces >- if (uc($marker) eq uc($value)) { >+ $marker =~ s/^\s+//; #remove leading spaces >+ $marker =~ s/\s+$//; #remove trailing spaces >+ if ( uc($marker) eq uc($value) ) { > $take = $index; > last; > } > } >- if ($take > -1) { >+ if ( $take > -1 ) { > last; > } > } >+ > # Index points to the next value > my $restrictionyear = 0; >- if (($take <= $#values) && ($take >= 0)){ >+ if ( ( $take <= $#values ) && ( $take >= 0 ) ) { > $restrictionyear += $values[$take]; > } > >- if ($restrictionyear > 0) { >- if ( $borrower->{'dateofbirth'} ) { >- my @alloweddate = split /-/,$borrower->{'dateofbirth'} ; >+ if ( $restrictionyear > 0 ) { >+ if ( $borrower->{'dateofbirth'} ) { >+ my @alloweddate = split /-/, $borrower->{'dateofbirth'}; > $alloweddate[0] += $restrictionyear; >+ > #Prevent runime eror on leap year (invalid date) >- if (($alloweddate[1] == 2) && ($alloweddate[2] == 29)) { >+ if ( ( $alloweddate[1] == 2 ) && ( $alloweddate[2] == 29 ) ) { > $alloweddate[2] = 28; > } > >- if ( Date_to_Days(Today) < Date_to_Days(@alloweddate) -1 ) { >- if (C4::Context->preference('AgeRestrictionOverride' )) { >+ if ( Date_to_Days(Today) < Date_to_Days(@alloweddate) - 1 ) { >+ if ( C4::Context->preference('AgeRestrictionOverride') ) { > $needsconfirmation{AGE_RESTRICTION} = "$bibvalues"; > } > else { >@@ -1069,26 +1165,37 @@ Returns: > =cut > > sub CanBookBeReturned { >- my ($item, $branch) = @_; >- my $allowreturntobranch = C4::Context->preference("AllowReturnToBranch") || 'anywhere'; >- >- # assume return is allowed to start >- my $allowed = 1; >- my $message; >- >- # identify all cases where return is forbidden >- if ($allowreturntobranch eq 'homebranch' && $branch ne $item->{'homebranch'}) { >- $allowed = 0; >- $message = $item->{'homebranch'}; >- } elsif ($allowreturntobranch eq 'holdingbranch' && $branch ne $item->{'holdingbranch'}) { >- $allowed = 0; >- $message = $item->{'holdingbranch'}; >- } elsif ($allowreturntobranch eq 'homeorholdingbranch' && $branch ne $item->{'homebranch'} && $branch ne $item->{'holdingbranch'}) { >- $allowed = 0; >- $message = $item->{'homebranch'}; # FIXME: choice of homebranch is arbitrary >- } >- >- return ($allowed, $message); >+ my ( $item, $branch ) = @_; >+ my $allowreturntobranch = >+ C4::Context->preference("AllowReturnToBranch") || 'anywhere'; >+ >+ # assume return is allowed to start >+ my $allowed = 1; >+ my $message; >+ >+ # identify all cases where return is forbidden >+ if ( $allowreturntobranch eq 'homebranch' >+ && $branch ne $item->{'homebranch'} ) >+ { >+ $allowed = 0; >+ $message = $item->{'homebranch'}; >+ } >+ elsif ($allowreturntobranch eq 'holdingbranch' >+ && $branch ne $item->{'holdingbranch'} ) >+ { >+ $allowed = 0; >+ $message = $item->{'holdingbranch'}; >+ } >+ elsif ($allowreturntobranch eq 'homeorholdingbranch' >+ && $branch ne $item->{'homebranch'} >+ && $branch ne $item->{'holdingbranch'} ) >+ { >+ $allowed = 0; >+ $message = >+ $item->{'homebranch'}; # FIXME: choice of homebranch is arbitrary >+ } >+ >+ return ( $allowed, $message ); > } > > =head2 CheckHighHolds >@@ -1174,158 +1281,181 @@ AddIssue does the following things : > =cut > > sub AddIssue { >- my ( $borrower, $barcode, $datedue, $cancelreserve, $issuedate, $sipmode) = @_; >- my $dbh = C4::Context->dbh; >- my $barcodecheck=CheckValidBarcode($barcode); >- if ($datedue && ref $datedue ne 'DateTime') { >+ my ( $borrower, $barcode, $datedue, $cancelreserve, $issuedate, $sipmode ) >+ = @_; >+ my $dbh = C4::Context->dbh; >+ my $barcodecheck = CheckValidBarcode($barcode); >+ if ( $datedue && ref $datedue ne 'DateTime' ) { > $datedue = dt_from_string($datedue); > } >+ > # $issuedate defaults to today. >- if ( ! defined $issuedate ) { >- $issuedate = DateTime->now(time_zone => C4::Context->tz()); >+ if ( !defined $issuedate ) { >+ $issuedate = DateTime->now( time_zone => C4::Context->tz() ); > } > else { >- if ( ref $issuedate ne 'DateTime') { >+ if ( ref $issuedate ne 'DateTime' ) { > $issuedate = dt_from_string($issuedate); > > } > } >- if ($borrower and $barcode and $barcodecheck ne '0'){#??? wtf >- # find which item we issue >- my $item = GetItem('', $barcode) or return; # if we don't get an Item, abort. >- my $branch = _GetCircControlBranch($item,$borrower); >+ if ( $borrower and $barcode and $barcodecheck ne '0' ) { #??? wtf >+ # find which item we issue >+ my $item = GetItem( '', $barcode ) >+ or return; # if we don't get an Item, abort. >+ my $branch = _GetCircControlBranch( $item, $borrower ); > > # get actual issuing if there is one >- my $actualissue = GetItemIssue( $item->{itemnumber}); >+ my $actualissue = GetItemIssue( $item->{itemnumber} ); > > # get biblioinformation for this item >- my $biblio = GetBiblioFromItemNumber($item->{itemnumber}); >+ my $biblio = GetBiblioFromItemNumber( $item->{itemnumber} ); > > # > # check if we just renew the issue. > # >- if ($actualissue->{borrowernumber} eq $borrower->{'borrowernumber'}) { >+ if ( $actualissue->{borrowernumber} eq $borrower->{'borrowernumber'} ) { > $datedue = AddRenewal( >- $borrower->{'borrowernumber'}, >- $item->{'itemnumber'}, >- $branch, >- $datedue, >- $issuedate, # here interpreted as the renewal date >+ $borrower->{'borrowernumber'}, >+ $item->{'itemnumber'}, >+ $branch, >+ $datedue, >+ $issuedate, # here interpreted as the renewal date > ); > } > else { >- # it's NOT a renewal >- if ( $actualissue->{borrowernumber}) { >- # This book is currently on loan, but not to the person >- # who wants to borrow it now. mark it returned before issuing to the new borrower >- AddReturn( >- $item->{'barcode'}, >- C4::Context->userenv->{'branch'} >- ); >+ # it's NOT a renewal >+ if ( $actualissue->{borrowernumber} ) { >+ >+# This book is currently on loan, but not to the person >+# who wants to borrow it now. mark it returned before issuing to the new borrower >+ AddReturn( $item->{'barcode'}, >+ C4::Context->userenv->{'branch'} ); > } > >- MoveReserve( $item->{'itemnumber'}, $borrower->{'borrowernumber'}, $cancelreserve ); >- # Starting process for transfer job (checking transfert and validate it if we have one) >- my ($datesent) = GetTransfers($item->{'itemnumber'}); >+ MoveReserve( $item->{'itemnumber'}, $borrower->{'borrowernumber'}, >+ $cancelreserve ); >+ >+# Starting process for transfer job (checking transfert and validate it if we have one) >+ my ($datesent) = GetTransfers( $item->{'itemnumber'} ); > if ($datesent) { >- # updating line of branchtranfert to finish it, and changing the to branch value, implement a comment for visibility of this case (maybe for stats ....) >- my $sth = >- $dbh->prepare( >+ >+# updating line of branchtranfert to finish it, and changing the to branch value, implement a comment for visibility of this case (maybe for stats ....) >+ my $sth = $dbh->prepare( > "UPDATE branchtransfers > SET datearrived = now(), > tobranch = ?, > comments = 'Forced branchtransfer' > WHERE itemnumber= ? AND datearrived IS NULL" >- ); >- $sth->execute(C4::Context->userenv->{'branch'},$item->{'itemnumber'}); >+ ); >+ $sth->execute( C4::Context->userenv->{'branch'}, >+ $item->{'itemnumber'} ); > } > >- # Record in the database the fact that the book was issued. >- my $sth = >- $dbh->prepare( >+ # Record in the database the fact that the book was issued. >+ my $sth = $dbh->prepare( > "INSERT INTO issues > (borrowernumber, itemnumber,issuedate, date_due, branchcode) > VALUES (?,?,?,?,?)" >- ); >- unless ($datedue) { >- my $itype = ( C4::Context->preference('item-level_itypes') ) ? $biblio->{'itype'} : $biblio->{'itemtype'}; >- $datedue = CalcDateDue( $issuedate, $itype, $branch, $borrower ); >- >- } >- $datedue->truncate( to => 'minute'); >- $sth->execute( >- $borrower->{'borrowernumber'}, # borrowernumber >- $item->{'itemnumber'}, # itemnumber >- $issuedate->strftime('%Y-%m-%d %H:%M:00'), # issuedate >- $datedue->strftime('%Y-%m-%d %H:%M:00'), # date_due >- C4::Context->userenv->{'branch'} # branchcode >- ); >- if ( C4::Context->preference('ReturnToShelvingCart') ) { ## ReturnToShelvingCart is on, anything issued should be taken off the cart. >- CartToShelf( $item->{'itemnumber'} ); >- } >- $item->{'issues'}++; >- if ( C4::Context->preference('UpdateTotalIssuesOnCirc') ) { >- UpdateTotalIssues($item->{'biblionumber'}, 1); >- } >+ ); >+ unless ($datedue) { >+ my $itype = >+ ( C4::Context->preference('item-level_itypes') ) >+ ? $biblio->{'itype'} >+ : $biblio->{'itemtype'}; >+ $datedue = >+ CalcDateDue( $issuedate, $itype, $branch, $borrower ); > >- ## If item was lost, it has now been found, reverse any list item charges if neccessary. >- if ( $item->{'itemlost'} ) { >- if ( C4::Context->preference('RefundLostItemFeeOnReturn' ) ) { >- _FixAccountForLostAndReturned( $item->{'itemnumber'}, undef, $item->{'barcode'} ); > } >- } >+ $datedue->truncate( to => 'minute' ); >+ $sth->execute( >+ $borrower->{'borrowernumber'}, # borrowernumber >+ $item->{'itemnumber'}, # itemnumber >+ $issuedate->strftime('%Y-%m-%d %H:%M:00'), # issuedate >+ $datedue->strftime('%Y-%m-%d %H:%M:00'), # date_due >+ C4::Context->userenv->{'branch'} # branchcode >+ ); >+ if ( C4::Context->preference('ReturnToShelvingCart') ) >+ { ## ReturnToShelvingCart is on, anything issued should be taken off the cart. >+ CartToShelf( $item->{'itemnumber'} ); >+ } >+ $item->{'issues'}++; >+ if ( C4::Context->preference('UpdateTotalIssuesOnCirc') ) { >+ UpdateTotalIssues( $item->{'biblionumber'}, 1 ); >+ } > >- ModItem({ issues => $item->{'issues'}, >- holdingbranch => C4::Context->userenv->{'branch'}, >- itemlost => 0, >- datelastborrowed => DateTime->now(time_zone => C4::Context->tz())->ymd(), >- onloan => $datedue->ymd(), >- }, $item->{'biblionumber'}, $item->{'itemnumber'}); >- ModDateLastSeen( $item->{'itemnumber'} ); >+ ## If item was lost, it has now been found, reverse any list item charges if neccessary. >+ if ( $item->{'itemlost'} ) { >+ if ( C4::Context->preference('RefundLostItemFeeOnReturn') ) { >+ _FixAccountForLostAndReturned( $item->{'itemnumber'}, >+ undef, $item->{'barcode'} ); >+ } >+ } > >- # If it costs to borrow this book, charge it to the patron's account. >- my ( $charge, $itemtype ) = GetIssuingCharges( >- $item->{'itemnumber'}, >- $borrower->{'borrowernumber'} >- ); >- if ( $charge > 0 ) { >- AddIssuingCharge( >- $item->{'itemnumber'}, >- $borrower->{'borrowernumber'}, $charge >+ ModItem( >+ { >+ issues => $item->{'issues'}, >+ holdingbranch => C4::Context->userenv->{'branch'}, >+ itemlost => 0, >+ datelastborrowed => >+ DateTime->now( time_zone => C4::Context->tz() )->ymd(), >+ onloan => $datedue->ymd(), >+ }, >+ $item->{'biblionumber'}, >+ $item->{'itemnumber'} > ); >- $item->{'charge'} = $charge; >- } >+ ModDateLastSeen( $item->{'itemnumber'} ); >+ >+ # If it costs to borrow this book, charge it to the patron's account. >+ my ( $charge, $itemtype ) = >+ GetIssuingCharges( $item->{'itemnumber'}, >+ $borrower->{'borrowernumber'} ); >+ if ( $charge > 0 ) { >+ AddIssuingCharge( $item->{'itemnumber'}, >+ $borrower->{'borrowernumber'}, $charge ); >+ $item->{'charge'} = $charge; >+ } > >- # Record the fact that this book was issued. >- &UpdateStats( >- C4::Context->userenv->{'branch'}, >- 'issue', $charge, >- ($sipmode ? "SIP-$sipmode" : ''), $item->{'itemnumber'}, >- $item->{'itype'}, $borrower->{'borrowernumber'}, undef, $item->{'ccode'} >- ); >+ # Record the fact that this book was issued. >+ &UpdateStats( >+ C4::Context->userenv->{'branch'}, >+ 'issue', >+ $charge, >+ ( $sipmode ? "SIP-$sipmode" : '' ), >+ $item->{'itemnumber'}, >+ $item->{'itype'}, >+ $borrower->{'borrowernumber'}, >+ undef, >+ $item->{'ccode'} >+ ); > >- # Send a checkout slip. >- my $circulation_alert = 'C4::ItemCirculationAlertPreference'; >- my %conditions = ( >- branchcode => $branch, >- categorycode => $borrower->{categorycode}, >- item_type => $item->{itype}, >- notification => 'CHECKOUT', >- ); >- if ($circulation_alert->is_enabled_for(\%conditions)) { >- SendCirculationAlert({ >- type => 'CHECKOUT', >- item => $item, >- borrower => $borrower, >- branch => $branch, >- }); >+ # Send a checkout slip. >+ my $circulation_alert = 'C4::ItemCirculationAlertPreference'; >+ my %conditions = ( >+ branchcode => $branch, >+ categorycode => $borrower->{categorycode}, >+ item_type => $item->{itype}, >+ notification => 'CHECKOUT', >+ ); >+ if ( $circulation_alert->is_enabled_for( \%conditions ) ) { >+ SendCirculationAlert( >+ { >+ type => 'CHECKOUT', >+ item => $item, >+ borrower => $borrower, >+ branch => $branch, >+ } >+ ); >+ } > } >- } > >- logaction("CIRCULATION", "ISSUE", $borrower->{'borrowernumber'}, $biblio->{'itemnumber'}) >- if C4::Context->preference("IssueLog"); >- } >- return ($datedue); # not necessarily the same as when it came in! >+ logaction( >+ "CIRCULATION", "ISSUE", >+ $borrower->{'borrowernumber'}, >+ $biblio->{'itemnumber'} >+ ) if C4::Context->preference("IssueLog"); >+ } >+ return ($datedue); # not necessarily the same as when it came in! > } > > =head2 GetLoanLength >@@ -1339,17 +1469,19 @@ Get loan length for an itemtype, a borrower type and a branch > sub GetLoanLength { > my ( $borrowertype, $itemtype, $branchcode ) = @_; > my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare(qq{ >+ my $sth = $dbh->prepare( >+ qq{ > SELECT issuelength, lengthunit, renewalperiod > FROM issuingrules > WHERE categorycode=? > AND itemtype=? > AND branchcode=? > AND issuelength IS NOT NULL >- }); >+ } >+ ); > >- # try to find issuelength & return the 1st available. >- # check with borrowertype, itemtype and branchcode, then without one of those parameters >+# try to find issuelength & return the 1st available. >+# check with borrowertype, itemtype and branchcode, then without one of those parameters > $sth->execute( $borrowertype, $itemtype, $branchcode ); > my $loanlength = $sth->fetchrow_hashref; > >@@ -1393,14 +1525,13 @@ sub GetLoanLength { > > # if no rule is set => 21 days (hardcoded) > return { >- issuelength => 21, >+ issuelength => 21, > renewalperiod => 21, >- lengthunit => 'days', >+ lengthunit => 'days', > }; > > } > >- > =head2 GetHardDueDate > > my ($hardduedate,$hardduedatecompare) = &GetHardDueDate($borrowertype,$itemtype,branchcode) >@@ -1414,11 +1545,13 @@ sub GetHardDueDate { > > my $rule = GetIssuingRule( $borrowertype, $itemtype, $branchcode ); > >- if ( defined( $rule ) ) { >+ if ( defined($rule) ) { > if ( $rule->{hardduedate} ) { >- return (dt_from_string($rule->{hardduedate}, 'iso'),$rule->{hardduedatecompare}); >- } else { >- return (undef, undef); >+ return ( dt_from_string( $rule->{hardduedate}, 'iso' ), >+ $rule->{hardduedatecompare} ); >+ } >+ else { >+ return ( undef, undef ); > } > } > } >@@ -1439,40 +1572,42 @@ Returns a hashref from the issuingrules table. > sub GetIssuingRule { > my ( $borrowertype, $itemtype, $branchcode ) = @_; > my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare( "select * from issuingrules where categorycode=? and itemtype=? and branchcode=? and issuelength is not null" ); >+ my $sth = $dbh->prepare( >+"select * from issuingrules where categorycode=? and itemtype=? and branchcode=? and issuelength is not null" >+ ); > my $irule; > > $sth->execute( $borrowertype, $itemtype, $branchcode ); > $irule = $sth->fetchrow_hashref; >- return $irule if defined($irule) ; >+ return $irule if defined($irule); > > $sth->execute( $borrowertype, "*", $branchcode ); > $irule = $sth->fetchrow_hashref; >- return $irule if defined($irule) ; >+ return $irule if defined($irule); > > $sth->execute( "*", $itemtype, $branchcode ); > $irule = $sth->fetchrow_hashref; >- return $irule if defined($irule) ; >+ return $irule if defined($irule); > > $sth->execute( "*", "*", $branchcode ); > $irule = $sth->fetchrow_hashref; >- return $irule if defined($irule) ; >+ return $irule if defined($irule); > > $sth->execute( $borrowertype, $itemtype, "*" ); > $irule = $sth->fetchrow_hashref; >- return $irule if defined($irule) ; >+ return $irule if defined($irule); > > $sth->execute( $borrowertype, "*", "*" ); > $irule = $sth->fetchrow_hashref; >- return $irule if defined($irule) ; >+ return $irule if defined($irule); > > $sth->execute( "*", $itemtype, "*" ); > $irule = $sth->fetchrow_hashref; >- return $irule if defined($irule) ; >+ return $irule if defined($irule); > > $sth->execute( "*", "*", "*" ); > $irule = $sth->fetchrow_hashref; >- return $irule if defined($irule) ; >+ return $irule if defined($irule); > > # if no rule matches, > return; >@@ -1511,7 +1646,7 @@ wildcards. > =cut > > sub GetBranchBorrowerCircRule { >- my $branchcode = shift; >+ my $branchcode = shift; > my $categorycode = shift; > > my $branch_cat_query = "SELECT maxissueqty >@@ -1520,9 +1655,9 @@ sub GetBranchBorrowerCircRule { > AND categorycode = ?"; > my $dbh = C4::Context->dbh(); > my $sth = $dbh->prepare($branch_cat_query); >- $sth->execute($branchcode, $categorycode); >+ $sth->execute( $branchcode, $categorycode ); > my $result; >- if ($result = $sth->fetchrow_hashref()) { >+ if ( $result = $sth->fetchrow_hashref() ) { > return $result; > } > >@@ -1532,7 +1667,7 @@ sub GetBranchBorrowerCircRule { > WHERE branchcode = ?"; > $sth = $dbh->prepare($branch_query); > $sth->execute($branchcode); >- if ($result = $sth->fetchrow_hashref()) { >+ if ( $result = $sth->fetchrow_hashref() ) { > return $result; > } > >@@ -1542,23 +1677,21 @@ sub GetBranchBorrowerCircRule { > WHERE categorycode = ?"; > $sth = $dbh->prepare($category_query); > $sth->execute($categorycode); >- if ($result = $sth->fetchrow_hashref()) { >+ if ( $result = $sth->fetchrow_hashref() ) { > return $result; > } >- >+ > # try default branch, default borrower category > my $default_query = "SELECT maxissueqty > FROM default_circ_rules"; > $sth = $dbh->prepare($default_query); > $sth->execute(); >- if ($result = $sth->fetchrow_hashref()) { >+ if ( $result = $sth->fetchrow_hashref() ) { > return $result; > } >- >+ > # built-in default circulation rule >- return { >- maxissueqty => undef, >- }; >+ return { maxissueqty => undef, }; > } > > =head2 GetBranchItemRule >@@ -1592,39 +1725,50 @@ Neither C<$branchcode> nor C<$itemtype> should be '*'. > > sub GetBranchItemRule { > my ( $branchcode, $itemtype ) = @_; >- my $dbh = C4::Context->dbh(); >+ my $dbh = C4::Context->dbh(); > my $result = {}; > > my @attempts = ( >- ['SELECT holdallowed, returnbranch >+ [ >+ 'SELECT holdallowed, returnbranch > FROM branch_item_rules > WHERE branchcode = ? >- AND itemtype = ?', $branchcode, $itemtype], >- ['SELECT holdallowed, returnbranch >+ AND itemtype = ?', $branchcode, $itemtype >+ ], >+ [ >+ 'SELECT holdallowed, returnbranch > FROM default_branch_circ_rules >- WHERE branchcode = ?', $branchcode], >- ['SELECT holdallowed, returnbranch >+ WHERE branchcode = ?', $branchcode >+ ], >+ [ >+ 'SELECT holdallowed, returnbranch > FROM default_branch_item_rules >- WHERE itemtype = ?', $itemtype], >- ['SELECT holdallowed, returnbranch >- FROM default_circ_rules'], >+ WHERE itemtype = ?', $itemtype >+ ], >+ [ >+ 'SELECT holdallowed, returnbranch >+ FROM default_circ_rules' >+ ], > ); > > foreach my $attempt (@attempts) { >- my ($query, @bind_params) = @{$attempt}; >- my $search_result = $dbh->selectrow_hashref ( $query , {}, @bind_params ) >+ my ( $query, @bind_params ) = @{$attempt}; >+ my $search_result = $dbh->selectrow_hashref( $query, {}, @bind_params ) > or next; > > # Since branch/category and branch/itemtype use the same per-branch > # defaults tables, we have to check that the key we want is set, not > # just that a row was returned >- $result->{'holdallowed'} = $search_result->{'holdallowed'} unless ( defined $result->{'holdallowed'} ); >- $result->{'returnbranch'} = $search_result->{'returnbranch'} unless ( defined $result->{'returnbranch'} ); >+ $result->{'holdallowed'} = $search_result->{'holdallowed'} >+ unless ( defined $result->{'holdallowed'} ); >+ $result->{'returnbranch'} = $search_result->{'returnbranch'} >+ unless ( defined $result->{'returnbranch'} ); > } >- >+ > # built-in default circulation rule > $result->{'holdallowed'} = 2 unless ( defined $result->{'holdallowed'} ); >- $result->{'returnbranch'} = 'homebranch' unless ( defined $result->{'returnbranch'} ); >+ $result->{'returnbranch'} = 'homebranch' >+ unless ( defined $result->{'returnbranch'} ); > > return $result; > } >@@ -1706,61 +1850,75 @@ patron who last borrowed the book. > sub AddReturn { > my ( $barcode, $branch, $exemptfine, $dropbox ) = @_; > >- if ($branch and not GetBranchDetail($branch)) { >- warn "AddReturn error: branch '$branch' not found. Reverting to " . C4::Context->userenv->{'branch'}; >+ if ( $branch and not GetBranchDetail($branch) ) { >+ warn "AddReturn error: branch '$branch' not found. Reverting to " >+ . C4::Context->userenv->{'branch'}; > undef $branch; > } >- $branch = C4::Context->userenv->{'branch'} unless $branch; # we trust userenv to be a safe fallback/default >+ $branch = C4::Context->userenv->{'branch'} >+ unless $branch; # we trust userenv to be a safe fallback/default > my $messages; > my $borrower; > my $biblio; > my $doreturn = 1; > my $validTransfert = 0; >- my $stat_type = 'return'; >+ my $stat_type = 'return'; > > # get information on item >- my $itemnumber = GetItemnumberFromBarcode( $barcode ); >+ my $itemnumber = GetItemnumberFromBarcode($barcode); > unless ($itemnumber) { >- return (0, { BadBarcode => $barcode }); # no barcode means no item or borrower. bail out. >- } >- my $issue = GetItemIssue($itemnumber); >-# warn Dumper($iteminformation); >- if ($issue and $issue->{borrowernumber}) { >- $borrower = C4::Members::GetMemberDetails($issue->{borrowernumber}) >- or die "Data inconsistency: barcode $barcode (itemnumber:$itemnumber) claims to be issued to non-existant borrowernumber '$issue->{borrowernumber}'\n" >- . Dumper($issue) . "\n"; >- } else { >+ return ( 0, { BadBarcode => $barcode } ) >+ ; # no barcode means no item or borrower. bail out. >+ } >+ my $issue = GetItemIssue($itemnumber); >+ >+ # warn Dumper($iteminformation); >+ if ( $issue and $issue->{borrowernumber} ) { >+ $borrower = C4::Members::GetMemberDetails( $issue->{borrowernumber} ) >+ or die >+"Data inconsistency: barcode $barcode (itemnumber:$itemnumber) claims to be issued to non-existant borrowernumber '$issue->{borrowernumber}'\n" >+ . Dumper($issue) . "\n"; >+ } >+ else { > $messages->{'NotIssued'} = $barcode; >- # even though item is not on loan, it may still be transferred; therefore, get current branch info >+ >+# even though item is not on loan, it may still be transferred; therefore, get current branch info > $doreturn = 0; >- # No issue, no borrowernumber. ONLY if $doreturn, *might* you have a $borrower later. >- # Record this as a local use, instead of a return, if the RecordLocalUseOnReturn is on >- if (C4::Context->preference("RecordLocalUseOnReturn")) { >- $messages->{'LocalUse'} = 1; >- $stat_type = 'localuse'; >+ >+# No issue, no borrowernumber. ONLY if $doreturn, *might* you have a $borrower later. >+# Record this as a local use, instead of a return, if the RecordLocalUseOnReturn is on >+ if ( C4::Context->preference("RecordLocalUseOnReturn") ) { >+ $messages->{'LocalUse'} = 1; >+ $stat_type = 'localuse'; > } > } > > my $item = GetItem($itemnumber) or die "GetItem($itemnumber) failed"; >- # full item data, but no borrowernumber or checkout info (no issue) >- # we know GetItem should work because GetItemnumberFromBarcode worked >- my $hbr = GetBranchItemRule($item->{'homebranch'}, $item->{'itype'})->{'returnbranch'} || "homebranch"; >- # get the proper branch to which to return the item >- $hbr = $item->{$hbr} || $branch ; >- # if $hbr was "noreturn" or any other non-item table value, then it should 'float' (i.e. stay at this branch) >- >- my $borrowernumber = $borrower->{'borrowernumber'} || undef; # we don't know if we had a borrower or not >- >- # check if the book is in a permanent collection.... >- # FIXME -- This 'PE' attribute is largely undocumented. afaict, there's no user interface that reflects this functionality. >- if ( $hbr ) { >- my $branches = GetBranches(); # a potentially expensive call for a non-feature. >+ >+ # full item data, but no borrowernumber or checkout info (no issue) >+ # we know GetItem should work because GetItemnumberFromBarcode worked >+ my $hbr = GetBranchItemRule( $item->{'homebranch'}, $item->{'itype'} ) >+ ->{'returnbranch'} || "homebranch"; >+ >+ # get the proper branch to which to return the item >+ $hbr = $item->{$hbr} || $branch; >+ >+# if $hbr was "noreturn" or any other non-item table value, then it should 'float' (i.e. stay at this branch) >+ >+ my $borrowernumber = $borrower->{'borrowernumber'} >+ || undef; # we don't know if we had a borrower or not >+ >+# check if the book is in a permanent collection.... >+# FIXME -- This 'PE' attribute is largely undocumented. afaict, there's no user interface that reflects this functionality. >+ if ($hbr) { >+ my $branches = >+ GetBranches(); # a potentially expensive call for a non-feature. > $branches->{$hbr}->{PE} and $messages->{'IsPermanent'} = $hbr; > } > > # check if the return is allowed at this branch >- my ($returnallowed, $message) = CanBookBeReturned($item, $branch); >- unless ($returnallowed){ >+ my ( $returnallowed, $message ) = CanBookBeReturned( $item, $branch ); >+ unless ($returnallowed) { > $messages->{'Wrongbranch'} = { > Wrongbranch => $branch, > Rightbranch => $message >@@ -1769,7 +1927,7 @@ sub AddReturn { > return ( $doreturn, $messages, $issue, $borrower ); > } > >- if ( $item->{'withdrawn'} ) { # book has been cancelled >+ if ( $item->{'withdrawn'} ) { # book has been cancelled > $messages->{'withdrawn'} = 1; > $doreturn = 0 if C4::Context->preference("BlockReturnOfWithdrawnItems"); > } >@@ -1777,22 +1935,26 @@ sub AddReturn { > # case of a return of document (deal with issues and holdingbranch) > my $today = DateTime->now( time_zone => C4::Context->tz() ); > if ($doreturn) { >- my $datedue = $issue->{date_due}; >+ my $datedue = $issue->{date_due}; > $borrower or warn "AddReturn without current borrower"; > my $circControlBranch; > if ($dropbox) { >- # define circControlBranch only if dropbox mode is set >- # don't allow dropbox mode to create an invalid entry in issues (issuedate > today) >- # FIXME: check issuedate > returndate, factoring in holidays >- #$circControlBranch = _GetCircControlBranch($item,$borrower) unless ( $item->{'issuedate'} eq C4::Dates->today('iso') );; >- $circControlBranch = _GetCircControlBranch($item,$borrower); >- $issue->{'overdue'} = DateTime->compare($issue->{'date_due'}, $today ) == -1 ? 1 : 0; >+ >+# define circControlBranch only if dropbox mode is set >+# don't allow dropbox mode to create an invalid entry in issues (issuedate > today) >+# FIXME: check issuedate > returndate, factoring in holidays >+#$circControlBranch = _GetCircControlBranch($item,$borrower) unless ( $item->{'issuedate'} eq C4::Dates->today('iso') );; >+ $circControlBranch = _GetCircControlBranch( $item, $borrower ); >+ $issue->{'overdue'} = >+ DateTime->compare( $issue->{'date_due'}, $today ) == -1 ? 1 : 0; > } > > if ($borrowernumber) { >- if( C4::Context->preference('CalculateFinesOnReturn') && $issue->{'overdue'}){ >- # we only need to calculate and change the fines if we want to do that on return >- # Should be on for hourly loans >+ if ( C4::Context->preference('CalculateFinesOnReturn') >+ && $issue->{'overdue'} ) >+ { >+# we only need to calculate and change the fines if we want to do that on return >+# Should be on for hourly loans > my $control = C4::Context->preference('CircControl'); > my $control_branchcode = > ( $control eq 'ItemHomeLibrary' ) ? $item->{homebranch} >@@ -1822,126 +1984,169 @@ sub AddReturn { > > } > >- ModItem({ onloan => undef }, $issue->{'biblionumber'}, $item->{'itemnumber'}); >+ ModItem( >+ { onloan => undef }, >+ $issue->{'biblionumber'}, >+ $item->{'itemnumber'} >+ ); > } > >- # the holdingbranch is updated if the document is returned to another location. >- # this is always done regardless of whether the item was on loan or not >- if ($item->{'holdingbranch'} ne $branch) { >- UpdateHoldingbranch($branch, $item->{'itemnumber'}); >+ # the holdingbranch is updated if the document is returned to another location. >+ # this is always done regardless of whether the item was on loan or not >+ if ( $item->{'holdingbranch'} ne $branch ) { >+ UpdateHoldingbranch( $branch, $item->{'itemnumber'} ); > $item->{'holdingbranch'} = $branch; # update item data holdingbranch too > } > ModDateLastSeen( $item->{'itemnumber'} ); > > # check if we have a transfer for this document >- my ($datesent,$frombranch,$tobranch) = GetTransfers( $item->{'itemnumber'} ); >+ my ( $datesent, $frombranch, $tobranch ) = >+ GetTransfers( $item->{'itemnumber'} ); > >- # if we have a transfer to do, we update the line of transfers with the datearrived >+# if we have a transfer to do, we update the line of transfers with the datearrived > if ($datesent) { > if ( $tobranch eq $branch ) { > my $sth = C4::Context->dbh->prepare( >- "UPDATE branchtransfers SET datearrived = now() WHERE itemnumber= ? AND datearrived IS NULL" >+"UPDATE branchtransfers SET datearrived = now() WHERE itemnumber= ? AND datearrived IS NULL" > ); > $sth->execute( $item->{'itemnumber'} ); >- # if we have a reservation with valid transfer, we can set it's status to 'W' >- ShelfToCart( $item->{'itemnumber'} ) if ( C4::Context->preference("ReturnToShelvingCart") ); >- C4::Reserves::ModReserveStatus($item->{'itemnumber'}, 'W'); >- } else { >+ >+ # if we have a reservation with valid transfer, we can set it's status to 'W' >+ ShelfToCart( $item->{'itemnumber'} ) >+ if ( C4::Context->preference("ReturnToShelvingCart") ); >+ C4::Reserves::ModReserveStatus( $item->{'itemnumber'}, 'W' ); >+ } >+ else { > $messages->{'WrongTransfer'} = $tobranch; > $messages->{'WrongTransferItem'} = $item->{'itemnumber'}; > } > $validTransfert = 1; >- } else { >- ShelfToCart( $item->{'itemnumber'} ) if ( C4::Context->preference("ReturnToShelvingCart") ); >+ } >+ else { >+ ShelfToCart( $item->{'itemnumber'} ) >+ if ( C4::Context->preference("ReturnToShelvingCart") ); > } > > # fix up the accounts..... > if ( $item->{'itemlost'} ) { > $messages->{'WasLost'} = 1; > >- if ( C4::Context->preference('RefundLostItemFeeOnReturn' ) ) { >- _FixAccountForLostAndReturned($item->{'itemnumber'}, $borrowernumber, $barcode); # can tolerate undef $borrowernumber >+ if ( C4::Context->preference('RefundLostItemFeeOnReturn') ) { >+ _FixAccountForLostAndReturned( $item->{'itemnumber'}, >+ $borrowernumber, $barcode ) >+ ; # can tolerate undef $borrowernumber > $messages->{'LostItemFeeRefunded'} = 1; > } > } > > # fix up the overdues in accounts... > if ($borrowernumber) { >- my $fix = _FixOverduesOnReturn($borrowernumber, $item->{itemnumber}, $exemptfine, $dropbox); >- defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $item->{itemnumber}...) failed!"; # zero is OK, check defined >- >+ my $fix = _FixOverduesOnReturn( $borrowernumber, $item->{itemnumber}, >+ $exemptfine, $dropbox ); >+ defined($fix) >+ or warn >+"_FixOverduesOnReturn($borrowernumber, $item->{itemnumber}...) failed!" >+ ; # zero is OK, check defined >+ > if ( $issue->{overdue} && $issue->{date_due} ) { >-# fix fine days >+ >+ # fix fine days > my $debardate = >- _debar_user_on_return( $borrower, $item, $issue->{date_due}, $today ); >+ _debar_user_on_return( $borrower, $item, $issue->{date_due}, >+ $today ); > $messages->{Debarred} = $debardate if ($debardate); > } > } > >- # find reserves..... >- # if we don't have a reserve with the status W, we launch the Checkreserves routine >- my ($resfound, $resrec); >- my $lookahead= C4::Context->preference('ConfirmFutureHolds'); #number of days to look for future holds >- ($resfound, $resrec, undef) = C4::Reserves::CheckReserves( $item->{'itemnumber'}, undef, $lookahead ) unless ( $item->{'withdrawn'} ); >+# find reserves..... >+# if we don't have a reserve with the status W, we launch the Checkreserves routine >+ my ( $resfound, $resrec ); >+ my $lookahead = C4::Context->preference('ConfirmFutureHolds') >+ ; #number of days to look for future holds >+ ( $resfound, $resrec, undef ) = >+ C4::Reserves::CheckReserves( $item->{'itemnumber'}, undef, $lookahead ) >+ unless ( $item->{'withdrawn'} ); > if ($resfound) { >- $resrec->{'ResFound'} = $resfound; >+ $resrec->{'ResFound'} = $resfound; > $messages->{'ResFound'} = $resrec; > } > > # update stats? > # Record the fact that this book was returned. >- UpdateStats( >- $branch, $stat_type, '0', '', >- $item->{'itemnumber'}, >- $biblio->{'itemtype'}, >- $borrowernumber, undef, $item->{'ccode'} >- ); >+ UpdateStats( $branch, $stat_type, '0', '', $item->{'itemnumber'}, >+ $biblio->{'itemtype'}, $borrowernumber, undef, $item->{'ccode'} ); > >- # Send a check-in slip. # NOTE: borrower may be undef. probably shouldn't try to send messages then. >+# Send a check-in slip. # NOTE: borrower may be undef. probably shouldn't try to send messages then. > my $circulation_alert = 'C4::ItemCirculationAlertPreference'; >- my %conditions = ( >+ my %conditions = ( > branchcode => $branch, > categorycode => $borrower->{categorycode}, > item_type => $item->{itype}, > notification => 'CHECKIN', > ); >- if ($doreturn && $circulation_alert->is_enabled_for(\%conditions)) { >- SendCirculationAlert({ >- type => 'CHECKIN', >- item => $item, >- borrower => $borrower, >- branch => $branch, >- }); >- } >- >- logaction("CIRCULATION", "RETURN", $borrowernumber, $item->{'itemnumber'}) >- if C4::Context->preference("ReturnLog"); >- >+ if ( $doreturn && $circulation_alert->is_enabled_for( \%conditions ) ) { >+ SendCirculationAlert( >+ { >+ type => 'CHECKIN', >+ item => $item, >+ borrower => $borrower, >+ branch => $branch, >+ } >+ ); >+ } >+ >+ logaction( "CIRCULATION", "RETURN", $borrowernumber, $item->{'itemnumber'} ) >+ if C4::Context->preference("ReturnLog"); >+ > # Remove any OVERDUES related debarment if the borrower has no overdues >- if ( $borrowernumber >- && $borrower->{'debarred'} >- && C4::Context->preference('AutoRemoveOverduesRestrictions') >- && !HasOverdues( $borrowernumber ) >- && @{ GetDebarments({ borrowernumber => $borrowernumber, type => 'OVERDUES' }) } >- ) { >- DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' }); >- } >- >- # FIXME: make this comment intelligible. >- #adding message if holdingbranch is non equal a userenv branch to return the document to homebranch >- #we check, if we don't have reserv or transfert for this document, if not, return it to homebranch . >- >- if (($doreturn or $messages->{'NotIssued'}) and !$resfound and ($branch ne $hbr) and not $messages->{'WrongTransfer'}){ >- if ( C4::Context->preference("AutomaticItemReturn" ) or >- (C4::Context->preference("UseBranchTransferLimits") and >- ! IsBranchTransferAllowed($branch, $hbr, $item->{C4::Context->preference("BranchTransferLimitsType")} ) >- )) { >- $debug and warn sprintf "about to call ModItemTransfer(%s, %s, %s)", $item->{'itemnumber'},$branch, $hbr; >+ if ( >+ $borrowernumber >+ && $borrower->{'debarred'} >+ && C4::Context->preference('AutoRemoveOverduesRestrictions') >+ && !HasOverdues($borrowernumber) >+ && @{ >+ GetDebarments( >+ { borrowernumber => $borrowernumber, type => 'OVERDUES' } >+ ) >+ } >+ ) >+ { >+ DelUniqueDebarment( >+ { borrowernumber => $borrowernumber, type => 'OVERDUES' } ); >+ } >+ >+# FIXME: make this comment intelligible. >+#adding message if holdingbranch is non equal a userenv branch to return the document to homebranch >+#we check, if we don't have reserv or transfert for this document, if not, return it to homebranch . >+ >+ if ( ( $doreturn or $messages->{'NotIssued'} ) >+ and !$resfound >+ and ( $branch ne $hbr ) >+ and not $messages->{'WrongTransfer'} ) >+ { >+ if ( >+ C4::Context->preference("AutomaticItemReturn") >+ or ( >+ C4::Context->preference("UseBranchTransferLimits") >+ and !IsBranchTransferAllowed( >+ $branch, >+ $hbr, >+ $item->{ C4::Context->preference("BranchTransferLimitsType") >+ } >+ ) >+ ) >+ ) >+ { >+ $debug >+ and warn sprintf "about to call ModItemTransfer(%s, %s, %s)", >+ $item->{'itemnumber'}, $branch, $hbr; > $debug and warn "item: " . Dumper($item); >- ModItemTransfer($item->{'itemnumber'}, $branch, $hbr); >+ ModItemTransfer( $item->{'itemnumber'}, $branch, $hbr ); > $messages->{'WasTransfered'} = 1; >- } else { >- $messages->{'NeedsTransfer'} = 1; # TODO: instead of 1, specify branchcode that the transfer SHOULD go to, $item->{homebranch} >+ } >+ else { >+ $messages->{'NeedsTransfer'} = 1 >+ ; # TODO: instead of 1, specify branchcode that the transfer SHOULD go to, $item->{homebranch} > } > } > return ( $doreturn, $messages, $issue, $borrower ); >@@ -1971,46 +2176,63 @@ routine in C<C4::Accounts>. > =cut > > sub MarkIssueReturned { >- my ( $borrowernumber, $itemnumber, $dropbox_branch, $returndate, $privacy ) = @_; >+ my ( $borrowernumber, $itemnumber, $dropbox_branch, $returndate, $privacy ) >+ = @_; > > my $dbh = C4::Context->dbh; > my $query = 'UPDATE issues SET returndate='; > my @bind; > if ($dropbox_branch) { > my $calendar = Koha::Calendar->new( branchcode => $dropbox_branch ); >- my $dropboxdate = $calendar->addDate( DateTime->now( time_zone => C4::Context->tz), -1 ); >+ my $dropboxdate = >+ $calendar->addDate( DateTime->now( time_zone => C4::Context->tz ), >+ -1 ); > $query .= ' ? '; > push @bind, $dropboxdate->strftime('%Y-%m-%d %H:%M'); >- } elsif ($returndate) { >+ } >+ elsif ($returndate) { > $query .= ' ? '; > push @bind, $returndate; >- } else { >+ } >+ else { > $query .= ' now() '; > } > $query .= ' WHERE borrowernumber = ? AND itemnumber = ?'; > push @bind, $borrowernumber, $itemnumber; >+ > # FIXME transaction >- my $sth_upd = $dbh->prepare($query); >+ my $sth_upd = $dbh->prepare($query); > $sth_upd->execute(@bind); >- my $sth_copy = $dbh->prepare('INSERT INTO old_issues SELECT * FROM issues >+ my $sth_copy = $dbh->prepare( >+ 'INSERT INTO old_issues SELECT * FROM issues > WHERE borrowernumber = ? >- AND itemnumber = ?'); >- $sth_copy->execute($borrowernumber, $itemnumber); >- # anonymise patron checkout immediately if $privacy set to 2 and AnonymousPatron is set to a valid borrowernumber >- if ( $privacy == 2) { >- # The default of 0 does not work due to foreign key constraints >- # The anonymisation will fail quietly if AnonymousPatron is not a valid entry >- # FIXME the above is unacceptable - bug 9942 relates >- my $anonymouspatron = (C4::Context->preference('AnonymousPatron')) ? C4::Context->preference('AnonymousPatron') : 0; >- my $sth_ano = $dbh->prepare("UPDATE old_issues SET borrowernumber=? >+ AND itemnumber = ?' >+ ); >+ $sth_copy->execute( $borrowernumber, $itemnumber ); >+ >+# anonymise patron checkout immediately if $privacy set to 2 and AnonymousPatron is set to a valid borrowernumber >+ if ( $privacy == 2 ) { >+ >+ # The default of 0 does not work due to foreign key constraints >+ # The anonymisation will fail quietly if AnonymousPatron is not a valid entry >+ # FIXME the above is unacceptable - bug 9942 relates >+ my $anonymouspatron = >+ ( C4::Context->preference('AnonymousPatron') ) >+ ? C4::Context->preference('AnonymousPatron') >+ : 0; >+ my $sth_ano = $dbh->prepare( >+ "UPDATE old_issues SET borrowernumber=? > WHERE borrowernumber = ? >- AND itemnumber = ?"); >- $sth_ano->execute($anonymouspatron, $borrowernumber, $itemnumber); >+ AND itemnumber = ?" >+ ); >+ $sth_ano->execute( $anonymouspatron, $borrowernumber, $itemnumber ); > } >- my $sth_del = $dbh->prepare("DELETE FROM issues >+ my $sth_del = $dbh->prepare( >+ "DELETE FROM issues > WHERE borrowernumber = ? >- AND itemnumber = ?"); >- $sth_del->execute($borrowernumber, $itemnumber); >+ AND itemnumber = ?" >+ ); >+ $sth_del->execute( $borrowernumber, $itemnumber ); > } > > =head2 _debar_user_on_return >@@ -2061,11 +2283,13 @@ sub _debar_user_on_return { > my $new_debar_dt = > $dt_today->clone()->add_duration( $deltadays * $finedays ); > >- Koha::Borrower::Debarments::AddUniqueDebarment({ >- borrowernumber => $borrower->{borrowernumber}, >- expiration => $new_debar_dt->ymd(), >- type => 'SUSPENSION', >- }); >+ Koha::Borrower::Debarments::AddUniqueDebarment( >+ { >+ borrowernumber => $borrower->{borrowernumber}, >+ expiration => $new_debar_dt->ymd(), >+ type => 'SUSPENSION', >+ } >+ ); > > return $new_debar_dt->ymd(); > } >@@ -2089,16 +2313,16 @@ Internal function, called only by AddReturn > =cut > > sub _FixOverduesOnReturn { >- my ($borrowernumber, $item); >- unless ($borrowernumber = shift) { >+ my ( $borrowernumber, $item ); >+ unless ( $borrowernumber = shift ) { > warn "_FixOverduesOnReturn() not supplied valid borrowernumber"; > return; > } >- unless ($item = shift) { >+ unless ( $item = shift ) { > warn "_FixOverduesOnReturn() not supplied valid itemnumber"; > return; > } >- my ($exemptfine, $dropbox) = @_; >+ my ( $exemptfine, $dropbox ) = @_; > my $dbh = C4::Context->dbh; > > # check for overdue fine >@@ -2112,24 +2336,29 @@ sub _FixOverduesOnReturn { > return 0 unless $data; # no warning, there's just nothing to fix > > my $uquery; >- my @bind = ($data->{'accountlines_id'}); >+ my @bind = ( $data->{'accountlines_id'} ); > if ($exemptfine) { >- $uquery = "update accountlines set accounttype='FFOR', amountoutstanding=0"; >- if (C4::Context->preference("FinesLog")) { >- &logaction("FINES", 'MODIFY',$borrowernumber,"Overdue forgiven: item $item"); >- } >- } elsif ($dropbox && $data->{lastincrement}) { >- my $outstanding = $data->{amountoutstanding} - $data->{lastincrement} ; >- my $amt = $data->{amount} - $data->{lastincrement} ; >- if (C4::Context->preference("FinesLog")) { >- &logaction("FINES", 'MODIFY',$borrowernumber,"Dropbox adjustment $amt, item $item"); >- } >- $uquery = "update accountlines set accounttype='F' "; >- if($outstanding >= 0 && $amt >=0) { >+ $uquery = >+ "update accountlines set accounttype='FFOR', amountoutstanding=0"; >+ if ( C4::Context->preference("FinesLog") ) { >+ &logaction( "FINES", 'MODIFY', $borrowernumber, >+ "Overdue forgiven: item $item" ); >+ } >+ } >+ elsif ( $dropbox && $data->{lastincrement} ) { >+ my $outstanding = $data->{amountoutstanding} - $data->{lastincrement}; >+ my $amt = $data->{amount} - $data->{lastincrement}; >+ if ( C4::Context->preference("FinesLog") ) { >+ &logaction( "FINES", 'MODIFY', $borrowernumber, >+ "Dropbox adjustment $amt, item $item" ); >+ } >+ $uquery = "update accountlines set accounttype='F' "; >+ if ( $outstanding >= 0 && $amt >= 0 ) { > $uquery .= ", amount = ? , amountoutstanding=? "; >- unshift @bind, ($amt, $outstanding) ; >+ unshift @bind, ( $amt, $outstanding ); > } >- } else { >+ } >+ else { > $uquery = "update accountlines set accounttype='F' "; > } > $uquery .= " where (accountlines_id = ?)"; >@@ -2151,12 +2380,19 @@ FIXME: Give a positive return value on success. It might be the $borrowernumber > =cut > > sub _FixAccountForLostAndReturned { >- my $itemnumber = shift or return; >+ my $itemnumber = shift or return; > my $borrowernumber = @_ ? shift : undef; >- my $item_id = @_ ? shift : $itemnumber; # Send the barcode if you want that logged in the description >+ my $item_id = >+ @_ >+ ? shift >+ : $itemnumber >+ ; # Send the barcode if you want that logged in the description > my $dbh = C4::Context->dbh; >+ > # check for charge made for lost book >- my $sth = $dbh->prepare("SELECT * FROM accountlines WHERE itemnumber = ? AND accounttype IN ('L', 'Rep', 'W') ORDER BY date DESC, accountno DESC"); >+ my $sth = $dbh->prepare( >+"SELECT * FROM accountlines WHERE itemnumber = ? AND accounttype IN ('L', 'Rep', 'W') ORDER BY date DESC, accountno DESC" >+ ); > $sth->execute($itemnumber); > my $data = $sth->fetchrow_hashref; > $data or return; # bail if there is nothing to do >@@ -2166,61 +2402,93 @@ sub _FixAccountForLostAndReturned { > my $offset; > my $amount = $data->{'amount'}; > my $acctno = $data->{'accountno'}; >- my $amountleft; # Starts off undef/zero. >- if ($data->{'amountoutstanding'} == $amount) { >+ my $amountleft; # Starts off undef/zero. >+ if ( $data->{'amountoutstanding'} == $amount ) { > $offset = $data->{'amount'}; >- $amountleft = 0; # Hey, it's zero here, too. >- } else { >- $offset = $amount - $data->{'amountoutstanding'}; # Um, isn't this the same as ZERO? We just tested those two things are == >- $amountleft = $data->{'amountoutstanding'} - $amount; # Um, isn't this the same as ZERO? We just tested those two things are == >- } >- my $usth = $dbh->prepare("UPDATE accountlines SET accounttype = 'LR',amountoutstanding='0' >- WHERE (accountlines_id = ?)"); >- $usth->execute($data->{'accountlines_id'}); # We might be adjusting an account for some OTHER borrowernumber now. Not the one we passed in. >- #check if any credit is left if so writeoff other accounts >- my $nextaccntno = getnextacctno($data->{'borrowernumber'}); >- $amountleft *= -1 if ($amountleft < 0); >- if ($amountleft > 0) { >- my $msth = $dbh->prepare("SELECT * FROM accountlines WHERE (borrowernumber = ?) >- AND (amountoutstanding >0) ORDER BY date"); # might want to order by amountoustanding ASC (pay smallest first) >- $msth->execute($data->{'borrowernumber'}); >+ $amountleft = 0; # Hey, it's zero here, too. >+ } >+ else { >+ $offset = $amount - $data->{'amountoutstanding'} >+ ; # Um, isn't this the same as ZERO? We just tested those two things are == >+ $amountleft = >+ $data->{'amountoutstanding'} - >+ $amount >+ ; # Um, isn't this the same as ZERO? We just tested those two things are == >+ } >+ my $usth = $dbh->prepare( >+ "UPDATE accountlines SET accounttype = 'LR',amountoutstanding='0' >+ WHERE (accountlines_id = ?)" >+ ); >+ $usth->execute( $data->{'accountlines_id'} ) >+ ; # We might be adjusting an account for some OTHER borrowernumber now. Not the one we passed in. >+ #check if any credit is left if so writeoff other accounts >+ my $nextaccntno = getnextacctno( $data->{'borrowernumber'} ); >+ $amountleft *= -1 if ( $amountleft < 0 ); >+ if ( $amountleft > 0 ) { >+ my $msth = $dbh->prepare( >+ "SELECT * FROM accountlines WHERE (borrowernumber = ?) >+ AND (amountoutstanding >0) ORDER BY date" >+ ); # might want to order by amountoustanding ASC (pay smallest first) >+ $msth->execute( $data->{'borrowernumber'} ); >+ > # offset transactions > my $newamtos; > my $accdata; >- while (($accdata=$msth->fetchrow_hashref) and ($amountleft>0)){ >- if ($accdata->{'amountoutstanding'} < $amountleft) { >+ while ( ( $accdata = $msth->fetchrow_hashref ) and ( $amountleft > 0 ) ) >+ { >+ if ( $accdata->{'amountoutstanding'} < $amountleft ) { > $newamtos = 0; > $amountleft -= $accdata->{'amountoutstanding'}; >- } else { >- $newamtos = $accdata->{'amountoutstanding'} - $amountleft; >+ } >+ else { >+ $newamtos = $accdata->{'amountoutstanding'} - $amountleft; > $amountleft = 0; > } > my $thisacct = $accdata->{'accountlines_id'}; >+ > # FIXME: move prepares outside while loop! >- my $usth = $dbh->prepare("UPDATE accountlines SET amountoutstanding= ? >- WHERE (accountlines_id = ?)"); >- $usth->execute($newamtos,$thisacct); >- $usth = $dbh->prepare("INSERT INTO accountoffsets >+ my $usth = $dbh->prepare( >+ "UPDATE accountlines SET amountoutstanding= ? >+ WHERE (accountlines_id = ?)" >+ ); >+ $usth->execute( $newamtos, $thisacct ); >+ $usth = $dbh->prepare( >+ "INSERT INTO accountoffsets > (borrowernumber, accountno, offsetaccount, offsetamount) > VALUES >- (?,?,?,?)"); >- $usth->execute($data->{'borrowernumber'},$accdata->{'accountno'},$nextaccntno,$newamtos); >+ (?,?,?,?)" >+ ); >+ $usth->execute( >+ $data->{'borrowernumber'}, >+ $accdata->{'accountno'}, >+ $nextaccntno, $newamtos >+ ); > } > } >- $amountleft *= -1 if ($amountleft > 0); >+ $amountleft *= -1 if ( $amountleft > 0 ); > my $desc = "Item Returned " . $item_id; >- $usth = $dbh->prepare("INSERT INTO accountlines >+ $usth = $dbh->prepare( >+ "INSERT INTO accountlines > (borrowernumber,accountno,date,amount,description,accounttype,amountoutstanding) >- VALUES (?,?,now(),?,?,'CR',?)"); >- $usth->execute($data->{'borrowernumber'},$nextaccntno,0-$amount,$desc,$amountleft); >+ VALUES (?,?,now(),?,?,'CR',?)" >+ ); >+ $usth->execute( >+ $data->{'borrowernumber'}, >+ $nextaccntno, 0 - $amount, >+ $desc, $amountleft >+ ); > if ($borrowernumber) { >+ > # FIXME: same as query above. use 1 sth for both >- $usth = $dbh->prepare("INSERT INTO accountoffsets >+ $usth = $dbh->prepare( >+ "INSERT INTO accountoffsets > (borrowernumber, accountno, offsetaccount, offsetamount) >- VALUES (?,?,?,?)"); >- $usth->execute($borrowernumber, $data->{'accountno'}, $nextaccntno, $offset); >+ VALUES (?,?,?,?)" >+ ); >+ $usth->execute( $borrowernumber, $data->{'accountno'}, $nextaccntno, >+ $offset ); > } >- ModItem({ paidfor => '' }, undef, $itemnumber); >+ ModItem( { paidfor => '' }, undef, $itemnumber ); > return; > } > >@@ -2241,31 +2509,32 @@ C<$borrower> is a hashref to borrower. Only {branchcode} is used. > =cut > > sub _GetCircControlBranch { >- my ($item, $borrower) = @_; >+ my ( $item, $borrower ) = @_; > my $circcontrol = C4::Context->preference('CircControl'); > my $branch; > >- if ($circcontrol eq 'PickupLibrary' and (C4::Context->userenv and C4::Context->userenv->{'branch'}) ) { >- $branch= C4::Context->userenv->{'branch'}; >- } elsif ($circcontrol eq 'PatronLibrary') { >- $branch=$borrower->{branchcode}; >- } else { >- my $branchfield = C4::Context->preference('HomeOrHoldingBranch') || 'homebranch'; >+ if ( $circcontrol eq 'PickupLibrary' >+ and ( C4::Context->userenv and C4::Context->userenv->{'branch'} ) ) >+ { >+ $branch = C4::Context->userenv->{'branch'}; >+ } >+ elsif ( $circcontrol eq 'PatronLibrary' ) { >+ $branch = $borrower->{branchcode}; >+ } >+ else { >+ my $branchfield = >+ C4::Context->preference('HomeOrHoldingBranch') || 'homebranch'; > $branch = $item->{$branchfield}; >+ > # default to item home branch if holdingbranch is used > # and is not defined >- if (!defined($branch) && $branchfield eq 'holdingbranch') { >+ if ( !defined($branch) && $branchfield eq 'holdingbranch' ) { > $branch = $item->{homebranch}; > } > } > return $branch; > } > >- >- >- >- >- > =head2 GetItemIssue > > $issue = &GetItemIssue($itemnumber); >@@ -2285,16 +2554,19 @@ sub GetItemIssue { > "SELECT items.*, issues.* > FROM issues > LEFT JOIN items ON issues.itemnumber=items.itemnumber >- WHERE issues.itemnumber=?"); >+ WHERE issues.itemnumber=?" >+ ); > $sth->execute($itemnumber); > my $data = $sth->fetchrow_hashref; > return unless $data; >- $data->{issuedate} = dt_from_string($data->{issuedate}, 'sql'); >- $data->{issuedate}->truncate(to => 'minute'); >- $data->{date_due} = dt_from_string($data->{date_due}, 'sql'); >- $data->{date_due}->truncate(to => 'minute'); >- my $dt = DateTime->now( time_zone => C4::Context->tz)->truncate( to => 'minute'); >- $data->{'overdue'} = DateTime->compare($data->{'date_due'}, $dt ) == -1 ? 1 : 0; >+ $data->{issuedate} = dt_from_string( $data->{issuedate}, 'sql' ); >+ $data->{issuedate}->truncate( to => 'minute' ); >+ $data->{date_due} = dt_from_string( $data->{date_due}, 'sql' ); >+ $data->{date_due}->truncate( to => 'minute' ); >+ my $dt = >+ DateTime->now( time_zone => C4::Context->tz )->truncate( to => 'minute' ); >+ $data->{'overdue'} = >+ DateTime->compare( $data->{'date_due'}, $dt ) == -1 ? 1 : 0; > return $data; > } > >@@ -2311,12 +2583,13 @@ Returns a hashref > =cut > > sub GetOpenIssue { >- my ( $itemnumber ) = @_; >- return unless $itemnumber; >- my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare( "SELECT * FROM issues WHERE itemnumber = ? AND returndate IS NULL" ); >- $sth->execute( $itemnumber ); >- return $sth->fetchrow_hashref(); >+ my ($itemnumber) = @_; >+ return unless $itemnumber; >+ my $dbh = C4::Context->dbh; >+ my $sth = $dbh->prepare( >+ "SELECT * FROM issues WHERE itemnumber = ? AND returndate IS NULL"); >+ $sth->execute($itemnumber); >+ return $sth->fetchrow_hashref(); > > } > >@@ -2336,8 +2609,8 @@ Returns reference to an array of hashes > > sub GetItemIssues { > my ( $itemnumber, $history ) = @_; >- >- my $today = DateTime->now( time_zome => C4::Context->tz); # get today date >+ >+ my $today = DateTime->now( time_zome => C4::Context->tz ); # get today date > $today->truncate( to => 'minute' ); > my $sql = "SELECT * FROM issues > JOIN borrowers USING (borrowernumber) >@@ -2353,16 +2626,18 @@ sub GetItemIssues { > $sql .= "ORDER BY date_due DESC"; > my $sth = C4::Context->dbh->prepare($sql); > if ($history) { >- $sth->execute($itemnumber, $itemnumber); >- } else { >+ $sth->execute( $itemnumber, $itemnumber ); >+ } >+ else { > $sth->execute($itemnumber); > } >- my $results = $sth->fetchall_arrayref({}); >+ my $results = $sth->fetchall_arrayref( {} ); > foreach (@$results) { >- my $date_due = dt_from_string($_->{date_due},'sql'); >+ my $date_due = dt_from_string( $_->{date_due}, 'sql' ); > $date_due->truncate( to => 'minute' ); > >- $_->{overdue} = (DateTime->compare($date_due, $today) == -1) ? 1 : 0; >+ $_->{overdue} = >+ ( DateTime->compare( $date_due, $today ) == -1 ) ? 1 : 0; > } > return $results; > } >@@ -2402,7 +2677,7 @@ sub GetBiblioIssues { > ORDER BY timestamp > "; > my $sth = $dbh->prepare($query); >- $sth->execute($biblionumber, $biblionumber); >+ $sth->execute( $biblionumber, $biblionumber ); > > my @issues; > while ( my $data = $sth->fetchrow_hashref ) { >@@ -2433,10 +2708,10 @@ HAVING days_until_due >= 0 AND days_until_due <= ? > END_SQL > > my @bind_parameters = ( $params->{'days_in_advance'} ); >- >- my $sth = $dbh->prepare( $statement ); >- $sth->execute( @bind_parameters ); >- my $upcoming_dues = $sth->fetchall_arrayref({}); >+ >+ my $sth = $dbh->prepare($statement); >+ $sth->execute(@bind_parameters); >+ my $upcoming_dues = $sth->fetchall_arrayref( {} ); > > return $upcoming_dues; > } >@@ -2478,21 +2753,25 @@ sub CanBookBeRenewed { > my $borrower = C4::Members::GetMemberDetails($borrowernumber) > or return; > >- my $branchcode = _GetCircControlBranch($item, $borrower); >+ my $branchcode = _GetCircControlBranch( $item, $borrower ); > >- my $issuingrule = GetIssuingRule($borrower->{categorycode}, $item->{itype}, $branchcode); >+ my $issuingrule = >+ GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $branchcode ); > >- if ( ( $issuingrule->{renewalsallowed} > $itemissue->{renewals} ) || $override_limit ) { >+ if ( ( $issuingrule->{renewalsallowed} > $itemissue->{renewals} ) >+ || $override_limit ) >+ { > $renewokay = 1; >- } else { >+ } >+ else { > $error = "too_many"; > } > >- my ( $resfound, $resrec, undef ) = C4::Reserves::CheckReserves( $itemnumber ); >+ my ( $resfound, $resrec, undef ) = C4::Reserves::CheckReserves($itemnumber); > >- if ( $resfound ) { # '' when no hold was found >+ if ($resfound) { # '' when no hold was found > $renewokay = 0; >- $error = "on_reserve"; >+ $error = "on_reserve"; > } > > return ( $renewokay, $error ); >@@ -2523,24 +2802,24 @@ from the book's item type. > =cut > > sub AddRenewal { >- my $borrowernumber = shift; >- my $itemnumber = shift or return; >- my $branch = shift; >- my $datedue = shift; >- my $lastreneweddate = shift || DateTime->now(time_zone => C4::Context->tz)->ymd(); >+ my $borrowernumber = shift; >+ my $itemnumber = shift or return; >+ my $branch = shift; >+ my $datedue = shift; >+ my $lastreneweddate = >+ shift || DateTime->now( time_zone => C4::Context->tz )->ymd(); > >- my $item = GetItem($itemnumber) or return; >+ my $item = GetItem($itemnumber) or return; > my $biblio = GetBiblioFromItemNumber($itemnumber) or return; > > my $dbh = C4::Context->dbh; > > # Find the issues record for this book >- my $sth = >- $dbh->prepare("SELECT * FROM issues WHERE itemnumber = ?"); >- $sth->execute( $itemnumber ); >+ my $sth = $dbh->prepare("SELECT * FROM issues WHERE itemnumber = ?"); >+ $sth->execute($itemnumber); > my $issuedata = $sth->fetchrow_hashref; > >- return unless ( $issuedata ); >+ return unless ($issuedata); > > $borrowernumber ||= $issuedata->{borrowernumber}; > >@@ -2554,38 +2833,50 @@ sub AddRenewal { > # based on the value of the RenewalPeriodBase syspref. > unless ($datedue) { > >- my $borrower = C4::Members::GetMember( borrowernumber => $borrowernumber ) or return; >- my $itemtype = (C4::Context->preference('item-level_itypes')) ? $biblio->{'itype'} : $biblio->{'itemtype'}; >+ my $borrower = >+ C4::Members::GetMember( borrowernumber => $borrowernumber ) >+ or return; >+ my $itemtype = >+ ( C4::Context->preference('item-level_itypes') ) >+ ? $biblio->{'itype'} >+ : $biblio->{'itemtype'}; > >- $datedue = (C4::Context->preference('RenewalPeriodBase') eq 'date_due') ? >- dt_from_string( $issuedata->{date_due} ) : >- DateTime->now( time_zone => C4::Context->tz()); >- $datedue = CalcDateDue($datedue, $itemtype, $issuedata->{'branchcode'}, $borrower, 'is a renewal'); >+ $datedue = >+ ( C4::Context->preference('RenewalPeriodBase') eq 'date_due' ) >+ ? dt_from_string( $issuedata->{date_due} ) >+ : DateTime->now( time_zone => C4::Context->tz() ); >+ $datedue = CalcDateDue( $datedue, $itemtype, $issuedata->{'branchcode'}, >+ $borrower, 'is a renewal' ); > } > > # Update the issues record to have the new due date, and a new count > # of how many times it has been renewed. > my $renews = $issuedata->{'renewals'} + 1; >- $sth = $dbh->prepare("UPDATE issues SET date_due = ?, renewals = ?, lastreneweddate = ? >+ $sth = $dbh->prepare( >+ "UPDATE issues SET date_due = ?, renewals = ?, lastreneweddate = ? > WHERE borrowernumber=? > AND itemnumber=?" > ); > >- $sth->execute( $datedue->strftime('%Y-%m-%d %H:%M'), $renews, $lastreneweddate, $borrowernumber, $itemnumber ); >+ $sth->execute( $datedue->strftime('%Y-%m-%d %H:%M'), >+ $renews, $lastreneweddate, $borrowernumber, $itemnumber ); > > # Update the renewal count on the item, and tell zebra to reindex > $renews = $biblio->{'renewals'} + 1; >- ModItem({ renewals => $renews, onloan => $datedue->strftime('%Y-%m-%d %H:%M')}, $biblio->{'biblionumber'}, $itemnumber); >+ ModItem( >+ { renewals => $renews, onloan => $datedue->strftime('%Y-%m-%d %H:%M') }, >+ $biblio->{'biblionumber'}, $itemnumber >+ ); > > # Charge a new rental fee, if applicable? > my ( $charge, $type ) = GetIssuingCharges( $itemnumber, $borrowernumber ); > if ( $charge > 0 ) { >- my $accountno = getnextacctno( $borrowernumber ); >- my $item = GetBiblioFromItemNumber($itemnumber); >+ my $accountno = getnextacctno($borrowernumber); >+ my $item = GetBiblioFromItemNumber($itemnumber); > my $manager_id = 0; >- $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; >+ $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; > $sth = $dbh->prepare( >- "INSERT INTO accountlines >+ "INSERT INTO accountlines > (date, borrowernumber, accountno, amount, manager_id, > description,accounttype, amountoutstanding, itemnumber) > VALUES (now(),?,?,?,?,?,?,?,?)" >@@ -2596,41 +2887,55 @@ sub AddRenewal { > } > > # Send a renewal slip according to checkout alert preferencei >- if ( C4::Context->preference('RenewalSendNotice') eq '1') { >- my $borrower = C4::Members::GetMemberDetails( $borrowernumber, 0 ); >- my $circulation_alert = 'C4::ItemCirculationAlertPreference'; >- my %conditions = ( >- branchcode => $branch, >- categorycode => $borrower->{categorycode}, >- item_type => $item->{itype}, >- notification => 'CHECKOUT', >- ); >- if ($circulation_alert->is_enabled_for(\%conditions)) { >- SendCirculationAlert({ >- type => 'RENEWAL', >- item => $item, >- borrower => $borrower, >- branch => $branch, >- }); >- } >+ if ( C4::Context->preference('RenewalSendNotice') eq '1' ) { >+ my $borrower = C4::Members::GetMemberDetails( $borrowernumber, 0 ); >+ my $circulation_alert = 'C4::ItemCirculationAlertPreference'; >+ my %conditions = ( >+ branchcode => $branch, >+ categorycode => $borrower->{categorycode}, >+ item_type => $item->{itype}, >+ notification => 'CHECKOUT', >+ ); >+ if ( $circulation_alert->is_enabled_for( \%conditions ) ) { >+ SendCirculationAlert( >+ { >+ type => 'RENEWAL', >+ item => $item, >+ borrower => $borrower, >+ branch => $branch, >+ } >+ ); >+ } > } > > # Remove any OVERDUES related debarment if the borrower has no overdues > my $borrower = C4::Members::GetMember( borrowernumber => $borrowernumber ); >- if ( $borrowernumber >- && $borrower->{'debarred'} >- && !HasOverdues( $borrowernumber ) >- && @{ GetDebarments({ borrowernumber => $borrowernumber, type => 'OVERDUES' }) } >- ) { >- DelUniqueDebarment({ borrowernumber => $borrowernumber, type => 'OVERDUES' }); >+ if ( >+ $borrowernumber >+ && $borrower->{'debarred'} >+ && !HasOverdues($borrowernumber) >+ && @{ >+ GetDebarments( >+ { borrowernumber => $borrowernumber, type => 'OVERDUES' } >+ ) >+ } >+ ) >+ { >+ DelUniqueDebarment( >+ { borrowernumber => $borrowernumber, type => 'OVERDUES' } ); > } > > # Log the renewal >- UpdateStats( $branch, 'renew', $charge, '', $itemnumber, $item->{itype}, $borrowernumber, undef, $item->{'ccode'}); >+ UpdateStats( >+ $branch, 'renew', $charge, '', >+ $itemnumber, $item->{itype}, $borrowernumber, undef, >+ $item->{'ccode'} >+ ); > return $datedue; > } > > sub GetRenewCount { >+ > # check renewal status > my ( $bornum, $itemno ) = @_; > my $dbh = C4::Context->dbh; >@@ -2638,8 +2943,8 @@ sub GetRenewCount { > my $renewsallowed = 0; > my $renewsleft = 0; > >- my $borrower = C4::Members::GetMember( borrowernumber => $bornum); >- my $item = GetItem($itemno); >+ my $borrower = C4::Members::GetMember( borrowernumber => $bornum ); >+ my $item = GetItem($itemno); > > # Look in the issues table for this item, lent to this borrower, > # and not yet returned. >@@ -2653,14 +2958,16 @@ sub GetRenewCount { > $sth->execute( $bornum, $itemno ); > my $data = $sth->fetchrow_hashref; > $renewcount = $data->{'renewals'} if $data->{'renewals'}; >+ > # $item and $borrower should be calculated >- my $branchcode = _GetCircControlBranch($item, $borrower); >- >- my $issuingrule = GetIssuingRule($borrower->{categorycode}, $item->{itype}, $branchcode); >- >+ my $branchcode = _GetCircControlBranch( $item, $borrower ); >+ >+ my $issuingrule = >+ GetIssuingRule( $borrower->{categorycode}, $item->{itype}, $branchcode ); >+ > $renewsallowed = $issuingrule->{'renewalsallowed'}; > $renewsleft = $renewsallowed - $renewcount; >- if($renewsleft < 0){ $renewsleft = 0; } >+ if ( $renewsleft < 0 ) { $renewsleft = 0; } > return ( $renewcount, $renewsallowed, $renewsleft ); > } > >@@ -2692,9 +2999,10 @@ sub GetIssuingCharges { > # Get the book's item type and rental charge (via its biblioitem). > my $charge_query = 'SELECT itemtypes.itemtype,rentalcharge FROM items > LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber'; >- $charge_query .= (C4::Context->preference('item-level_itypes')) >- ? ' LEFT JOIN itemtypes ON items.itype = itemtypes.itemtype' >- : ' LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype'; >+ $charge_query .= >+ ( C4::Context->preference('item-level_itypes') ) >+ ? ' LEFT JOIN itemtypes ON items.itype = itemtypes.itemtype' >+ : ' LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype'; > > $charge_query .= ' WHERE items.itemnumber =?'; > >@@ -2703,7 +3011,7 @@ sub GetIssuingCharges { > if ( my $item_data = $sth->fetchrow_hashref ) { > $item_type = $item_data->{itemtype}; > $charge = $item_data->{rentalcharge}; >- my $branch = C4::Branch::mybranch(); >+ my $branch = C4::Branch::mybranch(); > my $discount_query = q|SELECT rentaldiscount, > issuingrules.itemtype, issuingrules.branchcode > FROM borrowers >@@ -2713,10 +3021,13 @@ sub GetIssuingCharges { > AND (issuingrules.branchcode = ? OR issuingrules.branchcode = '*')|; > my $discount_sth = $dbh->prepare($discount_query); > $discount_sth->execute( $borrowernumber, $item_type, $branch ); >- my $discount_rules = $discount_sth->fetchall_arrayref({}); >- if (@{$discount_rules}) { >+ my $discount_rules = $discount_sth->fetchall_arrayref( {} ); >+ >+ if ( @{$discount_rules} ) { >+ > # We may have multiple rules so get the most specific >- my $discount = _get_discount_from_rule($discount_rules, $branch, $item_type); >+ my $discount = >+ _get_discount_from_rule( $discount_rules, $branch, $item_type ); > $charge = ( $charge * ( 100 - $discount ) ) / 100; > } > } >@@ -2726,37 +3037,46 @@ sub GetIssuingCharges { > > # Select most appropriate discount rule from those returned > sub _get_discount_from_rule { >- my ($rules_ref, $branch, $itemtype) = @_; >+ my ( $rules_ref, $branch, $itemtype ) = @_; > my $discount; > >- if (@{$rules_ref} == 1) { # only 1 applicable rule use it >+ if ( @{$rules_ref} == 1 ) { # only 1 applicable rule use it > $discount = $rules_ref->[0]->{rentaldiscount}; >- return (defined $discount) ? $discount : 0; >+ return ( defined $discount ) ? $discount : 0; > } >+ > # could have up to 4 does one match $branch and $itemtype >- my @d = grep { $_->{branchcode} eq $branch && $_->{itemtype} eq $itemtype } @{$rules_ref}; >+ my @d = grep { $_->{branchcode} eq $branch && $_->{itemtype} eq $itemtype } >+ @{$rules_ref}; > if (@d) { > $discount = $d[0]->{rentaldiscount}; >- return (defined $discount) ? $discount : 0; >+ return ( defined $discount ) ? $discount : 0; > } >+ > # do we have item type + all branches >- @d = grep { $_->{branchcode} eq q{*} && $_->{itemtype} eq $itemtype } @{$rules_ref}; >+ @d = grep { $_->{branchcode} eq q{*} && $_->{itemtype} eq $itemtype } >+ @{$rules_ref}; > if (@d) { > $discount = $d[0]->{rentaldiscount}; >- return (defined $discount) ? $discount : 0; >+ return ( defined $discount ) ? $discount : 0; > } >+ > # do we all item types + this branch >- @d = grep { $_->{branchcode} eq $branch && $_->{itemtype} eq q{*} } @{$rules_ref}; >+ @d = grep { $_->{branchcode} eq $branch && $_->{itemtype} eq q{*} } >+ @{$rules_ref}; > if (@d) { > $discount = $d[0]->{rentaldiscount}; >- return (defined $discount) ? $discount : 0; >+ return ( defined $discount ) ? $discount : 0; > } >+ > # so all and all (surely we wont get here) >- @d = grep { $_->{branchcode} eq q{*} && $_->{itemtype} eq q{*} } @{$rules_ref}; >+ @d = >+ grep { $_->{branchcode} eq q{*} && $_->{itemtype} eq q{*} } @{$rules_ref}; > if (@d) { > $discount = $d[0]->{rentaldiscount}; >- return (defined $discount) ? $discount : 0; >+ return ( defined $discount ) ? $discount : 0; > } >+ > # none of the above > return 0; > } >@@ -2769,11 +3089,11 @@ sub _get_discount_from_rule { > > sub AddIssuingCharge { > my ( $itemnumber, $borrowernumber, $charge ) = @_; >- my $dbh = C4::Context->dbh; >- my $nextaccntno = getnextacctno( $borrowernumber ); >- my $manager_id = 0; >+ my $dbh = C4::Context->dbh; >+ my $nextaccntno = getnextacctno($borrowernumber); >+ my $manager_id = 0; > $manager_id = C4::Context->userenv->{'number'} if C4::Context->userenv; >- my $query =" >+ my $query = " > INSERT INTO accountlines > (borrowernumber, itemnumber, accountno, > date, amount, description, accounttype, >@@ -2781,7 +3101,8 @@ sub AddIssuingCharge { > VALUES (?, ?, ?,now(), ?, 'Rental', 'Rent',?,?) > "; > my $sth = $dbh->prepare($query); >- $sth->execute( $borrowernumber, $itemnumber, $nextaccntno, $charge, $charge, $manager_id ); >+ $sth->execute( $borrowernumber, $itemnumber, $nextaccntno, $charge, >+ $charge, $manager_id ); > } > > =head2 GetTransfers >@@ -2847,8 +3168,8 @@ sub GetTransfersFromTo { > sub DeleteTransfer { > my ($itemnumber) = @_; > return unless $itemnumber; >- my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare( >+ my $dbh = C4::Context->dbh; >+ my $sth = $dbh->prepare( > "DELETE FROM branchtransfers > WHERE itemnumber=? > AND datearrived IS NULL " >@@ -2881,21 +3202,26 @@ sub AnonymiseIssueHistory { > AND borrowernumber IS NOT NULL > "; > >- # The default of 0 does not work due to foreign key constraints >- # The anonymisation will fail quietly if AnonymousPatron is not a valid entry >- my $anonymouspatron = (C4::Context->preference('AnonymousPatron')) ? C4::Context->preference('AnonymousPatron') : 0; >- my @bind_params = ($anonymouspatron, $date); >- if (defined $borrowernumber) { >- $query .= " AND borrowernumber = ?"; >- push @bind_params, $borrowernumber; >- } else { >- $query .= " AND (SELECT privacy FROM borrowers WHERE borrowers.borrowernumber=old_issues.borrowernumber) <> 0"; >+ # The default of 0 does not work due to foreign key constraints >+ # The anonymisation will fail quietly if AnonymousPatron is not a valid entry >+ my $anonymouspatron = >+ ( C4::Context->preference('AnonymousPatron') ) >+ ? C4::Context->preference('AnonymousPatron') >+ : 0; >+ my @bind_params = ( $anonymouspatron, $date ); >+ if ( defined $borrowernumber ) { >+ $query .= " AND borrowernumber = ?"; >+ push @bind_params, $borrowernumber; >+ } >+ else { >+ $query .= >+" AND (SELECT privacy FROM borrowers WHERE borrowers.borrowernumber=old_issues.borrowernumber) <> 0"; > } > my $sth = $dbh->prepare($query); > $sth->execute(@bind_params); > my $anonymisation_err = $dbh->err; >- my $rows_affected = $sth->rows; ### doublecheck row count return function >- return ($rows_affected, $anonymisation_err); >+ my $rows_affected = $sth->rows; ### doublecheck row count return function >+ return ( $rows_affected, $anonymisation_err ); > } > > =head2 SendCirculationAlert >@@ -2937,23 +3263,26 @@ B<Example>: > > sub SendCirculationAlert { > my ($opts) = @_; >- my ($type, $item, $borrower, $branch) = >- ($opts->{type}, $opts->{item}, $opts->{borrower}, $opts->{branch}); >+ my ( $type, $item, $borrower, $branch ) = >+ ( $opts->{type}, $opts->{item}, $opts->{borrower}, $opts->{branch} ); > my %message_name = ( > CHECKIN => 'Item_Check_in', > CHECKOUT => 'Item_Checkout', >- RENEWAL => 'Item_Checkout', >+ RENEWAL => 'Item_Checkout', > ); >- my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences({ >- borrowernumber => $borrower->{borrowernumber}, >- message_name => $message_name{$type}, >- }); >- my $issues_table = ( $type eq 'CHECKOUT' || $type eq 'RENEWAL' ) ? 'issues' : 'old_issues'; >- my $letter = C4::Letters::GetPreparedLetter ( >- module => 'circulation', >+ my $borrower_preferences = C4::Members::Messaging::GetMessagingPreferences( >+ { >+ borrowernumber => $borrower->{borrowernumber}, >+ message_name => $message_name{$type}, >+ } >+ ); >+ my $issues_table = >+ ( $type eq 'CHECKOUT' || $type eq 'RENEWAL' ) ? 'issues' : 'old_issues'; >+ my $letter = C4::Letters::GetPreparedLetter( >+ module => 'circulation', > letter_code => $type, >- branchcode => $branch, >- tables => { >+ branchcode => $branch, >+ tables => { > $issues_table => $item->{itemnumber}, > 'items' => $item->{itemnumber}, > 'biblio' => $item->{biblionumber}, >@@ -2964,14 +3293,18 @@ sub SendCirculationAlert { > ) or return; > > my @transports = keys %{ $borrower_preferences->{transports} }; >+ > # warn "no transports" unless @transports; > for (@transports) { >+ > # warn "transport: $_"; >- my $message = C4::Message->find_last_message($borrower, $type, $_); >- if (!$message) { >+ my $message = C4::Message->find_last_message( $borrower, $type, $_ ); >+ if ( !$message ) { >+ > #warn "create new message"; >- C4::Message->enqueue($letter, $borrower, $_); >- } else { >+ C4::Message->enqueue( $letter, $borrower, $_ ); >+ } >+ else { > #warn "append to old message"; > $message->append($letter); > $message->update; >@@ -2990,20 +3323,21 @@ This function validate the line of brachtransfer but with the wrong destination > =cut > > sub updateWrongTransfer { >- my ( $itemNumber,$waitingAtLibrary,$FromLibrary ) = @_; >+ my ( $itemNumber, $waitingAtLibrary, $FromLibrary ) = @_; > my $dbh = C4::Context->dbh; >-# first step validate the actual line of transfert . >+ >+ # first step validate the actual line of transfert . > my $sth = >- $dbh->prepare( >- "update branchtransfers set datearrived = now(),tobranch=?,comments='wrongtransfer' where itemnumber= ? AND datearrived IS NULL" >- ); >- $sth->execute($FromLibrary,$itemNumber); >+ $dbh->prepare( >+"update branchtransfers set datearrived = now(),tobranch=?,comments='wrongtransfer' where itemnumber= ? AND datearrived IS NULL" >+ ); >+ $sth->execute( $FromLibrary, $itemNumber ); > >-# second step create a new line of branchtransfer to the right location . >- ModItemTransfer($itemNumber, $FromLibrary, $waitingAtLibrary); >+ # second step create a new line of branchtransfer to the right location . >+ ModItemTransfer( $itemNumber, $FromLibrary, $waitingAtLibrary ); > >-#third step changing holdingbranch of item >- UpdateHoldingbranch($FromLibrary,$itemNumber); >+ #third step changing holdingbranch of item >+ UpdateHoldingbranch( $FromLibrary, $itemNumber ); > } > > =head2 UpdateHoldingbranch >@@ -3015,8 +3349,8 @@ Simple methode for updating hodlingbranch in items BDD line > =cut > > sub UpdateHoldingbranch { >- my ( $branch,$itemnumber ) = @_; >- ModItem({ holdingbranch => $branch }, undef, $itemnumber); >+ my ( $branch, $itemnumber ) = @_; >+ ModItem( { holdingbranch => $branch }, undef, $itemnumber ); > } > > =head2 CalcDateDue >@@ -3040,47 +3374,54 @@ sub CalcDateDue { > > # loanlength now a href > my $loanlength = >- GetLoanLength( $borrower->{'categorycode'}, $itemtype, $branch ); >+ GetLoanLength( $borrower->{'categorycode'}, $itemtype, $branch ); > >- my $length_key = ( $isrenewal and defined $loanlength->{renewalperiod} ) >- ? qq{renewalperiod} >- : qq{issuelength}; >+ my $length_key = >+ ( $isrenewal and defined $loanlength->{renewalperiod} ) >+ ? qq{renewalperiod} >+ : qq{issuelength}; > > my $datedue; >- if ( $startdate ) { >- if (ref $startdate ne 'DateTime' ) { >+ if ($startdate) { >+ if ( ref $startdate ne 'DateTime' ) { > $datedue = dt_from_string($datedue); >- } else { >+ } >+ else { > $datedue = $startdate->clone; > } >- } else { >+ } >+ else { > $datedue = > DateTime->now( time_zone => C4::Context->tz() ) > ->truncate( to => 'minute' ); > } > >- > # calculate the datedue as normal > if ( C4::Context->preference('useDaysMode') eq 'Days' ) > { # ignoring calendar > if ( $loanlength->{lengthunit} eq 'hours' ) { > $datedue->add( hours => $loanlength->{$length_key} ); >- } else { # days >+ } >+ else { # days > $datedue->add( days => $loanlength->{$length_key} ); > $datedue->set_hour(23); > $datedue->set_minute(59); > } >- } else { >+ } >+ else { > my $dur; >- if ($loanlength->{lengthunit} eq 'hours') { >- $dur = DateTime::Duration->new( hours => $loanlength->{$length_key}); >+ if ( $loanlength->{lengthunit} eq 'hours' ) { >+ $dur = >+ DateTime::Duration->new( hours => $loanlength->{$length_key} ); > } >- else { # days >- $dur = DateTime::Duration->new( days => $loanlength->{$length_key}); >+ else { # days >+ $dur = >+ DateTime::Duration->new( days => $loanlength->{$length_key} ); > } > my $calendar = Koha::Calendar->new( branchcode => $branch ); >- $datedue = $calendar->addDate( $datedue, $dur, $loanlength->{lengthunit} ); >- if ($loanlength->{lengthunit} eq 'days') { >+ $datedue = >+ $calendar->addDate( $datedue, $dur, $loanlength->{lengthunit} ); >+ if ( $loanlength->{lengthunit} eq 'days' ) { > $datedue->set_hour(23); > $datedue->set_minute(59); > } >@@ -3109,7 +3450,7 @@ sub CalcDateDue { > # if ReturnBeforeExpiry ON the datedue can't be after borrower expirydate > if ( C4::Context->preference('ReturnBeforeExpiry') ) { > my $expiry_dt = dt_from_string( $borrower->{dateexpiry}, 'iso' ); >- $expiry_dt->set( hour => 23, minute => 59); >+ $expiry_dt->set( hour => 23, minute => 59 ); > if ( DateTime->compare( $datedue, $expiry_dt ) == 1 ) { > $datedue = $expiry_dt->clone; > } >@@ -3118,7 +3459,6 @@ sub CalcDateDue { > return $datedue; > } > >- > =head2 CheckRepeatableHolidays > > $countrepeatable = CheckRepeatableHoliday($itemnumber,$week_day,$branchcode); >@@ -3131,20 +3471,19 @@ C<$branchcode> = localisation of issue > > =cut > >-sub CheckRepeatableHolidays{ >-my($itemnumber,$week_day,$branchcode)=@_; >-my $dbh = C4::Context->dbh; >-my $query = qq|SELECT count(*) >+sub CheckRepeatableHolidays { >+ my ( $itemnumber, $week_day, $branchcode ) = @_; >+ my $dbh = C4::Context->dbh; >+ my $query = qq|SELECT count(*) > FROM repeatable_holidays > WHERE branchcode=? > AND weekday=?|; >-my $sth = $dbh->prepare($query); >-$sth->execute($branchcode,$week_day); >-my $result=$sth->fetchrow; >-return $result; >+ my $sth = $dbh->prepare($query); >+ $sth->execute( $branchcode, $week_day ); >+ my $result = $sth->fetchrow; >+ return $result; > } > >- > =head2 CheckSpecialHolidays > > $countspecial = CheckSpecialHolidays($years,$month,$day,$itemnumber,$branchcode); >@@ -3159,20 +3498,20 @@ C<$branchcode> = localisation of issue > > =cut > >-sub CheckSpecialHolidays{ >-my ($years,$month,$day,$itemnumber,$branchcode) = @_; >-my $dbh = C4::Context->dbh; >-my $query=qq|SELECT count(*) >+sub CheckSpecialHolidays { >+ my ( $years, $month, $day, $itemnumber, $branchcode ) = @_; >+ my $dbh = C4::Context->dbh; >+ my $query = qq|SELECT count(*) > FROM `special_holidays` > WHERE year=? > AND month=? > AND day=? > AND branchcode=? > |; >-my $sth = $dbh->prepare($query); >-$sth->execute($years,$month,$day,$branchcode); >-my $countspecial=$sth->fetchrow ; >-return $countspecial; >+ my $sth = $dbh->prepare($query); >+ $sth->execute( $years, $month, $day, $branchcode ); >+ my $countspecial = $sth->fetchrow; >+ return $countspecial; > } > > =head2 CheckRepeatableSpecialHolidays >@@ -3188,37 +3527,34 @@ C<$branchcode> = localisation of issue > > =cut > >-sub CheckRepeatableSpecialHolidays{ >-my ($month,$day,$itemnumber,$branchcode) = @_; >-my $dbh = C4::Context->dbh; >-my $query=qq|SELECT count(*) >+sub CheckRepeatableSpecialHolidays { >+ my ( $month, $day, $itemnumber, $branchcode ) = @_; >+ my $dbh = C4::Context->dbh; >+ my $query = qq|SELECT count(*) > FROM `repeatable_holidays` > WHERE month=? > AND day=? > AND branchcode=? > |; >-my $sth = $dbh->prepare($query); >-$sth->execute($month,$day,$branchcode); >-my $countspecial=$sth->fetchrow ; >-return $countspecial; >+ my $sth = $dbh->prepare($query); >+ $sth->execute( $month, $day, $branchcode ); >+ my $countspecial = $sth->fetchrow; >+ return $countspecial; > } > >- >- >-sub CheckValidBarcode{ >-my ($barcode) = @_; >-my $dbh = C4::Context->dbh; >-my $query=qq|SELECT count(*) >+sub CheckValidBarcode { >+ my ($barcode) = @_; >+ my $dbh = C4::Context->dbh; >+ my $query = qq|SELECT count(*) > FROM items > WHERE barcode=? > |; >-my $sth = $dbh->prepare($query); >-$sth->execute($barcode); >-my $exist=$sth->fetchrow ; >-return $exist; >+ my $sth = $dbh->prepare($query); >+ $sth->execute($barcode); >+ my $exist = $sth->fetchrow; >+ return $exist; > } > >- > =head2 CanItemBeTransferred > > A convenience function to easily check item transfer limits. >@@ -3248,57 +3584,62 @@ sub CanItemBeTransferred { > #When we check for BranchTransferLimit global settings centrally, it makes > # using this functionality much easier. > unless ( C4::Context->preference("UseBranchTransferLimits") == 1 ) { >- return 1; >+ return 1; > } > > #Init parameter variables > my ( $toBranch, $fromBranch, $item, $biblioitem ) = @_; > > #Check the $fromBranch and set the DEFAULT value >- $fromBranch = $item->{holdingbranch} if ! defined $fromBranch; >+ $fromBranch = $item->{holdingbranch} if !defined $fromBranch; > >- if ( $toBranch eq $fromBranch ) { return 1; } ## Short circuit for speed. >+ if ( $toBranch eq $fromBranch ) { return 1; } ## Short circuit for speed. > >- #This is the CCode or itemtype value used to find the correct transfer rule for this item. >+#This is the CCode or itemtype value used to find the correct transfer rule for this item. > my $code; > > ## Figure out the $code! > ## First we need to figure out are we using CCODE or itemtype, this limits do we need $biblioitem or not. > ## Since $biblioitem can be optional, we cannot count that it is defined. > if ( C4::Context->preference("BranchTransferLimitsType") eq 'itemtype' ) { >- if (C4::Context->preference("item-level_itypes") && defined $item->{'itype'}) { >- $code = $item->{'itype'}; #Easiest way to get the $code is from the item. >- } >- elsif (defined $biblioitem->{itemtype}) { >- $code = $biblioitem->{itemtype} >- } >- #If code cannot be resolved from $item or $biblioitem, we need to escalate to the DB >- else { >- $biblioitem = C4::Biblio::GetBiblioFromItemNumber( $item->{itemnumber} ); >- $code = $biblioitem->{itemtype} >- } >+ if ( C4::Context->preference("item-level_itypes") >+ && defined $item->{'itype'} ) >+ { >+ $code = >+ $item->{'itype'}; #Easiest way to get the $code is from the item. >+ } >+ elsif ( defined $biblioitem->{itemtype} ) { >+ $code = $biblioitem->{itemtype}; >+ } > >- } else { >- my $limitType = C4::Context->preference("BranchTransferLimitsType"); >- if (defined $item->{ $limitType }) { >- $code = $item->{ $limitType }; >- } >- else { >- #collection code (ccode) is not present in the Biblio, so no point looking there. >- # If the Item doesn't have a itemtype, then give up and let the transfer pass. >- } >+#If code cannot be resolved from $item or $biblioitem, we need to escalate to the DB >+ else { >+ $biblioitem = >+ C4::Biblio::GetBiblioFromItemNumber( $item->{itemnumber} ); >+ $code = $biblioitem->{itemtype}; >+ } >+ >+ } >+ else { >+ my $limitType = C4::Context->preference("BranchTransferLimitsType"); >+ if ( defined $item->{$limitType} ) { >+ $code = $item->{$limitType}; >+ } >+ else { >+#collection code (ccode) is not present in the Biblio, so no point looking there. >+# If the Item doesn't have a itemtype, then give up and let the transfer pass. >+ } > } > ## Phew we finally got the $code, now it's time to rumble! > >- if (! IsBranchTransferAllowed($toBranch, $fromBranch, $code)) { >- return 0, "$fromBranch->$toBranch->$code"; >+ if ( !IsBranchTransferAllowed( $toBranch, $fromBranch, $code ) ) { >+ return 0, "$fromBranch->$toBranch->$code"; > } > else { >- return 1; >+ return 1; > } > } > >- > =head2 IsBranchTransferAllowed > > $allowed = IsBranchTransferAllowed( $toBranch, $fromBranch, $code ); >@@ -3310,22 +3651,25 @@ Code is either an itemtype or collection doe depending on the pref BranchTransfe > sub IsBranchTransferAllowed { > my ( $toBranch, $fromBranch, $code ) = @_; > >- if ( $toBranch eq $fromBranch ) { return 1; } ## Short circuit for speed. >- >+ if ( $toBranch eq $fromBranch ) { return 1; } ## Short circuit for speed. >+ > my $limitType = C4::Context->preference("BranchTransferLimitsType"); >- my $dbh = C4::Context->dbh; >- >- my $sth = $dbh->prepare("SELECT * FROM branch_transfer_limits WHERE toBranch = ? AND fromBranch = ? AND $limitType = ?"); >+ my $dbh = C4::Context->dbh; >+ >+ my $sth = $dbh->prepare( >+"SELECT * FROM branch_transfer_limits WHERE toBranch = ? AND fromBranch = ? AND $limitType = ?" >+ ); > $sth->execute( $toBranch, $fromBranch, $code ); > my $limit = $sth->fetchrow_hashref(); >- >+ > ## If a row is found, then that combination is not allowed, if no matching row is found, then the combination *is allowed* > if ( $limit->{'limitId'} ) { > return 0; >- } else { >+ } >+ else { > return 1; > } >-} >+} > > =head2 CreateBranchTransferLimit > >@@ -3336,14 +3680,16 @@ $code is either itemtype or collection code depending on what the pref BranchTra > =cut > > sub CreateBranchTransferLimit { >- my ( $toBranch, $fromBranch, $code ) = @_; >- return unless defined($toBranch) && defined($fromBranch); >- my $limitType = C4::Context->preference("BranchTransferLimitsType"); >- >- my $dbh = C4::Context->dbh; >- >- my $sth = $dbh->prepare("INSERT INTO branch_transfer_limits ( $limitType, toBranch, fromBranch ) VALUES ( ?, ?, ? )"); >- return $sth->execute( $code, $toBranch, $fromBranch ); >+ my ( $toBranch, $fromBranch, $code ) = @_; >+ return unless defined($toBranch) && defined($fromBranch); >+ my $limitType = C4::Context->preference("BranchTransferLimitsType"); >+ >+ my $dbh = C4::Context->dbh; >+ >+ my $sth = $dbh->prepare( >+"INSERT INTO branch_transfer_limits ( $limitType, toBranch, fromBranch ) VALUES ( ?, ?, ? )" >+ ); >+ return $sth->execute( $code, $toBranch, $fromBranch ); > } > > =head2 DeleteBranchTransferLimits >@@ -3359,60 +3705,82 @@ no arguments are supplied. > sub DeleteBranchTransferLimits { > my $branch = shift; > return unless defined $branch; >- my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare("DELETE FROM branch_transfer_limits WHERE fromBranch = ?"); >+ my $dbh = C4::Context->dbh; >+ my $sth = >+ $dbh->prepare("DELETE FROM branch_transfer_limits WHERE fromBranch = ?"); > return $sth->execute($branch); > } > >-sub ReturnLostItem{ >+sub ReturnLostItem { > my ( $borrowernumber, $itemnum ) = @_; > > MarkIssueReturned( $borrowernumber, $itemnum ); >- my $borrower = C4::Members::GetMember( 'borrowernumber'=>$borrowernumber ); >- my $item = C4::Items::GetItem( $itemnum ); >- my $old_note = ($item->{'paidfor'} && ($item->{'paidfor'} ne q{})) ? $item->{'paidfor'}.' / ' : q{}; >+ my $borrower = >+ C4::Members::GetMember( 'borrowernumber' => $borrowernumber ); >+ my $item = C4::Items::GetItem($itemnum); >+ my $old_note = >+ ( $item->{'paidfor'} && ( $item->{'paidfor'} ne q{} ) ) >+ ? $item->{'paidfor'} . ' / ' >+ : q{}; > my @datearr = localtime(time); >- my $date = ( 1900 + $datearr[5] ) . "-" . ( $datearr[4] + 1 ) . "-" . $datearr[3]; >- my $bor = "$borrower->{'firstname'} $borrower->{'surname'} $borrower->{'cardnumber'}"; >- ModItem({ paidfor => $old_note."Paid for by $bor $date" }, undef, $itemnum); >+ my $date = >+ ( 1900 + $datearr[5] ) . "-" . ( $datearr[4] + 1 ) . "-" . $datearr[3]; >+ my $bor = >+"$borrower->{'firstname'} $borrower->{'surname'} $borrower->{'cardnumber'}"; >+ ModItem( { paidfor => $old_note . "Paid for by $bor $date" }, >+ undef, $itemnum ); > } > >- >-sub LostItem{ >- my ($itemnumber, $mark_returned) = @_; >+sub LostItem { >+ my ( $itemnumber, $mark_returned ) = @_; > > my $dbh = C4::Context->dbh(); >- my $sth=$dbh->prepare("SELECT issues.*,items.*,biblio.title >+ my $sth = $dbh->prepare( >+ "SELECT issues.*,items.*,biblio.title > FROM issues > JOIN items USING (itemnumber) > JOIN biblio USING (biblionumber) >- WHERE issues.itemnumber=?"); >+ WHERE issues.itemnumber=?" >+ ); > $sth->execute($itemnumber); >- my $issues=$sth->fetchrow_hashref(); >+ my $issues = $sth->fetchrow_hashref(); > > # If a borrower lost the item, add a replacement cost to the their record >- if ( my $borrowernumber = $issues->{borrowernumber} ){ >- my $borrower = C4::Members::GetMemberDetails( $borrowernumber ); >+ if ( my $borrowernumber = $issues->{borrowernumber} ) { >+ my $borrower = C4::Members::GetMemberDetails($borrowernumber); >+ >+ if ( C4::Context->preference('WhenLostForgiveFine') ) { >+ my $fix = _FixOverduesOnReturn( $borrowernumber, $itemnumber, 1, 0 ) >+ ; # 1, 0 = exemptfine, no-dropbox >+ defined($fix) >+ or warn >+ "_FixOverduesOnReturn($borrowernumber, $itemnumber...) failed!" >+ ; # zero is OK, check defined >+ } >+ if ( C4::Context->preference('WhenLostChargeReplacementFee') ) { >+ C4::Accounts::chargelostitem( >+ $borrowernumber, $itemnumber, >+ $issues->{'replacementprice'}, >+ "Lost Item $issues->{'title'} $issues->{'barcode'}" >+ ); > >- if (C4::Context->preference('WhenLostForgiveFine')){ >- my $fix = _FixOverduesOnReturn($borrowernumber, $itemnumber, 1, 0); # 1, 0 = exemptfine, no-dropbox >- defined($fix) or warn "_FixOverduesOnReturn($borrowernumber, $itemnumber...) failed!"; # zero is OK, check defined >- } >- if (C4::Context->preference('WhenLostChargeReplacementFee')){ >- C4::Accounts::chargelostitem($borrowernumber, $itemnumber, $issues->{'replacementprice'}, "Lost Item $issues->{'title'} $issues->{'barcode'}"); >- #FIXME : Should probably have a way to distinguish this from an item that really was returned. >- #warn " $issues->{'borrowernumber'} / $itemnumber "; >+#FIXME : Should probably have a way to distinguish this from an item that really was returned. >+#warn " $issues->{'borrowernumber'} / $itemnumber "; > } > >- MarkIssueReturned($borrowernumber,$itemnumber,undef,undef,$borrower->{'privacy'}) if $mark_returned; >+ MarkIssueReturned( $borrowernumber, $itemnumber, undef, undef, >+ $borrower->{'privacy'} ) >+ if $mark_returned; > } > } > > sub GetOfflineOperations { > my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare("SELECT * FROM pending_offline_operations WHERE branchcode=? ORDER BY timestamp"); >- $sth->execute(C4::Context->userenv->{'branch'}); >- my $results = $sth->fetchall_arrayref({}); >+ my $sth = $dbh->prepare( >+"SELECT * FROM pending_offline_operations WHERE branchcode=? ORDER BY timestamp" >+ ); >+ $sth->execute( C4::Context->userenv->{'branch'} ); >+ my $results = $sth->fetchall_arrayref( {} ); > return $results; > } > >@@ -3420,23 +3788,33 @@ sub GetOfflineOperation { > my $operationid = shift; > return unless $operationid; > my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare("SELECT * FROM pending_offline_operations WHERE operationid=?"); >- $sth->execute( $operationid ); >+ my $sth = $dbh->prepare( >+ "SELECT * FROM pending_offline_operations WHERE operationid=?"); >+ $sth->execute($operationid); > return $sth->fetchrow_hashref; > } > > sub AddOfflineOperation { >- my ( $userid, $branchcode, $timestamp, $action, $barcode, $cardnumber, $amount ) = @_; >+ my ( >+ $userid, $branchcode, $timestamp, $action, >+ $barcode, $cardnumber, $amount >+ ) = @_; > my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare("INSERT INTO pending_offline_operations (userid, branchcode, timestamp, action, barcode, cardnumber, amount) VALUES(?,?,?,?,?,?,?)"); >- $sth->execute( $userid, $branchcode, $timestamp, $action, $barcode, $cardnumber, $amount ); >+ my $sth = $dbh->prepare( >+"INSERT INTO pending_offline_operations (userid, branchcode, timestamp, action, barcode, cardnumber, amount) VALUES(?,?,?,?,?,?,?)" >+ ); >+ $sth->execute( >+ $userid, $branchcode, $timestamp, $action, >+ $barcode, $cardnumber, $amount >+ ); > return "Added."; > } > > sub DeleteOfflineOperation { > my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare("DELETE FROM pending_offline_operations WHERE operationid=?"); >- $sth->execute( shift ); >+ my $sth = $dbh->prepare( >+ "DELETE FROM pending_offline_operations WHERE operationid=?"); >+ $sth->execute(shift); > return "Deleted."; > } > >@@ -3445,14 +3823,17 @@ sub ProcessOfflineOperation { > > my $report; > if ( $operation->{action} eq 'return' ) { >- $report = ProcessOfflineReturn( $operation ); >- } elsif ( $operation->{action} eq 'issue' ) { >- $report = ProcessOfflineIssue( $operation ); >- } elsif ( $operation->{action} eq 'payment' ) { >- $report = ProcessOfflinePayment( $operation ); >+ $report = ProcessOfflineReturn($operation); >+ } >+ elsif ( $operation->{action} eq 'issue' ) { >+ $report = ProcessOfflineIssue($operation); >+ } >+ elsif ( $operation->{action} eq 'payment' ) { >+ $report = ProcessOfflinePayment($operation); > } > >- DeleteOfflineOperation( $operation->{operationid} ) if $operation->{operationid}; >+ DeleteOfflineOperation( $operation->{operationid} ) >+ if $operation->{operationid}; > > return $report; > } >@@ -3460,27 +3841,25 @@ sub ProcessOfflineOperation { > sub ProcessOfflineReturn { > my $operation = shift; > >- my $itemnumber = C4::Items::GetItemnumberFromBarcode( $operation->{barcode} ); >+ my $itemnumber = >+ C4::Items::GetItemnumberFromBarcode( $operation->{barcode} ); > >- if ( $itemnumber ) { >- my $issue = GetOpenIssue( $itemnumber ); >- if ( $issue ) { >+ if ($itemnumber) { >+ my $issue = GetOpenIssue($itemnumber); >+ if ($issue) { > MarkIssueReturned( > $issue->{borrowernumber}, >- $itemnumber, >- undef, >- $operation->{timestamp}, >- ); >- ModItem( >- { renewals => 0, onloan => undef }, >- $issue->{'biblionumber'}, >- $itemnumber >+ $itemnumber, undef, $operation->{timestamp}, > ); >+ ModItem( { renewals => 0, onloan => undef }, >+ $issue->{'biblionumber'}, $itemnumber ); > return "Success."; >- } else { >+ } >+ else { > return "Item not issued."; > } >- } else { >+ } >+ else { > return "Item not found."; > } > } >@@ -3488,33 +3867,31 @@ sub ProcessOfflineReturn { > sub ProcessOfflineIssue { > my $operation = shift; > >- my $borrower = C4::Members::GetMemberDetails( undef, $operation->{cardnumber} ); # Get borrower from operation cardnumber >+ my $borrower = >+ C4::Members::GetMemberDetails( undef, $operation->{cardnumber} ) >+ ; # Get borrower from operation cardnumber > > if ( $borrower->{borrowernumber} ) { >- my $itemnumber = C4::Items::GetItemnumberFromBarcode( $operation->{barcode} ); >+ my $itemnumber = >+ C4::Items::GetItemnumberFromBarcode( $operation->{barcode} ); > unless ($itemnumber) { > return "Barcode not found."; > } >- my $issue = GetOpenIssue( $itemnumber ); >+ my $issue = GetOpenIssue($itemnumber); > >- if ( $issue and ( $issue->{borrowernumber} ne $borrower->{borrowernumber} ) ) { # Item already issued to another borrower, mark it returned >+ if ( $issue >+ and ( $issue->{borrowernumber} ne $borrower->{borrowernumber} ) ) >+ { # Item already issued to another borrower, mark it returned > MarkIssueReturned( > $issue->{borrowernumber}, >- $itemnumber, >- undef, >- $operation->{timestamp}, >+ $itemnumber, undef, $operation->{timestamp}, > ); > } >- AddIssue( >- $borrower, >- $operation->{'barcode'}, >- undef, >- 1, >- $operation->{timestamp}, >- undef, >- ); >+ AddIssue( $borrower, $operation->{'barcode'}, >+ undef, 1, $operation->{timestamp}, undef, ); > return "Success."; >- } else { >+ } >+ else { > return "Borrower not found."; > } > } >@@ -3522,15 +3899,16 @@ sub ProcessOfflineIssue { > sub ProcessOfflinePayment { > my $operation = shift; > >- my $borrower = C4::Members::GetMemberDetails( undef, $operation->{cardnumber} ); # Get borrower from operation cardnumber >+ my $borrower = >+ C4::Members::GetMemberDetails( undef, $operation->{cardnumber} ) >+ ; # Get borrower from operation cardnumber > my $amount = $operation->{amount}; > > recordpayment( $borrower->{borrowernumber}, $amount ); > >- return "Success." >+ return "Success."; > } > >- > =head2 TransferSlip > > TransferSlip($user_branch, $itemnumber, $to_branch) >@@ -3540,21 +3918,21 @@ sub ProcessOfflinePayment { > =cut > > sub TransferSlip { >- my ($branch, $itemnumber, $to_branch) = @_; >+ my ( $branch, $itemnumber, $to_branch ) = @_; > >- my $item = GetItem( $itemnumber ) >+ my $item = GetItem($itemnumber) > or return; > > my $pulldate = C4::Dates->new(); > >- return C4::Letters::GetPreparedLetter ( >- module => 'circulation', >+ return C4::Letters::GetPreparedLetter( >+ module => 'circulation', > letter_code => 'TRANSFERSLIP', >- branchcode => $branch, >- tables => { >- 'branches' => $to_branch, >- 'biblio' => $item->{biblionumber}, >- 'items' => $item, >+ branchcode => $branch, >+ tables => { >+ 'branches' => $to_branch, >+ 'biblio' => $item->{biblionumber}, >+ 'items' => $item, > }, > ); > } >@@ -3568,12 +3946,14 @@ sub TransferSlip { > =cut > > sub CheckIfIssuedToPatron { >- my ($borrowernumber, $biblionumber) = @_; >+ my ( $borrowernumber, $biblionumber ) = @_; > > my $items = GetItemsByBiblioitemnumber($biblionumber); > >- foreach my $item (@{$items}) { >- return 1 if ($item->{borrowernumber} && $item->{borrowernumber} eq $borrowernumber); >+ foreach my $item ( @{$items} ) { >+ return 1 >+ if ( $item->{borrowernumber} >+ && $item->{borrowernumber} eq $borrowernumber ); > } > > return; >@@ -3589,12 +3969,14 @@ sub CheckIfIssuedToPatron { > > sub IsItemIssued { > my $itemnumber = shift; >- my $dbh = C4::Context->dbh; >- my $sth = $dbh->prepare(q{ >+ my $dbh = C4::Context->dbh; >+ my $sth = $dbh->prepare( >+ q{ > SELECT COUNT(*) > FROM issues > WHERE itemnumber = ? >- }); >+ } >+ ); > $sth->execute($itemnumber); > return $sth->fetchrow; > } >diff --git a/koha-tmpl/opac-tmpl/prog/en/modules/opac-reserve.tt b/koha-tmpl/opac-tmpl/prog/en/modules/opac-reserve.tt >index 671e1f9..20fd4ae 100644 >--- a/koha-tmpl/opac-tmpl/prog/en/modules/opac-reserve.tt >+++ b/koha-tmpl/opac-tmpl/prog/en/modules/opac-reserve.tt >@@ -5,6 +5,7 @@ > <script type="text/javascript"> > // <![CDATA[ > var MSG_NO_COPY_SELECTED = _("Expecting a specific copy selection."); >+ var MSG_NO_TRANSFERRABLE_ITEMS = _("No item can be transferred to your pickup location. Please try another pickup location for "); > var ForceHoldNotesReasons=new Array( > _("This title consists of multiple volumes/parts. Please indicate which part you need. Clicking on specific copy information may be helpful."), > "*** Add a new reason above this line ***" ); // NOTE: Do not renumber reasons; this will affect use of existing ones. >@@ -21,16 +22,31 @@ > $(document).ready(function() { > $('#hold-request-form').preventDoubleFormSubmit(); > >+ $("#hold-request-form").find("select[name='branch']").change( function() { >+ var newSelection = $(this).val(); >+ >+ //Make sure that when changing the pickup location by resubmitting the form, >+ // user doesn't accidentally confirm his reservations. >+ var place_reserveInput = $("#hold-request-form").find('[name="place_reserve"]'); >+ place_reserveInput.attr("value", 0); >+ >+ //Make sure the pickup location is changed to the first select as well. >+ // The branch selection uses only the first given pickuplocations branch value. >+ $("#hold-request-form").find("select[name='branch']").val(newSelection); >+ >+ $("#hold-request-form").submit(); >+ }); >+ > var copiesRowId = null; > var wasSpecific = false; > var lastCopiesRowId = null; >- $(".checkitem").parent().click(function(e){ >- if(e.target.tagName.toLowerCase() == 'td'){ >+ $(".checkitem").parent().click(function(e){ >+ if(e.target.tagName.toLowerCase() == 'td'){ > $(this).find("input.checkitem").each( function() { > $(this).attr('checked', !$(this).attr('checked')); >- }); >- } >- }); >+ }); >+ } >+ }); > // Hides all 'specific copy' table rows on load. > $(".copiesrow").hide(); > >@@ -138,6 +154,21 @@ > return false; > } > >+ //Check for each biblio if there are no available Items that can be transferred to the pickup location, >+ // fail the hold request and alert the user. >+ var anotherPickupLocationSuggesters = $('#hold-request-form').find('div[id^="suggestAnotherPickupLocation_"]'); >+ if ( $(anotherPickupLocationSuggesters).size() > 0 ) { >+ anotherPickupLocationSuggesters.each( function() { >+ //Extract the biblionumber from the id and fetch the Biblio title >+ var idString = $(this).attr('id'); >+ var bibnumber = idString.replace('suggestAnotherPickupLocation_', ''); >+ var title = $('#title_'+bibnumber).text(); >+ >+ alert(MSG_NO_TRANSFERRABLE_ITEMS + title); >+ }); >+ return false; >+ } >+ > // Find the items with the 'Hold' box checked > var badBib = null; > $(".confirmjs:checked").each(function() { >@@ -189,7 +220,6 @@ > > > >- > [% FOREACH bibitemloo IN bibitemloop %] > [% IF ( bibitemloo.holdable ) %] > // http://jqueryui.com/demos/datepicker/#date-range >@@ -220,7 +250,7 @@ > <div id="doc3" class="yui-t7"> > <div id="bd"> > [% INCLUDE 'masthead.inc' %] >- <div id="yui-g"> >+ <div id="yui-g"> > <div id="holds" class="container"> > [% IF ( message ) %] > [% IF ( GNA ) %] >@@ -273,25 +303,26 @@ > [% IF ( none_available ) %] > <div id="none_available" class="dialog alert"><strong>Sorry</strong>, none of these items can be placed on hold. > </div> >- [% END %] >+ [% END %] > [% END %]<!-- NAME="message" --> > >- [% UNLESS ( message ) %][% UNLESS ( none_available ) %]<h3>Confirm holds for: >- [% FOREACH USER_INF IN USER_INFO %] >- [% USER_INF.firstname %] [% USER_INF.surname %] ([% USER_INF.cardnumber %]) >- [% END %] >- </h3>[% END %] >- [% IF (RESERVE_CHARGE) %] >- <div class="dialog alert" id="reserve_fee"> >- There is a charge of [% RESERVE_CHARGE %] for placing this hold >- </div> >- [% END %] >+ [% UNLESS ( message ) %][% IF ( 1 ) %] >+ <h3>Confirm holds for: >+ [% FOREACH USER_INF IN USER_INFO %] >+ [% USER_INF.firstname %] [% USER_INF.surname %] ([% USER_INF.cardnumber %]) >+ [% END %] >+ </h3>[% END %] >+ [% IF (RESERVE_CHARGE) %] >+ <div class="dialog alert" id="reserve_fee"> >+ There is a charge of [% RESERVE_CHARGE %] for placing this hold >+ </div> >+ [% END %] > > <form action="/cgi-bin/koha/opac-reserve.pl" method="post" id="hold-request-form"> > <input type="hidden" name="place_reserve" value="1"/> > >- <!-- These values are set dynamically by js --> >- <input type="hidden" name="biblionumbers" id="biblionumbers"/> >+ <!-- These values are set dynamically by js. Biblionumbers is needed for the page reload when changing pickup branch --> >+ <input type="hidden" name="biblionumbers" id="biblionumbers" value="[% biblionumbers %]"/> > <input type="hidden" name="selecteditems" id="selections"/> > <div id="bigloop"> > >@@ -314,7 +345,7 @@ > [% ELSE %] > [% END %] > >- <a class="title" href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% bibitemloo.biblionumber %]">[% bibitemloo.title |html %][% IF ( bibitemloo.subtitle ) %] [% FOREACH subtitl IN bibitemloo.subtitle %][% subtitl.subfield %][% END %][% END %]</a> >+ <a class="title" id="title_[% bibitemloo.biblionumber %]" href="/cgi-bin/koha/opac-detail.pl?biblionumber=[% bibitemloo.biblionumber %]">[% bibitemloo.title |html %][% IF ( bibitemloo.subtitle ) %] [% FOREACH subtitl IN bibitemloo.subtitle %][% subtitl.subfield %][% END %][% END %]</a> > [% IF ( bibitemloo.author ) %], by [% bibitemloo.author %][% END %]</p> > > >@@ -359,6 +390,10 @@ > > > [% UNLESS ( singleBranchMode ) %] >+ [% IF ( bibitemloo.suggestAnotherPickupLocation ) %] >+ <div id="suggestAnotherPickupLocation_[% bibitemloo.biblionumber %]" class="dialog alert">None of the available items can be transferred to your pickup location. You could try another pickup location. >+ </div> >+ [% END %] > [% IF ( bibitemloo.holdable ) %] > [% IF ( choose_branch ) %] > <li class="branch"> >@@ -398,8 +433,8 @@ > <span class="date-format from" data-biblionumber="[% bibitemloo.biblionumber %]">[% INCLUDE 'date-format.inc' %]</span> > </li> > [% END %] >+ [% END %][%#End of IF ( bibitemloo.holdable ) %] > >- [% END %] > [% IF ( bibitemloo.holdable ) %] > <li> > <label for="to[% bibitemloo.biblionumber %]">Hold not needed after:</label> >@@ -440,8 +475,8 @@ > checked="checked" > /> > [% END %] >- > <label for="reqany_[% bibitemloo.biblionumber %]">Next available copy</label> >+ > [% UNLESS ( bibitemloo.holdable ) %] > <input type="radio" name="reqtype_[% bibitemloo.biblionumber %]" > id="reqspecific_[% bibitemloo.biblionumber %]" >@@ -500,7 +535,7 @@ > [% UNLESS ( noItemTypeImages ) %] > [% IF ( itemLoo.imageurl ) %]<img src="[% itemLoo.imageurl %]" alt="" />[% END %] > [% END %] >- [% itemLoo.description %] >+ [% itemLoo.description %] > </td> > [% END %] > <td class="barcode">[% itemLoo.barcode %]</td> >@@ -552,10 +587,8 @@ > </div><!-- bigloop --> > > [% UNLESS ( message ) %] >- [% UNLESS ( none_available ) %] > <input type="submit" value="Place hold" class="placehold" /> > [% END %] >- [% END %] > > </form> > >diff --git a/opac/opac-reserve.pl b/opac/opac-reserve.pl >index 97d136a..a6a538a 100755 >--- a/opac/opac-reserve.pl >+++ b/opac/opac-reserve.pl >@@ -58,8 +58,8 @@ for ( C4::Context->preference("OPACShowHoldQueueDetails") ) { > } > > sub get_out { >- output_html_with_http_headers(shift,shift,shift); # $query, $cookie, $template->output; >- exit; >+ output_html_with_http_headers(shift,shift,shift); # $query, $cookie, $template->output; >+ exit; > } > > # get borrower information .... >@@ -91,7 +91,8 @@ if ((! $biblionumbers) && (! $query->param('place_reserve'))) { > } > > # Pass the numbers to the page so they can be fed back >-# when the hold is confirmed. TODO: Not necessary? >+# when the hold is confirmed. Biblionumbers are also needed if the >+# pickup branch changes and the page needs to be reloaded. > $template->param( biblionumbers => $biblionumbers ); > > # Each biblio number is suffixed with '/', e.g. "1/2/3/" >@@ -103,12 +104,12 @@ if (($#biblionumbers < 0) && (! $query->param('place_reserve'))) { > } > > # pass the pickup branch along.... >-my $branch = $query->param('branch') || $borr->{'branchcode'} || C4::Context->userenv->{branch} || '' ; >-($branches->{$branch}) or $branch = ""; # Confirm branch is real >-$template->param( branch => $branch ); >+my $pickupBranch = $query->param('branch') || $borr->{'branchcode'} || C4::Context->userenv->{branch} || '' ; >+($branches->{$pickupBranch}) or $pickupBranch = ""; # Confirm branch is real >+$template->param( branch => $pickupBranch ); > > # make branch selection options... >-my $branchloop = GetBranchesLoop($branch); >+my $branchloop = GetBranchesLoop($pickupBranch); > > # Is the person allowed to choose their branch > my $OPACChooseBranch = (C4::Context->preference("OPACAllowUserToChooseBranch")) ? 1 : 0; >@@ -202,19 +203,19 @@ if ( $query->param('place_reserve') ) { > } > > while (@selectedItems) { >- my $biblioNum = shift(@selectedItems); >- my $itemNum = shift(@selectedItems); >- my $branch = shift(@selectedItems); # i.e., branch code, not name >+ my $biblioNum = shift(@selectedItems); >+ my $itemNum = shift(@selectedItems); >+ my $pickupLocation = shift(@selectedItems); # i.e., branch code, not name, > > my $canreserve = 0; > > my $singleBranchMode = C4::Context->preference("singleBranchMode"); > if ( $singleBranchMode || !$OPACChooseBranch ) > { # single branch mode or disabled user choosing >- $branch = $borr->{'branchcode'}; >+ $pickupLocation = $borr->{'branchcode'}; > } > >-#item may belong to a host biblio, if yes change biblioNum to hosts bilbionumber >+ #item may belong to a host biblio, if yes change biblioNum to hosts bilbionumber > if ( $itemNum ne '' ) { > my $hostbiblioNum = GetBiblionumberFromItemnumber($itemNum); > if ( $hostbiblioNum ne $biblioNum ) { >@@ -235,20 +236,26 @@ if ( $query->param('place_reserve') ) { > > my $expiration_date = $query->param("expiration_date_$biblioNum"); > >- # If a specific item was selected and the pickup branch is the same as the >- # holdingbranch, force the value $rank and $found. >+ # If a specific item was selected and the pickup branch is the same as the >+ # holdingbranch, force the value $rank and $found. > my $rank = $biblioData->{rank}; > if ( $itemNum ne '' ) { >+ my $item = GetItem($itemNum); > $canreserve = 1 if CanItemBeReserved( $borrowernumber, $itemNum ); > $rank = '0' unless C4::Context->preference('ReservesNeedReturns'); >- my $item = GetItem($itemNum); >- if ( $item->{'holdingbranch'} eq $branch ) { >+ if ( $item->{'holdingbranch'} eq $pickupLocation ) { > $found = 'W' > unless C4::Context->preference('ReservesNeedReturns'); > } >+ >+ # UseBranchTransferLimits checking. >+ my ($transferOk, $message) = CheckBranchTransferAllowed( $pickupLocation, $item->{'holdingbranch'}, $item, undef ); >+ if (! $transferOk) { >+ $canreserve = 0; >+ } > } > else { >- $canreserve = 1 if CanBookBeReserved( $borrowernumber, $biblioNum ); >+ $canreserve = 1 if CanBookBeReserved( $borrowernumber, $biblioNum, $pickupLocation ); > > # Inserts a null into the 'itemnumber' field of 'reserves' table. > $itemNum = undef; >@@ -264,7 +271,7 @@ if ( $query->param('place_reserve') ) { > # Here we actually do the reserveration. Stage 3. > if ($canreserve) { > AddReserve( >- $branch, $borrowernumber, >+ $pickupLocation, $borrowernumber, > $biblioNum, 'a', > [$biblioNum], $rank, > $startdate, $expiration_date, >@@ -398,6 +405,10 @@ foreach my $biblioNum (@biblionumbers) { > } > } > >+ #Collect the amout of items that pass the CheckBranchTransferAllowed-check. This is needed to tell >+ # the user if some or all Items cannot be transferred to the pickup location. >+ my $branchTransferableItemsCount = 0; >+ > $biblioLoopIter{itemLoop} = []; > my $numCopiesAvailable = 0; > foreach my $itemInfo (@{$biblioData->{itemInfos}}) { >@@ -434,10 +445,10 @@ foreach my $biblioNum (@biblionumbers) { > my ($reservedate,$reservedfor,$expectedAt) = GetReservesFromItemnumber($itemNum); > my $ItemBorrowerReserveInfo = GetMemberDetails( $reservedfor, 0); > >- # the item could be reserved for this borrower vi a host record, flag this >- if ($reservedfor eq $borrowernumber){ >- $itemLoopIter->{already_reserved} = 1; >- } >+ # the item could be reserved for this borrower vi a host record, flag this >+ if ($reservedfor eq $borrowernumber){ >+ $itemLoopIter->{already_reserved} = 1; >+ } > > if ( defined $reservedate ) { > $itemLoopIter->{backgroundcolor} = 'reserved'; >@@ -480,12 +491,12 @@ foreach my $biblioNum (@biblionumbers) { > $itemLoopIter->{nocancel} = 1; > } > >- # if the items belongs to a host record, show link to host record >- if ($itemInfo->{biblionumber} ne $biblioNum){ >- $biblioLoopIter{hostitemsflag} = 1; >- $itemLoopIter->{hostbiblionumber} = $itemInfo->{biblionumber}; >- $itemLoopIter->{hosttitle} = GetBiblioData($itemInfo->{biblionumber})->{title}; >- } >+ # if the items belongs to a host record, show link to host record >+ if ($itemInfo->{biblionumber} ne $biblioNum){ >+ $biblioLoopIter{hostitemsflag} = 1; >+ $itemLoopIter->{hostbiblionumber} = $itemInfo->{biblionumber}; >+ $itemLoopIter->{hosttitle} = GetBiblioData($itemInfo->{biblionumber})->{title}; >+ } > > # If there is no loan, return and transfer, we show a checkbox. > $itemLoopIter->{notforloan} = $itemLoopIter->{notforloan} || 0; >@@ -501,20 +512,32 @@ foreach my $biblioNum (@biblionumbers) { > } > > if (IsAvailableForItemLevelRequest($itemNum) and $policy_holdallowed and CanItemBeReserved($borrowernumber,$itemNum) and ($itemLoopIter->{already_reserved} ne 1)) { >+ > $itemLoopIter->{available} = 1; > $numCopiesAvailable++; >+ >+ #Check for UseBranchTransferLimit. $numCopiesAvailable is incremented because this Item >+ # could still be available from another pickup location >+ my ($transferOk, $errorMsg) = CheckBranchTransferAllowed( $pickupBranch, undef, GetItem($itemNum), undef ); >+ if (! $transferOk) { >+ $itemLoopIter->{available} = 0; >+ $itemLoopIter->{branchTransferBlocked} = 1; >+ } >+ else { >+ $branchTransferableItemsCount++; >+ } > } > >- # FIXME: move this to a pm >+ # FIXME: move this to a pm > my $dbh = C4::Context->dbh; > my $sth2 = $dbh->prepare("SELECT * FROM reserves WHERE borrowernumber=? AND itemnumber=? AND found='W'"); > $sth2->execute($itemLoopIter->{ReservedForBorrowernumber}, $itemNum); > while (my $wait_hashref = $sth2->fetchrow_hashref) { > $itemLoopIter->{waitingdate} = format_date($wait_hashref->{waitingdate}); > } >- $itemLoopIter->{imageurl} = getitemtypeimagelocation( 'opac', $itemTypes->{ $itemInfo->{itype} }{imageurl} ); >+ $itemLoopIter->{imageurl} = getitemtypeimagelocation( 'opac', $itemTypes->{ $itemInfo->{itype} }{imageurl} ); > >- # Show serial enumeration when needed >+ # Show serial enumeration when needed > if ($itemLoopIter->{enumchron}) { > $itemdata_enumchron = 1; > } >@@ -523,6 +546,7 @@ foreach my $biblioNum (@biblionumbers) { > } > $template->param( itemdata_enumchron => $itemdata_enumchron ); > >+ ## Set the behaviour flags for the template > if ($numCopiesAvailable > 0) { > $numBibsAvailable++; > $biblioLoopIter{bib_available} = 1; >@@ -538,13 +562,18 @@ foreach my $biblioNum (@biblionumbers) { > $biblioLoopIter{holdable} = undef; > $biblioLoopIter{already_patron_possession} = 1; > } >+ if ($branchTransferableItemsCount == 0) { >+ #We can tell our Borrowers that they can try another pickup location if they don't find what they need. >+ $biblioLoopIter{suggestAnotherPickupLocation} = 1 ; >+ } >+ > > if( $biblioLoopIter{holdable} ){ $anyholdable++; } > > push @$biblioLoop, \%biblioLoopIter; > } > >-if ( $numBibsAvailable == 0 || $anyholdable == 0) { >+if ( $numBibsAvailable == 0 || $anyholdable == 0 ) { > $template->param( none_available => 1 ); > } > >@@ -571,7 +600,7 @@ if ( > C4::Context->preference( 'OPACAllowHoldDateInFuture' ) > ) { > $template->param( >- reserve_in_future => 1, >+ reserve_in_future => 1, > ); > } > >-- >1.8.1.2
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 10993
:
21891
|
21892
|
22000
|
22001
|
22322
| 23163