Adding XSLTreultsFilename and XSLTDetailFilename
[koha.git] / C4 / Circulation.pm
index 4c547c4..5fcd294 100644 (file)
@@ -71,7 +71,9 @@ BEGIN {
                &GetIssuingCharges
                &GetIssuingRule
         &GetBranchBorrowerCircRule
+               &GetBranchItemRule
                &GetBiblioIssues
+               &GetOpenIssue
                &AnonymiseIssueHistory
        );
 
@@ -681,7 +683,7 @@ sub CanBookBeIssued {
     if ( $borrower->{'dateexpiry'} eq '0000-00-00') {
         $issuingimpossible{EXPIRED} = 1;
     } else {
-        my @expirydate=  split /-/,$borrower->{'dateexpiry'};
+        my @expirydate=  split (/-/,$borrower->{'dateexpiry'});
         if($expirydate[0]==0 || $expirydate[1]==0|| $expirydate[2]==0 ||
             Date_to_Days(Today) > Date_to_Days( @expirydate )) {
             $issuingimpossible{EXPIRED} = 1;                                   
@@ -878,7 +880,6 @@ sub AddIssue {
     my ( $borrower, $barcode, $datedue, $cancelreserve, $issuedate, $sipmode) = @_;
     my $dbh = C4::Context->dbh;
        my $barcodecheck=CheckValidBarcode($barcode);
-
     # $issuedate defaults to today.
     if ( ! defined $issuedate ) {
         $issuedate = strftime( "%Y-%m-%d", localtime );
@@ -896,7 +897,7 @@ sub AddIssue {
                
                # get biblioinformation for this item
                my $biblio = GetBiblioFromItemNumber($item->{itemnumber});
-               
+               my $itype = ( C4::Context->preference('item-level_itypes') ) ? $biblio->{'itype'} : $biblio->{'itemtype'};
                #
                # check if we just renew the issue.
                #
@@ -977,9 +978,8 @@ sub AddIssue {
                 VALUES (?,?,?,?,?)"
           );
         unless ($datedue) {
-            my $itype = ( C4::Context->preference('item-level_itypes') ) ? $biblio->{'itype'} : $biblio->{'itemtype'};
             my $loanlength = GetLoanLength( $borrower->{'categorycode'}, $itype, $branch );
-            $datedue = CalcDateDue( C4::Dates->new( $issuedate, 'iso' ), $loanlength, $branch );
+            $datedue = CalcDateDue( C4::Dates->new( $issuedate, 'iso' ), $loanlength, $branch, $borrower );
 
             # if ReturnBeforeExpiry ON the datedue can't be after borrower expirydate
             if ( C4::Context->preference('ReturnBeforeExpiry') && $datedue->output('iso') gt $borrower->{dateexpiry} ) {
@@ -995,7 +995,7 @@ sub AddIssue {
         );
         $item->{'issues'}++;
         ModItem({ issues           => $item->{'issues'},
-                  holdingbranch    => C4::Context->userenv->{branch} or $item->{'holdingbranch'},
+                  holdingbranch    => C4::Context->userenv->{branch},
                   itemlost         => 0,
                   datelastborrowed => C4::Dates->new()->output('iso'),
                   onloan           => $datedue->output('iso'),
@@ -1020,7 +1020,7 @@ sub AddIssue {
             C4::Context->userenv->{'branch'},
             'issue', $charge,
             ($sipmode ? "SIP-$sipmode" : ''), $item->{'itemnumber'},
-            $item->{'itype'}, $borrower->{'borrowernumber'}
+            $itype, $borrower->{'borrowernumber'}
         );
     }
     
@@ -1233,6 +1233,70 @@ sub GetBranchBorrowerCircRule {
         maxissueqty => undef,
     };
 }
+=head2 GetBranchItemRule
+
+=over 4
+
+my $branch_item_rule = GetBranchItemRule($branchcode, $itemtype);
+
+=back
+
+Retrieves circulation rule attributes that apply to the given
+branch and item type, regardless of patron category.
+
+The return value is a hashref containing the following key:
+
+holdallowed => Hold policy for this branch and itemtype. Possible values:
+  0: No holds allowed.
+  1: Holds allowed only by patrons that have the same homebranch as the item.
+  2: Holds allowed from any patron.
+
+This searches branchitemrules in the following order:
+
+  * Same branchcode and itemtype
+  * Same branchcode, itemtype '*'
+  * branchcode '*', same itemtype
+  * branchcode and itemtype '*'
+
+Neither C<$branchcode> nor C<$categorycode> should be '*'.
+
+=cut
+
+sub GetBranchItemRule {
+    my ( $branchcode, $itemtype ) = @_;
+    my $dbh = C4::Context->dbh();
+    my $result = {};
+
+    my @attempts = (
+        ['SELECT holdallowed
+            FROM branch_item_rules
+            WHERE branchcode = ?
+              AND itemtype = ?', $branchcode, $itemtype],
+        ['SELECT holdallowed
+            FROM default_branch_circ_rules
+            WHERE branchcode = ?', $branchcode],
+        ['SELECT holdallowed
+            FROM default_branch_item_rules
+            WHERE itemtype = ?', $itemtype],
+        ['SELECT holdallowed
+            FROM default_circ_rules'],
+    );
+
+    foreach my $attempt (@attempts) {
+        my ($query, @bind_params) = @{$attempt};
+
+        # 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
+        return $result if ( defined( $result->{'holdallowed'} = $dbh->selectrow_array( $query, {}, @bind_params ) ) );
+    }
+    
+    # built-in default circulation rule
+    return {
+        holdallowed => 2,
+    };
+}
+
 
 =head2 AddReturn
 
@@ -1312,13 +1376,16 @@ sub AddReturn {
        $branch ||=C4::Context->userenv->{'branch'};
     
     # get information on item
-    my $iteminformation = GetItemIssue( GetItemnumberFromBarcode($barcode));
+    my $itemnumber = GetItemnumberFromBarcode($barcode);
+    my $iteminformation = GetItemIssue( $itemnumber );
     my $biblio = GetBiblioItemData($iteminformation->{'biblioitemnumber'});
-#     use Data::Dumper;warn Data::Dumper::Dumper($iteminformation);  
-    unless ($iteminformation->{'itemnumber'} ) {
+    my $itype = ( C4::Context->preference('item-level_itypes') ) ? $biblio->{'itype'} : $biblio->{'itemtype'};     
+
+    unless ( $iteminformation->{'itemnumber'} or $itemnumber) {
         $messages->{'BadBarcode'} = $barcode;
         $doreturn = 0;
     } else {
+        $iteminformation->{'itemnumber'} = $itemnumber;
         # find the borrower
         if ( not $iteminformation->{borrowernumber} ) {
             $messages->{'NotIssued'} = $barcode;
@@ -1327,13 +1394,14 @@ sub AddReturn {
         
         # even though item is not on loan, it may still
         # be transferred; therefore, get current branch information
-        my $curr_iteminfo = GetItem($iteminformation->{'itemnumber'});
+        my $curr_iteminfo = GetItem($itemnumber);
         $iteminformation->{'homebranch'} = $curr_iteminfo->{'homebranch'};
         $iteminformation->{'holdingbranch'} = $curr_iteminfo->{'holdingbranch'};
         $iteminformation->{'itemlost'} = $curr_iteminfo->{'itemlost'};
         
         # check if the book is in a permanent collection....
-        my $hbr      = $iteminformation->{C4::Context->preference("HomeOrHoldingBranch")};
+        my $hbr      = C4::Context->preference("HomeOrHoldingBranchReturn") || "homebranch";
+        $hbr         = $iteminformation->{$hbr};
         my $branches = GetBranches();
                # FIXME -- This 'PE' attribute is largely undocumented.  afaict, there's no user interface that reflects this functionality.
         if ( $hbr && $branches->{$hbr}->{'PE'} ) {
@@ -1341,7 +1409,7 @@ sub AddReturn {
         }
                
                    # if independent branches are on and returning to different branch, refuse the return
-        if ($hbr ne $branch && C4::Context->preference("IndependantBranches")){
+        if ($hbr ne $branch && C4::Context->preference("IndependantBranches") && $iteminformation->{borrowernumber}){
                          $messages->{'Wrongbranch'} = 1;
                          $doreturn=0;
                    }
@@ -1352,18 +1420,21 @@ sub AddReturn {
             $doreturn = 0;
         }
     
-
+    # We know the document was just seen
+    ModDateLastSeen( $iteminformation->{'itemnumber'} );
+        
     #     new op dev : if the book returned in an other branch update the holding branch
     
     # update issues, thereby returning book (should push this out into another subroutine
         $borrower = C4::Members::GetMemberDetails( $iteminformation->{borrowernumber}, 0 );
     
     # case of a return of document (deal with issues and holdingbranch)
-    
+            
         if ($doreturn) {
-                       my $circControlBranch = _GetCircControlBranch($iteminformation,$borrower);
+                       my $circControlBranch;
                        if($dropbox) {
                                # don't allow dropbox mode to create an invalid entry in issues (issuedate > returndate) FIXME: actually checks eq, not gt
+                $circControlBranch=_GetCircControlBranch($iteminformation,$borrower) unless ( $iteminformation->{'issuedate'} eq C4::Dates->today('iso') );
                                undef($dropbox) if ( $iteminformation->{'issuedate'} eq C4::Dates->today('iso') );
                        }
             MarkIssueReturned($borrower->{'borrowernumber'}, $iteminformation->{'itemnumber'},$circControlBranch);
@@ -1372,11 +1443,9 @@ sub AddReturn {
             
             
             # We update the holdingbranch from circControlBranch variable
-            UpdateHoldingbranch($circControlBranch,$iteminformation->{'itemnumber'});
-            $iteminformation->{'holdingbranch'} = $circControlBranch;
-        
-            
-            ModDateLastSeen( $iteminformation->{'itemnumber'} );
+            UpdateHoldingbranch($branch,$iteminformation->{'itemnumber'});
+            $iteminformation->{'holdingbranch'} = $branch;
+
             ModItem({ onloan => undef }, $biblio->{'biblionumber'}, $iteminformation->{'itemnumber'});
 
             if ($iteminformation->{borrowernumber}){
@@ -1420,8 +1489,8 @@ sub AddReturn {
     
     # find reserves.....
     #     if we don't have a reserve with the status W, we launch the Checkreserves routine
-        my ( $resfound, $resrec ) =
-        C4::Reserves::CheckReserves( $iteminformation->{'itemnumber'} );
+        my ( $resfound, $resrec ) = 
+        C4::Reserves::CheckReserves( $itemnumber, $barcode );
         if ($resfound) {
             $resrec->{'ResFound'}   = $resfound;
             $messages->{'ResFound'} = $resrec;
@@ -1433,7 +1502,7 @@ sub AddReturn {
         UpdateStats(
             $branch, 'return', '0', '',
             $iteminformation->{'itemnumber'},
-            $biblio->{'itemtype'},
+            $itype,
             $borrower->{'borrowernumber'}
         );
         
@@ -1442,8 +1511,11 @@ sub AddReturn {
         
         #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 ($branch ne $iteminformation->{$hbr}) and not $messages->{'WrongTransfer'} and ($validTransfert ne 1) and ($reserveDone ne 1) ){
+        if (($doreturn or $messages->{'NotIssued'}) 
+            and ($branch ne $hbr) 
+            and not $messages->{'WrongTransfer'} 
+            and ($validTransfert ne 1) 
+            and ($reserveDone ne 1) ){
                        if (C4::Context->preference("AutomaticItemReturn") == 1) {
                                ModItemTransfer($iteminformation->{'itemnumber'}, $branch, $iteminformation->{$hbr});
                                $messages->{'WasTransfered'} = 1;
@@ -1722,6 +1794,28 @@ sub GetItemIssue {
     return ($data);
 }
 
+=head2 GetOpenIssue
+
+$issue = GetOpenIssue( $itemnumber );
+
+Returns the row from the issues table if the item is currently issued, undef if the item is not currently issued
+
+C<$itemnumber> is the item's itemnumber
+
+Returns a hashref
+
+=cut
+
+sub GetOpenIssue {
+  my ( $itemnumber ) = @_;
+
+  my $dbh = C4::Context->dbh;  
+  my $sth = $dbh->prepare( "SELECT * FROM issues WHERE itemnumber = ? AND returndate IS NULL" );
+  $sth->execute( $itemnumber );
+  my $issue = $sth->fetchrow_hashref();
+  return $issue;
+}
+
 =head2 GetItemIssues
 
 $issues = &GetItemIssues($itemnumber, $history);
@@ -1970,7 +2064,7 @@ sub AddRenewal {
                        $item->{homebranch}                     # item's homebranch determines loanlength OR do we want the branch specified by the AddRenewal argument?
         );
                #FIXME -- use circControl?
-               $datedue =  CalcDateDue(C4::Dates->new(),$loanlength,$branch);  # this branch is the transactional branch.
+               $datedue =  CalcDateDue(C4::Dates->new(),$loanlength,$branch,$borrower);        # this branch is the transactional branch.
                                                                # The question of whether to use item's homebranch calendar is open.
     }
 
@@ -2314,15 +2408,8 @@ sub CalcDateDue {
        my ($startdate,$loanlength,$branch,$borrower) = @_;
        my $datedue;
 
-       if(C4::Context->preference('useDaysMode') eq 'Days') {  # ignoring calendar
-               my $timedue = time + ($loanlength) * 86400;
-       #FIXME - assumes now even though we take a startdate 
-               my @datearr  = localtime($timedue);
-               $datedue = C4::Dates->new( sprintf("%04d-%02d-%02d", 1900 + $datearr[5], $datearr[4] + 1, $datearr[3]), 'iso');
-       } else {
-               my $calendar = C4::Calendar->new(  branchcode => $branch );
-               $datedue = $calendar->addDate($startdate, $loanlength);
-       }
+       my $calendar = C4::Calendar->new(  branchcode => $branch );
+       $datedue = $calendar->addDate($startdate, $loanlength);
 
        # if ReturnBeforeExpiry ON the datedue can't be after borrower expirydate
        if ( C4::Context->preference('ReturnBeforeExpiry') && $datedue->output('iso') gt $borrower->{dateexpiry} ) {